dovecot: Use a new format for duplicate file which can handle mo...

dovecot at dovecot.org dovecot at dovecot.org
Sun Oct 21 16:28:16 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/f74e84fd11fc
changeset: 6591:f74e84fd11fc
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Oct 21 16:28:12 2007 +0300
description:
Use a new format for duplicate file which can handle moving between 32bit
and 64bit systems.

diffstat:

1 file changed, 124 insertions(+), 74 deletions(-)
src/deliver/duplicate.c |  198 +++++++++++++++++++++++++++++------------------

diffs (274 lines):

diff -r b9b201f5c581 -r f74e84fd11fc src/deliver/duplicate.c
--- a/src/deliver/duplicate.c	Sun Oct 21 16:25:59 2007 +0300
+++ b/src/deliver/duplicate.c	Sun Oct 21 16:28:12 2007 +0300
@@ -16,6 +16,7 @@
 #define DUPLICATE_PATH "~/.dovecot.lda-dupes"
 #define COMPRESS_PERCENTAGE 10
 #define DUPLICATE_BUFSIZE 4096
+#define DUPLICATE_VERSION 2
 
 struct duplicate {
 	const void *id;
@@ -23,6 +24,16 @@ struct duplicate {
 
 	const char *user;
 	time_t time;
+};
+
+struct duplicate_file_header {
+	uint32_t version;
+};
+
+struct duplicate_record_header {
+	uint32_t stamp;
+	uint32_t id_size;
+	uint32_t user_size;
 };
 
 struct duplicate_file {
@@ -39,8 +50,8 @@ static struct dotlock_settings duplicate
 	MEMBER(temp_prefix) NULL,
 	MEMBER(lock_suffix) NULL,
 
-	MEMBER(timeout) 10,
-	MEMBER(stale_timeout) 60,
+	MEMBER(timeout) 20,
+	MEMBER(stale_timeout) 10,
 
 	MEMBER(callback) NULL,
 	MEMBER(context) NULL,
@@ -77,15 +88,82 @@ static unsigned int duplicate_hash(const
 	return h ^ strcase_hash(d->user);
 }
 
+static int
+duplicate_read_records(struct duplicate_file *file, struct istream *input,
+		       unsigned int record_size)
+{
+	const unsigned char *data;
+	struct duplicate_record_header hdr;
+	size_t size;
+	unsigned int change_count;
+
+	change_count = 0;
+	while (i_stream_read_data(input, &data, &size, record_size) > 0) {
+		if (record_size == sizeof(hdr))
+			memcpy(&hdr, data, sizeof(hdr));
+		else {
+			/* FIXME: backwards compatibility with v1.0 */
+			time_t stamp;
+
+			i_assert(record_size ==
+				 sizeof(time_t) + sizeof(uint32_t)*2);
+			memcpy(&stamp, data, sizeof(stamp));
+			hdr.stamp = stamp;
+			memcpy(&hdr.id_size, data + sizeof(time_t),
+			       sizeof(hdr.id_size));
+			memcpy(&hdr.user_size,
+			       data + sizeof(time_t) + sizeof(uint32_t),
+			       sizeof(hdr.user_size));
+		}
+		i_stream_skip(input, record_size);
+
+		if (hdr.id_size == 0 || hdr.user_size == 0 ||
+		    hdr.id_size > DUPLICATE_BUFSIZE ||
+		    hdr.user_size > DUPLICATE_BUFSIZE) {
+			i_error("broken duplicate file %s", file->path);
+			return -1;
+		}
+
+		if (i_stream_read_data(input, &data, &size,
+				       hdr.id_size + hdr.user_size - 1) <= 0) {
+			i_error("unexpected end of file in %s", file->path);
+			return -1;
+		}
+
+		if (hdr.stamp >= ioloop_time) {
+			/* still valid, save it */
+			struct duplicate *d;
+			void *new_id;
+
+			new_id = p_malloc(file->pool, hdr.id_size);
+			memcpy(new_id, data, hdr.id_size);
+
+			d = p_new(file->pool, struct duplicate, 1);
+			d->id = new_id;
+			d->id_size = hdr.id_size;
+			d->user = p_strndup(file->pool,
+					    data + hdr.id_size, hdr.user_size);
+			d->time = hdr.stamp;
+			hash_insert(file->hash, d, d);
+		} else {
+                        change_count++;
+		}
+		i_stream_skip(input, hdr.id_size + hdr.user_size);
+	}
+
+	if (hash_count(file->hash) * COMPRESS_PERCENTAGE / 100 > change_count)
+		file->changed = TRUE;
+	return 0;
+}
+
 static int duplicate_read(struct duplicate_file *file)
 {
-	int fd;
 	struct istream *input;
+	struct duplicate_file_header hdr;
 	const unsigned char *data;
 	size_t size;
-	time_t stamp;
-	unsigned int offset, id_size, user_size, change_count;
-	bool broken = FALSE;
+	int fd;
+	unsigned int record_size = 0;
 
 	fd = open(file->path, O_RDONLY);
 	if (fd == -1) {
@@ -97,66 +175,26 @@ static int duplicate_read(struct duplica
 
 	/* <timestamp> <id_size> <user_size> <id> <user> */
 	input = i_stream_create_fd(fd, DUPLICATE_BUFSIZE, FALSE);
-
-	change_count = 0;
-	while (i_stream_read_data(input, &data, &size, sizeof(stamp) +
-				  sizeof(id_size) + sizeof(user_size)) > 0) {
-		offset = 0;
-		memcpy(&stamp, data, sizeof(stamp));
-		offset += sizeof(stamp);
-		memcpy(&id_size, data + offset, sizeof(id_size));
-		offset += sizeof(id_size);
-		memcpy(&user_size, data + offset, sizeof(user_size));
-		offset += sizeof(user_size);
-
-		i_stream_skip(input, offset);
-
-		if (id_size == 0 || user_size == 0 ||
-		    id_size > DUPLICATE_BUFSIZE ||
-		    user_size > DUPLICATE_BUFSIZE) {
-			i_error("broken duplicate file %s", file->path);
-			broken = TRUE;
-			break;
-		}
-
-		if (i_stream_read_data(input, &data, &size,
-				       id_size + user_size - 1) <= 0) {
-			i_error("unexpected end of file in %s", file->path);
-			broken = TRUE;
-			break;
-		}
-
-		if (stamp >= ioloop_time) {
-			/* still valid, save it */
-			struct duplicate *d;
-			void *new_id;
-
-			new_id = p_malloc(file->pool, id_size);
-			memcpy(new_id, data, id_size);
-
-			d = p_new(file->pool, struct duplicate, 1);
-			d->id = new_id;
-			d->id_size = id_size;
-			d->user = p_strndup(file->pool,
-					    data + id_size, user_size);
-			d->time = stamp;
-			hash_insert(file->hash, d, d);
-		} else {
-                        change_count++;
-		}
-		i_stream_skip(input, id_size + user_size);
-	}
-
-	if (hash_count(file->hash) * COMPRESS_PERCENTAGE / 100 > change_count)
-		file->changed = TRUE;
+	if (i_stream_read_data(input, &data, &size, sizeof(hdr)) > 0) {
+		memcpy(&hdr, data, sizeof(hdr));
+		if (hdr.version == 0 || hdr.version > DUPLICATE_VERSION + 10) {
+			/* FIXME: backwards compatibility with v1.0 */
+			record_size = sizeof(time_t) + sizeof(uint32_t)*2;
+		} else if (hdr.version == DUPLICATE_VERSION) {
+			record_size = sizeof(struct duplicate_record_header);
+			i_stream_skip(input, sizeof(hdr));
+		}
+	}
+
+	if (record_size == 0 ||
+	    duplicate_read_records(file, input, record_size) < 0) {
+		if (unlink(file->path) < 0 && errno != ENOENT)
+			i_error("unlink(%s) failed: %m", file->path);
+	}
 
 	i_stream_unref(&input);
 	if (close(fd) < 0)
 		i_error("close(%s) failed: %m", file->path);
-	if (broken) {
-		if (unlink(file->path) < 0 && errno != ENOENT)
-			i_error("unlink(%s) failed: %m", file->path);
-	}
 	return 0;
 }
 
@@ -178,8 +216,11 @@ static struct duplicate_file *duplicate_
 	return file;
 }
 
-static void duplicate_free(struct duplicate_file *file)
-{
+static void duplicate_free(struct duplicate_file **_file)
+{
+	struct duplicate_file *file = *_file;
+
+	*_file = NULL;
 	if (file->dotlock != NULL)
 		file_dotlock_delete(&file->dotlock);
 
@@ -226,6 +267,8 @@ void duplicate_flush(void)
 void duplicate_flush(void)
 {
 	struct duplicate_file *file = duplicate_file;
+	struct duplicate_file_header hdr;
+	struct duplicate_record_header rec;
 	struct ostream *output;
         struct hash_iterate_context *iter;
 	void *key, *value;
@@ -233,17 +276,24 @@ void duplicate_flush(void)
 	if (duplicate_file == NULL || !file->changed || file->new_fd == -1)
 		return;
 
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.version = DUPLICATE_VERSION;
+
 	output = o_stream_create_fd_file(file->new_fd, 0, FALSE);
+	o_stream_send(output, &hdr, sizeof(hdr));
+
+	memset(&rec, 0, sizeof(rec));
 	iter = hash_iterate_init(file->hash);
 	while (hash_iterate(iter, &key, &value)) {
 		struct duplicate *d = value;
-		unsigned int user_size = strlen(d->user);
-
-		o_stream_send(output, &d->time, sizeof(d->time));
-		o_stream_send(output, &d->id_size, sizeof(d->id_size));
-		o_stream_send(output, &user_size, sizeof(user_size));
-		o_stream_send(output, d->id, d->id_size);
-		o_stream_send(output, d->user, user_size);
+
+		rec.stamp = d->time;
+		rec.id_size = d->id_size;
+		rec.user_size = strlen(d->user);
+
+		o_stream_send(output, &rec, sizeof(rec));
+		o_stream_send(output, d->id, rec.id_size);
+		o_stream_send(output, d->user, rec.user_size);
 	}
 	hash_iterate_deinit(&iter);
 	o_stream_unref(&output);
@@ -264,6 +314,6 @@ void duplicate_deinit(void)
 {
 	if (duplicate_file != NULL) {
 		duplicate_flush();
-		duplicate_free(duplicate_file);
-	}
-}
+		duplicate_free(&duplicate_file);
+	}
+}


More information about the dovecot-cvs mailing list