diff -r eb310b0d0966 src/plugins/fts-squat/squat-trie.c
--- a/src/plugins/fts-squat/squat-trie.c	Sat Feb 16 13:22:11 2008 +0200
+++ b/src/plugins/fts-squat/squat-trie.c	Sat Feb 16 14:21:34 2008 +0200
@@ -30,6 +30,33 @@
 #define TRIE_READAHEAD_SIZE \
 	I_MAX(4096, 1 + 256 + TRIE_BYTES_LEFT(256))
 
+#include <sys/time.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "ioloop.h"
+void i_debug(const char *format, ...)
+{
+	static FILE *f = NULL;
+	va_list args;
+	struct timeval tv;
+
+	gettimeofday(&tv, NULL);
+
+	va_start(args, format);
+	t_push();
+	if (!f) {
+		const char *dir = t_strdup_printf("/tmp/dovecot/%d", (int)ioloop_time/10);
+		mkdir(dir, 0700);
+		f = fopen(t_strdup_printf("%s/%d", dir, getpid()), "a+");
+		setbuf(f, NULL);
+	}
+	fprintf(f, "%10u.%06u PID=%s %s\n",
+		(unsigned)tv.tv_sec, (unsigned)tv.tv_usec,
+		dec2str(getpid()), t_strdup_vprintf(format, args));
+	t_pop();
+	va_end(args);
+}
+
 struct squat_trie_build_context {
 	struct squat_trie *trie;
 	struct ostream *output;
@@ -54,6 +81,24 @@ struct squat_trie_iterate_context {
 	bool failed;
 };
 
+static const char *uidrange2str(const ARRAY_TYPE(seq_range) *uids)
+{
+	const struct seq_range *range;
+	unsigned int i, count;
+	string_t *str = t_str_new(256);
+
+	range = array_get(uids, &count);
+	for (i = 0; i < count; i++) {
+		if (i != 0)
+			str_append_c(str, ',');
+		if (range[i].seq1 == range[i].seq2)
+			str_printfa(str, "%u", range[i].seq1);
+		else
+			str_printfa(str, "%u-%u", range[i].seq1, range[i].seq2);
+	}
+	return str_c(str);
+}
+
 static int squat_trie_map(struct squat_trie *trie, bool building);
 
 void squat_trie_delete(struct squat_trie *trie)
@@ -67,6 +112,7 @@ static void squat_trie_set_corrupted(str
 {
 	trie->corrupted = TRUE;
 	i_error("Corrupted file %s", trie->path);
+	abort();
 	squat_trie_delete(trie);
 }
 
@@ -1056,7 +1102,8 @@ squat_trie_iterate_first(struct squat_tr
 
 static struct squat_node *
 squat_trie_iterate_next(struct squat_trie_iterate_context *ctx,
-			ARRAY_TYPE(seq_range) *shifts_r)
+			ARRAY_TYPE(seq_range) *shifts_r,
+			struct squat_node **parent_r)
 {
 	struct squat_trie_iterate_node *iter_nodes;
 	struct squat_node *children;
@@ -1075,6 +1122,7 @@ squat_trie_iterate_next(struct squat_tri
 		array_delete(&ctx->parents, count-1, 1);
 	}
 
+	*parent_r = ctx->cur.node;
 	*shifts_r = ctx->cur.shifts;
 	if (array_is_created(&ctx->cur.shifts))
 		shift_count = array_count(&ctx->cur.shifts);
@@ -1083,7 +1131,7 @@ squat_trie_iterate_next(struct squat_tri
 	while (children[ctx->cur.idx++].uid_list_idx == 0) {
 		if (ctx->cur.idx == ctx->cur.node->child_count) {
 			/* no more non-empty children in this node */
-			return squat_trie_iterate_next(ctx, shifts_r);
+			return squat_trie_iterate_next(ctx, shifts_r, parent_r);
 		}
 	}
 	array_append(&ctx->parents, &ctx->cur, 1);
@@ -1101,7 +1149,8 @@ squat_uidlist_update_expunged_uids(const
 				   ARRAY_TYPE(seq_range) *child_shifts,
 				   ARRAY_TYPE(seq_range) *uids_arr,
 				   struct squat_trie *trie,
-				   struct squat_node *node, bool do_shifts)
+				   struct squat_node *node,
+				   struct squat_node *parent, bool do_shifts)
 {
 	const struct seq_range *shifts;
 	struct seq_range *uids, shift;
@@ -1109,10 +1158,18 @@ squat_uidlist_update_expunged_uids(const
 	uint32_t child_shift_seq1, child_shift_count, seq_high;
 	unsigned int shift_sum = 0, child_sum = 0;
 
-	if (!array_is_created(shifts_arr)) {
+	if (!array_is_created(shifts_arr) || array_count(shifts_arr) == 0) {
 		i_assert(node->uid_list_idx != 0 || node->child_count == 0);
 		return;
 	}
+	i_assert(array_is_created(child_shifts));
+
+	/*if (do_shifts) {
+		i_debug("before unused_uids=%u child_count=%u: %s",
+			node->unused_uids, node->child_count,
+			uidrange2str(uids_arr));
+		i_debug(" - shifts: %s", uidrange2str(shifts_arr));
+	}*/
 
 	/* we'll recalculate this */
 	node->unused_uids = 0;
@@ -1229,13 +1286,25 @@ squat_uidlist_update_expunged_uids(const
 		node->have_sequential = FALSE;
 		node->next_uid = 0;
 	} else {
-		if (do_shifts)
+		unsigned int n = uids[0].seq1;
+		for (i = 1; i < uid_count; i++)
+			n += uids[i].seq1 - uids[i-1].seq2 - 1;
+		i_assert(n == node->unused_uids);
+		if (do_shifts) {
 			node->next_uid = uids[uid_count-1].seq2 + 1;
-		else {
+			i_assert(node->next_uid <= parent->next_uid - parent->unused_uids);
+		} else {
 			node->unused_uids += (node->next_uid - 1) -
 				uids[uid_count-1].seq2;
 		}
 	}
+
+	/*if (do_shifts) {
+		i_debug("after: unused_uids=%u child_count=%u: %s",
+			node->unused_uids, node->child_count,
+			uidrange2str(uids_arr));
+		i_debug(" - child_shifts: %s", uidrange2str(child_shifts));
+	}*/
 }
 
 static int
@@ -1244,10 +1313,12 @@ squat_trie_expunge_uidlists(struct squat
 			    struct squat_trie_iterate_context *iter,
 			    const ARRAY_TYPE(seq_range) *expunged_uids)
 {
-	struct squat_node *node;
+	struct squat_node *node, *parent;
 	ARRAY_TYPE(seq_range) uid_range, shifts;
 	bool shift = FALSE;
 	int ret = 0;
+
+	i_debug("expunges: %s", uidrange2str(expunged_uids));
 
 	node = squat_trie_iterate_first(iter);
 	if (node->uid_list_idx == 0)
@@ -1255,8 +1326,10 @@ squat_trie_expunge_uidlists(struct squat
 
 	i_array_init(&uid_range, 1024);
 	i_array_init(&shifts, array_count(expunged_uids));
+	i_array_init(&iter->cur.shifts, array_count(expunged_uids));
 	array_append_array(&shifts, expunged_uids);
 
+	parent = NULL;
 	do {
 		i_assert(node->uid_list_idx != 0);
 		array_clear(&uid_range);
@@ -1268,12 +1341,12 @@ squat_trie_expunge_uidlists(struct squat
 		}
 		squat_uidlist_update_expunged_uids(&shifts, &iter->cur.shifts,
 						   &uid_range, ctx->trie, node,
-						   shift);
+						   parent, shift);
 		node->uid_list_idx =
 			squat_uidlist_rebuild_nextu(rebuild_ctx, &uid_range);
 		i_assert(node->uid_list_idx != 0 || node->next_uid == 0);
 
-		node = squat_trie_iterate_next(iter, &shifts);
+		node = squat_trie_iterate_next(iter, &shifts, &parent);
 		shift = TRUE;
 	} while (node != NULL);
 	array_free(&uid_range);
@@ -1308,7 +1381,7 @@ squat_trie_renumber_uidlists2(struct squ
 			node->uid_list_idx =
 				squat_uidlist_rebuild_next(rebuild_ctx, &uids);
 		}
-		node = squat_trie_iterate_next(iter, &shifts);
+		node = squat_trie_iterate_next(iter, &shifts, NULL);
 	}
 	array_free(&uids);
 	return ret;
diff -r eb310b0d0966 src/plugins/fts-squat/squat-uidlist.c
--- a/src/plugins/fts-squat/squat-uidlist.c	Sat Feb 16 13:22:11 2008 +0200
+++ b/src/plugins/fts-squat/squat-uidlist.c	Sat Feb 16 14:21:34 2008 +0200
@@ -103,6 +103,7 @@ static void squat_uidlist_set_corrupted(
 	uidlist->corrupted = TRUE;
 
 	i_error("Corrupted squat uidlist file %s: %s", uidlist->path, reason);
+	abort(); //FIXME
 	squat_trie_delete(uidlist->trie);
 }
 
@@ -844,6 +845,7 @@ int squat_uidlist_rebuild_init(struct sq
 	const char *temp_path;
 	int fd;
 
+#if 0
 	if (build_ctx->build_hdr.link_count == 0)
 		return 0;
 
@@ -852,6 +854,7 @@ int squat_uidlist_rebuild_init(struct sq
 		    build_ctx->build_hdr.count*2/3)
 			return 0;
 	}
+#endif
 
 	temp_path = t_strconcat(build_ctx->uidlist->path, ".tmp", NULL);
 	fd = open(temp_path, O_RDWR | O_TRUNC | O_CREAT, 0600);
