changeset 22150:a094a555a5c3

lib-storage: Add details to "Broken sort-* indexes" error
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 09 Jun 2017 12:25:36 +0300
parents 562c621a9073
children 92b46facd793
files src/lib-storage/index/index-sort-string.c
diffstat 1 files changed, 50 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/index-sort-string.c	Fri Jun 09 14:31:15 2017 +0300
+++ b/src/lib-storage/index/index-sort-string.c	Fri Jun 09 12:25:36 2017 +0300
@@ -47,7 +47,8 @@
 
 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 @@
 				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 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 @@
 					   &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 @@
 		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 @@
 			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 @@
 
 			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 @@
 		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_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 @@
 	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 @@
 			/* 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);