]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Add details to "Broken sort-* indexes" error
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Fri, 9 Jun 2017 09:25:36 +0000 (12:25 +0300)
committerGitLab <gitlab@git.dovecot.net>
Fri, 9 Jun 2017 12:52:46 +0000 (15:52 +0300)
src/lib-storage/index/index-sort-string.c

index bd07906e19846dbf597b9e695c930be8a076ea7b..1e8cd1e8743b2eeec35703085928e26faa374b4b 100644 (file)
@@ -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);