changeset 21548:22a63dda10f0

lib-lda: Redesign mail_deliver_context.var_expand_table cache
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 17 Feb 2017 11:25:49 +0200
parents b8d061c8ff00
children 207a5e4b7a7f
files src/lib-lda/mail-deliver.c src/lib-lda/mail-deliver.h
diffstat 2 files changed, 78 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-lda/mail-deliver.c	Wed Apr 27 13:06:52 2016 +0300
+++ b/src/lib-lda/mail-deliver.c	Fri Feb 17 11:25:49 2017 +0200
@@ -17,6 +17,18 @@
 
 deliver_mail_func_t *deliver_mail = NULL;
 
+struct mail_deliver_cache {
+	bool filled;
+
+	const char *message_id;
+	const char *subject;
+	const char *from;
+	const char *from_envelope;
+	const char *storage_id;
+
+	uoff_t psize, vsize;
+};
+
 static const char *lda_log_wanted_headers[] = {
 	"From", "Message-ID", "Subject",
 	NULL
@@ -39,104 +51,92 @@
 		NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL);
 }
 
-static void
-mail_deliver_log_var_expand_table_update_times(struct mail_deliver_context *ctx,
-					       struct var_expand_table *tab)
+static void update_cache(struct mail_deliver_context *ctx,
+			 const char **old_str, const char *new_str)
 {
-#define VAR_EXPAND_DELIVERY_TIME_IDX 7
-	int delivery_time_msecs;
-
-	io_loop_time_refresh();
-	delivery_time_msecs = timeval_diff_msecs(&ioloop_timeval,
-						 &ctx->delivery_time_started);
-	tab[VAR_EXPAND_DELIVERY_TIME_IDX].value = dec2str(delivery_time_msecs);
+	if (new_str == NULL || new_str[0] == '\0')
+		*old_str = NULL;
+	else if (*old_str == NULL || strcmp(*old_str, new_str) != 0)
+		*old_str = p_strdup(ctx->pool, new_str);
 }
 
-static const struct var_expand_table *
-mail_deliver_get_log_var_expand_table_full(struct mail_deliver_context *ctx,
-					   struct mail *mail,
-					   const char *message)
+static void
+mail_deliver_log_update_cache(struct mail_deliver_context *ctx)
 {
-	const char *message_id, *subject = NULL, *from_envelope = NULL;
-	const char *from, *psize = NULL, *vsize = NULL, *storage_id = NULL;
-	const char *session_time = NULL, *to_envelope = NULL;
-	uoff_t size;
+	struct mail *mail;
+	const char *message_id = NULL, *subject = NULL, *from_envelope = NULL;
+	const char *from, *storage_id = NULL;
 
-	if (mail_get_first_header(mail, "Message-ID", &message_id) <= 0)
-		message_id = "unspecified";
-	else
+	if (ctx->cache == NULL)
+		ctx->cache = p_new(ctx->pool, struct mail_deliver_cache, 1);
+	else if (ctx->cache->filled)
+		return;
+	ctx->cache->filled = TRUE;
+
+	mail = ctx->dest_mail != NULL ? ctx->dest_mail : ctx->src_mail;
+
+	if (mail_get_first_header(mail, "Message-ID", &message_id) > 0)
 		message_id = str_sanitize(message_id, 200);
+	update_cache(ctx, &ctx->cache->message_id, message_id);
 
 	if (mail_get_first_header_utf8(mail, "Subject", &subject) > 0)
 		subject = str_sanitize(subject, 80);
+	update_cache(ctx, &ctx->cache->subject, subject);
+
 	from = str_sanitize(mail_deliver_get_address(mail, "From"), 80);
+	update_cache(ctx, &ctx->cache->from, from);
 
 	if (mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE, &from_envelope) > 0)
 		from_envelope = str_sanitize(from_envelope, 80);
+	update_cache(ctx, &ctx->cache->from_envelope, from_envelope);
 
-	if (mail_get_physical_size(mail, &size) == 0)
-		psize = dec2str(size);
-	if (mail_get_virtual_size(mail, &size) == 0)
-		vsize = dec2str(size);
-	session_time = dec2str(ctx->session_time_msecs);
-	to_envelope = ctx->dest_addr;
 	(void)mail_get_special(mail, MAIL_FETCH_STORAGE_ID, &storage_id);
+	update_cache(ctx, &ctx->cache->storage_id, storage_id);
 
-	const struct var_expand_table stack_tab[] = {
-		{ '$', message, NULL },
-		{ 'm', message_id, "msgid" },
-		{ 's', subject, "subject" },
-		{ 'f', from, "from" },
-		{ 'e', from_envelope, "from_envelope" },
-		{ 'p', psize, "size" },
-		{ 'w', vsize, "vsize" },
-		/* must be VAR_EXPAND_DELIVERY_TIME_IDX */
-		{ '\0', NULL, "delivery_time" },
-		{ '\0', session_time, "session_time" },
-		{ '\0', to_envelope, "to_envelope" },
-		{ '\0', storage_id, "storage_id" },
-		{ '\0', NULL, NULL }
-	};
-	struct var_expand_table *tab;
-
-	tab = t_malloc(sizeof(stack_tab));
-	memcpy(tab, stack_tab, sizeof(stack_tab));
-	mail_deliver_log_var_expand_table_update_times(ctx, tab);
-	return tab;
+	if (mail_get_physical_size(mail, &ctx->cache->psize) < 0)
+		ctx->cache->psize = 0;
+	if (mail_get_virtual_size(mail, &ctx->cache->vsize) < 0)
+		ctx->cache->vsize = 0;
 }
 
 const struct var_expand_table *
 mail_deliver_ctx_get_log_var_expand_table(struct mail_deliver_context *ctx,
 					  const char *message)
 {
-	struct mail *mail;
+	unsigned int delivery_time_msecs;
 
-	mail = ctx->dest_mail != NULL ? ctx->dest_mail : ctx->src_mail;
-	return mail_deliver_get_log_var_expand_table_full(ctx, mail, message);
-}
+	mail_deliver_log_update_cache(ctx);
+	/* This call finishes a mail delivery. With Sieve there may be multiple
+	   mail deliveries. */
+	ctx->cache->filled = FALSE;
+
+	io_loop_time_refresh();
+	delivery_time_msecs = timeval_diff_msecs(&ioloop_timeval,
+						 &ctx->delivery_time_started);
 
-static void
-mail_deliver_log_cache_var_expand_table(struct mail_deliver_context *ctx)
-{
-	const struct var_expand_table *src;
-	struct var_expand_table *dest;
-	unsigned int i, len;
-
-	src = mail_deliver_ctx_get_log_var_expand_table(ctx, "");
-	for (len = 0; src[len].key != '\0' || src[len].long_key != NULL; len++) ;
-
-	dest = p_new(ctx->pool, struct var_expand_table, len + 1);
-	for (i = 0; i < len; i++) {
-		dest[i] = src[i];
-		dest[i].value = p_strdup(ctx->pool, src[i].value);
-	}
-	ctx->var_expand_table = dest;
+	const struct var_expand_table stack_tab[] = {
+		{ '$', message, NULL },
+		{ 'm', ctx->cache->message_id != NULL ?
+		       ctx->cache->message_id : "unspecified", "msgid" },
+		{ 's', ctx->cache->subject, "subject" },
+		{ 'f', ctx->cache->from, "from" },
+		{ 'e', ctx->cache->from_envelope, "from_envelope" },
+		{ 'p', dec2str(ctx->cache->psize), "size" },
+		{ 'w', dec2str(ctx->cache->vsize), "vsize" },
+		{ '\0', dec2str(delivery_time_msecs), "delivery_time" },
+		{ '\0', dec2str(ctx->session_time_msecs), "session_time" },
+		{ '\0', ctx->dest_addr, "to_envelope" },
+		{ '\0', ctx->cache->storage_id, "storage_id" },
+		{ '\0', NULL, NULL }
+	};
+	return p_memdup(unsafe_data_stack_pool, stack_tab, sizeof(stack_tab));
 }
 
 void mail_deliver_log(struct mail_deliver_context *ctx, const char *fmt, ...)
 {
 	va_list args;
 	string_t *str;
+	const struct var_expand_table *tab;
 	const char *msg;
 
 	if (*ctx->set->deliver_log_format == '\0')
@@ -146,15 +146,8 @@
 	msg = t_strdup_vprintf(fmt, args);
 
 	str = t_str_new(256);
-
-	if (ctx->var_expand_table == NULL)
-		mail_deliver_log_cache_var_expand_table(ctx);
-	/* update %$ */
-	ctx->var_expand_table[0].value = msg;
-	mail_deliver_log_var_expand_table_update_times(ctx, ctx->var_expand_table);
-	var_expand(str, ctx->set->deliver_log_format, ctx->var_expand_table);
-	ctx->var_expand_table[0].value = "";
-	ctx->var_expand_table[VAR_EXPAND_DELIVERY_TIME_IDX].value = "";
+	tab = mail_deliver_ctx_get_log_var_expand_table(ctx, msg);
+	var_expand(str, ctx->set->deliver_log_format, tab);
 
 	i_info("%s", str_c(str));
 	va_end(args);
@@ -375,8 +368,10 @@
 
 	if (mailbox_save_using_mail(&save_ctx, ctx->src_mail) < 0)
 		ret = -1;
-	else
-		mail_deliver_log_cache_var_expand_table(ctx);
+	else {
+		/* fill the cache while we still have dest_mail */
+		mail_deliver_log_update_cache(ctx);
+	}
 	if (kw != NULL)
 		mailbox_keywords_unref(&kw);
 
@@ -399,7 +394,7 @@
 			}
 			/* might as well get the storage_id */
 			(void)mail_get_special(ctx->dest_mail, MAIL_FETCH_STORAGE_ID,
-					       &ctx->var_expand_table[10].value);
+					       &ctx->cache->storage_id);
 		} else if (var_has_key(ctx->set->deliver_log_format, '\0', "storage_id")) {
 			/* storage ID is available only after commit. */
 			struct mail *mail = mail_deliver_open_mail(box, &changes,
@@ -408,7 +403,7 @@
 				const char *str;
 
 				(void)mail_get_special(mail, MAIL_FETCH_STORAGE_ID, &str);
-				ctx->var_expand_table[10].value = t_strdup(str);
+				ctx->cache->storage_id = t_strdup(str);
 				mail_free(&mail);
 				(void)mailbox_transaction_commit(&t);
 			}
--- a/src/lib-lda/mail-deliver.h	Wed Apr 27 13:06:52 2016 +0300
+++ b/src/lib-lda/mail-deliver.h	Fri Feb 17 11:25:49 2017 +0200
@@ -55,8 +55,8 @@
 	   the mailbox. */
 	struct mail *dest_mail;
 
-	/* mail_deliver_log() caches the var expand table here */
-	struct var_expand_table *var_expand_table;
+	/* mail_deliver_log() caches the var expand table values here */
+	struct mail_deliver_cache *cache;
 
 	/* Error message for a temporary failure. This is necessary only when
 	   there is no storage where to get the error message from. */