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);
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;
}
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;
&nodes[left_idx], &left_str)) {
/* not equivalent with any message */
left_str = NULL;
+ } else {
+ left_str_idx = left_idx;
}
left_idx++;
}
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;
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;
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;
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;
}
}
-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,
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;
/* 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);