[dovecot-cvs] dovecot/src/lib-index mail-index-data.c,1.28,1.29 mail-index-update.c,1.29,1.30

cras at procontrol.fi cras at procontrol.fi
Tue Oct 29 07:22:14 EET 2002


Update of /home/cvs/dovecot/src/lib-index
In directory danu:/tmp/cvs-serv13285

Modified Files:
	mail-index-data.c mail-index-update.c 
Log Message:
Fixed (recently) broken updating of index data file. Also we don't leave
deleted data lying around in the file anymore but instead fill it with
zeros.



Index: mail-index-data.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-index-data.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- mail-index-data.c	28 Oct 2002 09:31:40 -0000	1.28
+++ mail-index-data.c	29 Oct 2002 05:22:12 -0000	1.29
@@ -133,6 +133,9 @@
 	}
 
 	if (size != 0) {
+		debug_mprotect(data->mmap_base, data->mmap_full_length,
+			       data->index);
+
 		if (pos + size <= data->mmap_used_length)
 			return TRUE;
 
@@ -444,6 +447,9 @@
 	i_assert((size & (MEM_ALIGN_SIZE-1)) == 0);
 	i_assert(data->index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
+	if (!mmap_update(data, 0, sizeof(MailIndexDataHeader)))
+		return 0;
+
 	if (size > data->mmap_full_length ||
 	    data->mmap_full_length - size < data->header->used_file_size) {
 		if (!mail_index_data_grow(data, size))
@@ -473,6 +479,11 @@
 
 	/* just mark it deleted. */
 	data->header->deleted_space += rec_hdr->data_size;
+
+	/* clear the record data. not really needed, but better not to keep
+	   deleted information lying around.. */
+	memset((char *) rec_hdr + sizeof(MailIndexDataRecordHeader), 0,
+	       rec_hdr->data_size - sizeof(MailIndexDataRecordHeader));
 
 	/* see if we've reached the max. deleted space in file */
 	if (data->header->used_file_size >= COMPRESS_MIN_SIZE &&

Index: mail-index-update.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/mail-index-update.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- mail-index-update.c	28 Oct 2002 09:46:03 -0000	1.29
+++ mail-index-update.c	29 Oct 2002 05:22:12 -0000	1.30
@@ -60,54 +60,76 @@
 	return -1;
 }
 
-static void get_changed_field_sizes(MailIndexUpdate *update,
-				    size_t *min_size, size_t *max_size)
-{
-	int i;
-
-	for (i = 0; i < DATA_FIELD_MAX_BITS; i++) {
-		if (update->fields[i] != NULL) {
-			*min_size += SIZEOF_MAIL_INDEX_DATA +
-				MEM_ALIGN(update->field_sizes[i]);
-			*max_size += SIZEOF_MAIL_INDEX_DATA +
-				MEM_ALIGN(update->field_sizes[i] +
-					  update->field_extra_sizes[i]);
-		}
-	}
-}
-
 static void get_data_block_sizes(MailIndexUpdate *update,
-				 size_t *min_size, size_t *max_size)
+				 size_t *min_size, size_t *max_size,
+				 int *no_grown_fields)
 {
 	MailIndexDataRecord *rec;
+	MailDataField field;
+	unsigned int field_min_size;
+	int i, field_exists;
 
-	/* first get size of new fields */
 	*min_size = *max_size = sizeof(MailIndexDataRecordHeader);
-	get_changed_field_sizes(update, min_size, max_size);
+	*no_grown_fields = TRUE;
 
-	/* then the size of unchanged fields */
 	rec = mail_index_data_lookup(update->index->data, update->rec, 0);
-	while (rec != NULL) {
-		if ((rec->field & update->updated_fields) == 0) {
+	for (i = 0, field = 1; field != DATA_FIELD_LAST; i++, field <<= 1) {
+		field_exists = rec != NULL && rec->field == field;
+
+		if (update->fields[i] != NULL) {
+			/* value was modified - use it */
+			field_min_size = MEM_ALIGN(update->field_sizes[i]);
+			*min_size += SIZEOF_MAIL_INDEX_DATA + field_min_size;
+			*max_size += SIZEOF_MAIL_INDEX_DATA +
+				MEM_ALIGN(update->field_sizes[i] +
+					  update->field_extra_sizes[i]);
+
+			if (!field_exists ||
+			    rec->full_field_size < field_min_size)
+				*no_grown_fields = FALSE;
+		} else if (field_exists) {
+			/* use the old value */
 			*min_size += SIZEOF_MAIL_INDEX_DATA +
 				rec->full_field_size;
 			*max_size += SIZEOF_MAIL_INDEX_DATA +
 				rec->full_field_size;
 		}
 
-		rec = mail_index_data_next(update->index->data,
-					   update->rec, rec);
+		if (field_exists) {
+			rec = mail_index_data_next(update->index->data,
+						   update->rec, rec);
+		}
 	}
 }
 
-/* Append all the data at the end of the data file and update 
-   the index's data position */
-static int update_by_append(MailIndexUpdate *update, size_t data_size)
+size_t get_max_align_size(size_t base, size_t extra, size_t *max_extra)
+{
+	size_t size;
+
+	size = MEM_ALIGN(base);
+	extra -= size - base;
+	if (*max_extra < MEM_ALIGN_SIZE || extra == 0)
+		return size; /* no extra / extra went into alignment */
+
+	extra = MEM_ALIGN(extra);
+	if (extra > *max_extra) {
+		/* partial */
+		extra = *max_extra & ~(MEM_ALIGN_SIZE-1);
+		i_assert(extra <= *max_extra);
+	}
+
+	*max_extra -= extra;
+	return base + extra;
+}
+
+/* extra_size is the amount of data in data_size which can be used for
+   field_extra_sizes */
+static void *create_data_block(MailIndexUpdate *update, size_t data_size,
+			       size_t extra_size)
 {
         MailIndexDataRecordHeader *dest_hdr;
         MailIndexDataRecord *rec, *destrec;
 	MailDataField field;
-	uoff_t fpos;
 	void *mem;
 	const void *src;
 	size_t pos, src_size;
@@ -132,8 +154,9 @@
 		if (update->fields[i] != NULL) {
 			/* value was modified - use it */
 			destrec->full_field_size =
-				MEM_ALIGN(update->field_sizes[i] +
-					  update->field_extra_sizes[i]);
+				get_max_align_size(update->field_sizes[i],
+						   update->field_extra_sizes[i],
+						   &extra_size);
 			src = update->fields[i];
 			src_size = update->field_sizes[i];
 		} else if (rec != NULL && rec->field == field) {
@@ -163,10 +186,23 @@
 		}
 	}
 
-	i_assert(pos == data_size);
+	i_assert(pos <= data_size);
+
+	return mem;
+}
+
+/* Append all the data at the end of the data file and update 
+   the index's data position */
+static int update_by_append(MailIndexUpdate *update, size_t data_size,
+			    size_t extra_size)
+{
+	void *mem;
+	uoff_t fpos;
+
+	mem = create_data_block(update, data_size, extra_size);
 
 	/* append the data at the end of the data file */
-	fpos = mail_index_data_append(update->index->data, mem, pos);
+	fpos = mail_index_data_append(update->index->data, mem, data_size);
 	if (fpos == 0)
 		return FALSE;
 
@@ -179,16 +215,37 @@
 	return TRUE;
 }
 
+/* Replace the whole block - assumes there's enoguh space to do it */
+static void update_by_replace_block(MailIndexUpdate *update, size_t extra_size)
+{
+	MailIndexDataRecordHeader *data_hdr;
+	size_t data_size;
+	void *mem;
+
+	data_hdr = mail_index_data_lookup_header(update->index->data,
+						 update->rec);
+
+	data_size = update->data_hdr.data_size;
+	i_assert(data_size == data_hdr->data_size);
+
+	mem = create_data_block(update, data_size, extra_size);
+	memcpy(data_hdr, mem, data_size);
+
+	/* clear the extra space. not really needed. */
+	memset((char *) data_hdr + data_size, 0,
+	       data_hdr->data_size - data_size);
+
+        mail_index_data_mark_modified(update->index->data);
+}
+
 /* Replace the modified fields in the file - assumes there's enough
    space to do it */
-static void update_by_replace(MailIndexUpdate *update)
+static void update_by_replace_fields(MailIndexUpdate *update)
 {
 	MailIndexDataRecord *rec;
+	size_t field_size;
 	int index;
 
-	// FIXME: 1) this doesn't work, 2) we need to handle optimally the
-	// writing of extra_space
-
 	rec = mail_index_data_lookup(update->index->data, update->rec, 0);
 	while (rec != NULL) {
 		if (rec->field & update->updated_fields) {
@@ -196,12 +253,16 @@
 			index = mail_field_get_index(rec->field);
 			i_assert(index >= 0);
 
-			i_assert(update->field_sizes[index] <=
-				 rec->full_field_size);
+			field_size = update->field_sizes[index];
+			i_assert(field_size <= rec->full_field_size);
 
-			memcpy(rec->data, update->fields[index],
-			       update->field_sizes[index]);
+			memcpy(rec->data, update->fields[index], field_size);
+
+			/* clear the extra space. not really needed. */
+			memset(rec->data + field_size, 0,
+			       rec->full_field_size - field_size);
 		}
+
 		rec = mail_index_data_next(update->index->data,
 					   update->rec, rec);
 	}
@@ -212,22 +273,29 @@
 int mail_index_update_end(MailIndexUpdate *update)
 {
 	MailIndexDataRecordHeader *data_hdr;
-	size_t min_size, max_size;
-	int failed = FALSE;
+	size_t min_size, max_size, extra_size;
+	int no_grown_fields, failed = FALSE;
 
 	i_assert(update->index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
 	if (update->updated_fields != 0) {
 		/* if fields don't fit to allocated data block, we have
 		   to move it to end of file */
-		get_data_block_sizes(update, &min_size, &max_size);
+		get_data_block_sizes(update, &min_size, &max_size,
+				     &no_grown_fields);
+		extra_size = max_size - min_size;
+
 		data_hdr = mail_index_data_lookup_header(update->index->data,
 							 update->rec);
 
-		if (data_hdr != NULL && min_size <= data_hdr->data_size)
-			update_by_replace(update);
-		else
-			failed = !update_by_append(update, max_size);
+		if (no_grown_fields)
+			update_by_replace_fields(update);
+		else if (data_hdr != NULL && min_size <= data_hdr->data_size)
+			update_by_replace_block(update, extra_size);
+		else {
+			if (!update_by_append(update, max_size, extra_size))
+				failed = TRUE;
+		}
 
 		if (!failed) {
 			/* update cached fields mask */




More information about the dovecot-cvs mailing list