changeset 21408:a0c9a72975fc

lib-storage: Add vsize extension to index Keep virtual size in index, instead of cache when it's less than 2^32-1. This helps when cache becomes corrupted, and goes away, we still have virtual sizes for quota calculations.
author Aki Tuomi <aki.tuomi@dovecot.fi>
date Tue, 03 Jan 2017 17:21:33 +0200
parents 659c06acb979
children 1d5160a7b0fd
files src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h
diffstat 2 files changed, 51 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/index-mail.c	Sun Jan 15 19:56:32 2017 +0200
+++ b/src/lib-storage/index/index-mail.c	Tue Jan 03 17:21:33 2017 +0200
@@ -447,7 +447,20 @@
 bool index_mail_get_cached_virtual_size(struct index_mail *mail, uoff_t *size_r)
 {
 	struct index_mail_data *data = &mail->data;
+	struct mail *_mail = &mail->mail.mail;
 	uoff_t size;
+	const void *idata;
+	bool expunged ATTR_UNUSED;
+	unsigned int idx ATTR_UNUSED;
+
+	/* see if we can get it from index */
+	mail_index_lookup_ext(_mail->transaction->view, _mail->seq,
+			      mail->vsize_ext_id, &idata, &expunged);
+	const uint32_t *vsize = idata;
+
+	if (vsize != NULL && *vsize > 0) {
+		data->virtual_size = (*vsize)-1;
+	}
 
 	data->cache_fetch_fields |= MAIL_FETCH_VIRTUAL_SIZE;
 	if (data->virtual_size == (uoff_t)-1) {
@@ -468,6 +481,16 @@
 		data->body_size_set = TRUE;
 	}
 	*size_r = data->virtual_size;
+
+	/* if vsize is present and wanted for index, but missing from index
+	   add it to index. */
+	if (vsize != NULL && *vsize == 0 &&
+	    data->body_size.virtual_size < (uint32_t)-1) {
+		uint32_t vsize = data->body_size.virtual_size+1;
+		mail_index_update_ext(_mail->transaction->itrans, _mail->seq,
+				      mail->vsize_ext_id, &vsize, NULL);
+	}
+
 	return TRUE;
 }
 
@@ -832,16 +855,40 @@
 
 static void index_mail_cache_sizes(struct index_mail *mail)
 {
+	struct mail *_mail = &mail->mail.mail;
+	struct mail_index_view *view = _mail->transaction->view;
+
 	static enum index_cache_field size_fields[] = {
 		MAIL_CACHE_VIRTUAL_FULL_SIZE,
 		MAIL_CACHE_PHYSICAL_FULL_SIZE
 	};
 	uoff_t sizes[N_ELEMENTS(size_fields)];
 	unsigned int i;
+	uint32_t vsize;
+	uint32_t idx ATTR_UNUSED;
 
 	sizes[0] = mail->data.virtual_size;
 	sizes[1] = mail->data.physical_size;
 
+	/* store the virtual size in index if
+		extension for it exists or
+		extension for box virtual size exists
+	*/
+
+	if ((mail_index_map_get_ext_idx(view->map, mail->vsize_ext_id, &idx) ||
+	     mail_index_map_get_ext_idx(view->map, _mail->box->vsize_hdr_ext_id, &idx)) &&
+	    (sizes[0] != (uoff_t)-1 &&
+	     sizes[0] < (uint32_t)-1)) {
+		/* vsize = 0 means it's not present in index, consult cache.
+		   we store vsize for every +4GB-1 mail to cache because
+		   index can only hold 2^32-1 size. Cache will not be used
+		   when vsize is stored in index. */
+		vsize = sizes[0] + 1;
+		sizes[0] = (uoff_t)-1;
+		mail_index_update_ext(_mail->transaction->itrans, _mail->seq,
+				      mail->vsize_ext_id, &vsize, NULL);
+	}
+
 	for (i = 0; i < N_ELEMENTS(size_fields); i++) {
 		if (sizes[i] != (uoff_t)-1 &&
 		    index_mail_want_cache(mail, size_fields[i])) {
@@ -1490,7 +1537,9 @@
 	mail->mail.v = *t->box->mail_vfuncs;
 	mail->mail.mail.box = t->box;
 	mail->mail.mail.transaction = t;
-
+	mail->vsize_ext_id = mail_index_ext_register(t->box->index, "vsize", 0,
+						     sizeof(uint32_t),
+						     sizeof(uint32_t));
 	t->mail_ref_count++;
 	mail->mail.data_pool = pool_alloconly_create("index_mail", 16384);
 	mail->ibox = INDEX_STORAGE_CONTEXT(t->box);
--- a/src/lib-storage/index/index-mail.h	Sun Jan 15 19:56:32 2017 +0200
+++ b/src/lib-storage/index/index-mail.h	Tue Jan 03 17:21:33 2017 +0200
@@ -137,6 +137,7 @@
 	struct index_mailbox_context *ibox;
 
 	int pop3_state;
+	uint32_t vsize_ext_id;
 
 	/* per-mail variables, here for performance reasons: */
 	uint32_t header_seq;