diff --git a/src/lib-storage/index/index-sort-string.c b/src/lib-storage/index/index-sort-string.c index bd07906e19..1e8cd1e874 100644 --- a/src/lib-storage/index/index-sort-string.c +++ b/src/lib-storage/index/index-sort-string.c @@ -47,7 +47,8 @@ struct sort_string_context { static struct sort_string_context *static_zero_cmp_context; -static void index_sort_list_reset_broken(struct sort_string_context *ctx); +static void index_sort_list_reset_broken(struct sort_string_context *ctx, + const char *reason); static void index_sort_node_add(struct sort_string_context *ctx, struct mail_sort_node *node); @@ -183,7 +184,16 @@ static void index_sort_node_add(struct sort_string_context *ctx, ctx->lowest_nonexpunged_zero = node->seq; } else if (ctx->lowest_nonexpunged_zero != 0 && ctx->lowest_nonexpunged_zero <= node->seq) { - index_sort_list_reset_broken(ctx); + uint32_t nonzero_uid, zero_uid; + + mail_index_lookup_uid(ctx->program->t->view, + node->seq, &nonzero_uid); + mail_index_lookup_uid(ctx->program->t->view, + ctx->lowest_nonexpunged_zero, &zero_uid); + index_sort_list_reset_broken(ctx, t_strdup_printf( + "sort_id=0 found in the middle " + "(uid=%u has sort_id, uid=%u doesn't)", + nonzero_uid, zero_uid)); ctx->broken = TRUE; node->sort_id = 0; } @@ -523,13 +533,14 @@ static void index_sort_merge(struct sort_string_context *ctx) static int index_sort_add_ids_range(struct sort_string_context *ctx, - unsigned int left_idx, unsigned int right_idx) + unsigned int left_idx, unsigned int right_idx, + const char **reason_r) { struct mail_sort_node *nodes; unsigned int i, count, rightmost_idx, skip; const char *left_str = NULL, *right_str = NULL, *str = NULL; - uint32_t left_sort_id, right_sort_id, diff; + uint32_t left_sort_id, right_sort_id, diff, left_str_idx = 0; bool no_left_str = FALSE, no_right_str = FALSE; int ret; @@ -609,6 +620,8 @@ index_sort_add_ids_range(struct sort_string_context *ctx, &nodes[left_idx], &left_str)) { /* not equivalent with any message */ left_str = NULL; + } else { + left_str_idx = left_idx; } left_idx++; } @@ -640,6 +653,16 @@ index_sort_add_ids_range(struct sort_string_context *ctx, if (ret <= 0) { if (ret < 0) { /* broken sort_ids */ + uint32_t str_uid, left_str_uid; + + mail_index_lookup_uid(ctx->program->t->view, + nodes[i].seq, &str_uid); + mail_index_lookup_uid(ctx->program->t->view, + nodes[left_str_idx].seq, &left_str_uid); + *reason_r = t_strdup_printf( + "(idx=%u, seq=%u, uid=%u) '%s' < left string (idx=%u, seq=%u, uid=%u) '%s'", + i, nodes[i].seq, str_uid, str, + left_str_idx, nodes[left_str_idx].seq, left_str_uid, left_str); return -1; } nodes[i].sort_id = left_sort_id; @@ -656,6 +679,11 @@ index_sort_add_ids_range(struct sort_string_context *ctx, if (skip == 0) { /* broken sort IDs (we previously assigned left_sort_id=right_sort_id) */ + uint32_t uid; + mail_index_lookup_uid(ctx->program->t->view, + nodes[i].seq, &uid); + *reason_r = t_strdup_printf( + "no sort_id space for uid=%u", uid); return -1; } left_sort_id += skip; @@ -663,18 +691,24 @@ index_sort_add_ids_range(struct sort_string_context *ctx, nodes[i].sort_id = left_sort_id; left_str = str; + left_str_idx = i; } nodes[i].sort_id_changed = TRUE; } i_assert(str != NULL); - return right_str == NULL || strcmp(str, right_str) < 0 || - (strcmp(str, right_str) == 0 && - nodes[i-1].sort_id == right_sort_id) ? 0 : -1; + if (right_str == NULL || strcmp(str, right_str) < 0 || + (strcmp(str, right_str) == 0 && + nodes[i-1].sort_id == right_sort_id)) + return 0; + + *reason_r = t_strdup_printf("Invalid sort_id order ('%s' > '%s')", + str, right_str); + return -1; } static int -index_sort_add_sort_ids(struct sort_string_context *ctx) +index_sort_add_sort_ids(struct sort_string_context *ctx, const char **reason_r) { const struct mail_sort_node *nodes; unsigned int i, left_idx, right_idx, count; @@ -693,7 +727,7 @@ index_sort_add_sort_ids(struct sort_string_context *ctx) if (right_idx == count) right_idx--; left_idx = i == 0 ? 0 : i - 1; - if (index_sort_add_ids_range(ctx, left_idx, right_idx) < 0) + if (index_sort_add_ids_range(ctx, left_idx, right_idx, reason_r) < 0) return -1; } return 0; @@ -773,14 +807,15 @@ static void index_sort_add_missing(struct sort_string_context *ctx) } } -static void index_sort_list_reset_broken(struct sort_string_context *ctx) +static void index_sort_list_reset_broken(struct sort_string_context *ctx, + const char *reason) { struct mailbox *box = ctx->program->t->box; struct mail_sort_node *node; mail_storage_set_critical(box->storage, - "%s: Broken %s indexes, resetting", - box->name, ctx->primary_sort_name); + "%s: Broken %s indexes, resetting: %s", + box->name, ctx->primary_sort_name, reason); array_clear(&ctx->zero_nodes); array_append_array(&ctx->zero_nodes, @@ -796,6 +831,7 @@ void index_sort_list_finish_string(struct mail_search_sort_program *program) struct sort_string_context *ctx = program->context; const struct mail_sort_node *nodes; unsigned int i, count; + const char *reason; uint32_t seq; static_zero_cmp_context = ctx; @@ -848,11 +884,11 @@ void index_sort_list_finish_string(struct mail_search_sort_program *program) /* merge zero and non-zero arrays into sorted_nodes */ index_sort_merge(ctx); /* give sort IDs to messages missing them */ - if (index_sort_add_sort_ids(ctx) == 0) + if (index_sort_add_sort_ids(ctx, &reason) == 0) break; /* broken, try again with sort IDs reset */ - index_sort_list_reset_broken(ctx); + index_sort_list_reset_broken(ctx, reason); } index_sort_write_changed_sort_ids(ctx);