changeset 12591:868f2de3898b

imapc: Fixed seqmap to work. The algorithm is a bit slow, could be improved. But probably won't make much of a difference in real life.
author Timo Sirainen <tss@iki.fi>
date Sun, 23 Jan 2011 20:26:02 +0200
parents 9e471f267fb4
children 475050722f54
files src/lib-storage/index/imapc/Makefile.am src/lib-storage/index/imapc/imapc-seqmap.c src/lib-storage/index/imapc/test-imapc-seqmap.c
diffstat 3 files changed, 204 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/imapc/Makefile.am	Fri Jan 21 17:39:24 2011 +0200
+++ b/src/lib-storage/index/imapc/Makefile.am	Sun Jan 23 20:26:02 2011 +0200
@@ -2,6 +2,7 @@
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-test \
 	-I$(top_srcdir)/src/lib-dns \
 	-I$(top_srcdir)/src/lib-mail \
 	-I$(top_srcdir)/src/lib-imap \
@@ -30,3 +31,22 @@
 
 pkginc_libdir=$(pkgincludedir)
 pkginc_lib_HEADERS = $(headers)
+
+test_programs = \
+	test-imapc-seqmap
+
+noinst_PROGRAMS = $(test_programs)
+
+test_libs = \
+	../../../lib-test/libtest.la \
+	../../../lib/liblib.la
+
+test_imapc_seqmap_SOURCES = test-imapc-seqmap.c
+test_imapc_seqmap_LDADD = imapc-seqmap.lo $(test_libs)
+test_imapc_seqmap_DEPENDENCIES = imapc-seqmap.lo $(test_libs)
+
+check: check-am check-test
+check-test: all-am
+	for bin in $(test_programs); do \
+	  if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \
+	done
--- a/src/lib-storage/index/imapc/imapc-seqmap.c	Fri Jan 21 17:39:24 2011 +0200
+++ b/src/lib-storage/index/imapc/imapc-seqmap.c	Sun Jan 23 20:26:02 2011 +0200
@@ -2,9 +2,11 @@
 
 #include "lib.h"
 #include "array.h"
+#include "bsearch-insert-pos.h"
 #include "imapc-seqmap.h"
 
 struct imapc_seqmap {
+	ARRAY_TYPE(uint32_t) queue;
 	ARRAY_TYPE(uint32_t) expunges;
 };
 
@@ -13,6 +15,7 @@
 	struct imapc_seqmap *seqmap;
 
 	seqmap = i_new(struct imapc_seqmap, 1);
+	i_array_init(&seqmap->queue, 64);
 	i_array_init(&seqmap->expunges, 64);
 	return seqmap;
 }
@@ -23,11 +26,13 @@
 
 	*_seqmap = NULL;
 	array_free(&seqmap->expunges);
+	array_free(&seqmap->queue);
 	i_free(seqmap);
 }
 
 void imapc_seqmap_reset(struct imapc_seqmap *seqmap)
 {
+	array_clear(&seqmap->queue);
 	array_clear(&seqmap->expunges);
 }
 
@@ -35,17 +40,82 @@
 {
 	i_assert(rseq > 0);
 
-	array_append(&seqmap->expunges, &rseq, 1);
+	array_append(&seqmap->queue, &rseq, 1);
+}
+
+static int uint32_cmp_p(const uint32_t *p1, const uint32_t *p2)
+{
+	if (*p1 < *p2)
+		return -1;
+	else if (*p1 > *p2)
+		return 1;
+	else
+		return 0;
+}
+
+static uint32_t
+imapc_seqmap_rseq_idx_lookup(struct imapc_seqmap *seqmap, uint32_t rseq,
+			     unsigned int *idx_r)
+{
+	const uint32_t *seqs;
+	unsigned int idx, count;
+	uint32_t lseq = rseq;
+
+	seqs = array_get(&seqmap->expunges, &count);
+	for (;;) {
+		array_bsearch_insert_pos(&seqmap->expunges, &lseq, uint32_cmp_p, &idx);
+		lseq = rseq + idx;
+		if (idx == count || seqs[idx] > lseq) {
+			*idx_r = idx;
+			return lseq;
+		}
+		if (seqs[idx] == lseq)
+			lseq++;
+	}
+}
+
+static void
+imapc_seqmap_dequeue_rseq(struct imapc_seqmap *seqmap, uint32_t rseq)
+{
+	unsigned int idx;
+	uint32_t lseq;
+
+	lseq = imapc_seqmap_rseq_idx_lookup(seqmap, rseq, &idx);
+	array_insert(&seqmap->expunges, idx, &lseq, 1);
+}
+
+static void imapc_seqmap_dequeue(struct imapc_seqmap *seqmap)
+{
+	const uint32_t *seqp;
+
+	array_foreach(&seqmap->queue, seqp)
+		imapc_seqmap_dequeue_rseq(seqmap, *seqp);
+	array_clear(&seqmap->queue);
 }
 
 uint32_t imapc_seqmap_rseq_to_lseq(struct imapc_seqmap *seqmap, uint32_t rseq)
 {
+	unsigned int idx;
+
 	i_assert(rseq > 0);
-	return rseq; // FIXME
+
+	imapc_seqmap_dequeue(seqmap);
+	return imapc_seqmap_rseq_idx_lookup(seqmap, rseq, &idx);
 }
 
 uint32_t imapc_seqmap_lseq_to_rseq(struct imapc_seqmap *seqmap, uint32_t lseq)
 {
+	const uint32_t *seqs;
+	unsigned int idx, count;
+
 	i_assert(lseq > 0);
-	return lseq; // FIXME
+
+	imapc_seqmap_dequeue(seqmap);
+
+	seqs = array_get(&seqmap->expunges, &count);
+	if (array_bsearch_insert_pos(&seqmap->expunges, &lseq,
+				     uint32_cmp_p, &idx))
+		return 0;
+
+	return lseq - idx;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/imapc/test-imapc-seqmap.c	Sun Jan 23 20:26:02 2011 +0200
@@ -0,0 +1,111 @@
+/* Copyright (c) 2011 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "imapc-seqmap.h"
+#include "test-common.h"
+
+#include <stdlib.h>
+
+static void test_imapc_seqmap(void)
+{
+	struct imapc_seqmap *seqmap;
+
+	test_begin("imapc seqmap");
+	seqmap = imapc_seqmap_init();
+
+	imapc_seqmap_expunge(seqmap, 4);
+	imapc_seqmap_expunge(seqmap, 3);
+	imapc_seqmap_expunge(seqmap, 2);
+
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 1);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 5);
+
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 1);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 4) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 5) == 2);
+
+	imapc_seqmap_reset(seqmap);
+	imapc_seqmap_expunge(seqmap, 3);
+	imapc_seqmap_expunge(seqmap, 3);
+	imapc_seqmap_expunge(seqmap, 3);
+
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 1);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 2);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 3) == 6);
+
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 1);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 2);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 4) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 5) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 6) == 3);
+
+	imapc_seqmap_reset(seqmap);
+	/* 9,8,5,4,2,1 */
+	imapc_seqmap_expunge(seqmap, 4);
+	imapc_seqmap_expunge(seqmap, 4);
+	imapc_seqmap_expunge(seqmap, 1);
+	imapc_seqmap_expunge(seqmap, 1);
+	imapc_seqmap_expunge(seqmap, 4);
+	imapc_seqmap_expunge(seqmap, 4);
+
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 1) == 3);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 2) == 6);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 3) == 7);
+	test_assert(imapc_seqmap_rseq_to_lseq(seqmap, 4) == 10);
+
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 1) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 2) == 0);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 3) == 1);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 6) == 2);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 7) == 3);
+	test_assert(imapc_seqmap_lseq_to_rseq(seqmap, 10) == 4);
+
+	imapc_seqmap_deinit(&seqmap);
+	test_end();
+}
+
+static void test_imapc_seqmap_random(void)
+{
+#define UIDMAP_SIZE 1000
+	struct imapc_seqmap *seqmap;
+	ARRAY_TYPE(uint32_t) uidmap;
+	const uint32_t *uids;
+	unsigned int i, count;
+	uint32_t seq, uid;
+
+	test_begin("imapc seqmap random");
+	seqmap = imapc_seqmap_init();
+
+	t_array_init(&uidmap, UIDMAP_SIZE);
+	for (uid = 1; uid <= UIDMAP_SIZE; uid++)
+		array_append(&uidmap, &uid, 1);
+
+	for (i = 0; i < 100; i++) {
+		seq = (rand() % array_count(&uidmap)) + 1;
+		array_delete(&uidmap, seq-1, 1);
+		imapc_seqmap_expunge(seqmap, seq);
+	}
+
+	uids = array_get(&uidmap, &count);
+	for (i = 0; i < 100; i++) {
+		seq = i + 1;
+		test_assert(imapc_seqmap_rseq_to_lseq(seqmap, seq) == uids[i]);
+		test_assert(imapc_seqmap_lseq_to_rseq(seqmap, uids[i]) == seq);
+	}
+	imapc_seqmap_deinit(&seqmap);
+	test_end();
+}
+
+int main(void)
+{
+	static void (*test_functions[])(void) = {
+		test_imapc_seqmap,
+		test_imapc_seqmap_random,
+		NULL
+	};
+	return test_run(test_functions);
+}