From: Jeremy Harris Date: Thu, 2 Sep 2021 16:08:20 +0000 (+0100) Subject: Avoid wait-for-tick on single-message connections X-Git-Tag: exim-4.96-RC0~162^2~6 X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/8271f864edaf7fb2db0eb3aaa0c4789f55125978 Avoid wait-for-tick on single-message connections --- diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index 89df37585..8e7749bba 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -2,6 +2,14 @@ This document describes *changes* to previous versions, that might affect Exim's operation, with an unchanged configuration file. For new options, and new features, see the NewStuff file next to this ChangeLog. +Since 4.95 +---------- + +JH/01 Move the wait-for-next-tick (needed for unique messmage IDs) from + after reception to before a subsequence reception. This should + mean slightly faster delivery, and also confirmation of reception + to senders. + Exim version 4.95 ----------------- diff --git a/src/src/exim.c b/src/src/exim.c index 37e1b756a..e15d5e476 100644 --- a/src/src/exim.c +++ b/src/src/exim.c @@ -444,9 +444,10 @@ function prepares for the time when things are faster - and it also copes with clocks that go backwards. Arguments: - tgt_tv A timeval which was used to create uniqueness; its usec field + prev_tv A timeval which was used to create uniqueness; its usec field has been rounded down to the value of the resolution. We want to be sure the current time is greater than this. + On return, updated to current (rounded down). resolution The resolution that was used to divide the microseconds (1 for maildir, larger for message ids) @@ -454,7 +455,7 @@ Returns: nothing */ void -exim_wait_tick(struct timeval * tgt_tv, int resolution) +exim_wait_tick(struct timeval * prev_tv, int resolution) { struct timeval now_tv; long int now_true_usec; @@ -463,13 +464,13 @@ exim_gettime(&now_tv); now_true_usec = now_tv.tv_usec; now_tv.tv_usec = (now_true_usec/resolution) * resolution; -while (exim_tvcmp(&now_tv, tgt_tv) <= 0) +while (exim_tvcmp(&now_tv, prev_tv) <= 0) { struct itimerval itval; itval.it_interval.tv_sec = 0; itval.it_interval.tv_usec = 0; - itval.it_value.tv_sec = tgt_tv->tv_sec - now_tv.tv_sec; - itval.it_value.tv_usec = tgt_tv->tv_usec + resolution - now_true_usec; + itval.it_value.tv_sec = prev_tv->tv_sec - now_tv.tv_sec; + itval.it_value.tv_usec = prev_tv->tv_usec + resolution - now_true_usec; /* We know that, overall, "now" is less than or equal to "then". Therefore, a negative value for the microseconds is possible only in the case when "now" @@ -487,7 +488,7 @@ while (exim_tvcmp(&now_tv, tgt_tv) <= 0) if (!f.running_in_test_harness) { debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n", - tgt_tv->tv_sec, (long) tgt_tv->tv_usec, + prev_tv->tv_sec, (long) prev_tv->tv_usec, now_tv.tv_sec, (long) now_tv.tv_usec); debug_printf("waiting " TIME_T_FMT ".%06lu sec\n", itval.it_value.tv_sec, (long) itval.it_value.tv_usec); @@ -503,6 +504,7 @@ while (exim_tvcmp(&now_tv, tgt_tv) <= 0) now_true_usec = now_tv.tv_usec; now_tv.tv_usec = (now_true_usec/resolution) * resolution; } +*prev_tv = now_tv; } diff --git a/src/src/globals.c b/src/src/globals.c index c3e8a16cf..50b9c2f2a 100644 --- a/src/src/globals.c +++ b/src/src/globals.c @@ -1167,7 +1167,6 @@ uschar *message_headers = NULL; uschar *message_id; uschar *message_id_domain = NULL; uschar *message_id_text = NULL; -struct timeval message_id_tv = { 0, 0 }; uschar message_id_option[MESSAGE_ID_LENGTH + 3]; uschar *message_id_external; int message_linecount = 0; diff --git a/src/src/globals.h b/src/src/globals.h index d5d93148f..731408bd6 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -724,7 +724,6 @@ extern uschar message_id_option[]; /* -E for use as option */ extern uschar *message_id_external; /* External form of following */ extern uschar *message_id_domain; /* Expanded to form domain-part of message_id */ extern uschar *message_id_text; /* Expanded to form message_id */ -extern struct timeval message_id_tv; /* Time used to create last message_id */ extern int message_linecount; /* As it says */ extern BOOL message_logs; /* TRUE to write message logs */ extern int message_size; /* Size of message */ diff --git a/src/src/receive.c b/src/src/receive.c index c2b313c63..47c5977ee 100644 --- a/src/src/receive.c +++ b/src/src/receive.c @@ -1664,9 +1664,9 @@ int error_rc = error_handling == ERRORS_SENDER ? errors_sender_rc : EXIT_FAILURE; int header_size = 256; int start, end, domain; -int id_resolution = 0; int had_zero = 0; int prevlines_length = 0; +const int id_resolution = BASE_62 == 62 ? 5000 : 10000; int ptr = 0; @@ -1720,6 +1720,10 @@ BOOL msgid_header_newly_created = FALSE; uschar *timestamp; int tslen; +/* Time of creation of message_id */ + +static struct timeval message_id_tv = { 0, 0 }; + /* Release any open files that might have been cached while preparing to accept the message - e.g. by verifying addresses - because reading a message @@ -1786,13 +1790,32 @@ if (smtp_input && !smtp_batched_input && !f.dkim_disable_verify) if (sender_host_address) dmarc_init(); /* initialize libopendmarc */ #endif +/* In SMTP sessions we may receive several messages in one connection. Before +each subsequent one, we wait for the clock to tick at the level of message-id +granularity. +This is so that the combination of time+pid is unique, even on systems where the +pid can be re-used within our time interval. We can't shorten the interval +without re-designing the message-id. See comments above where the message id is +created. This is Something For The Future. +Do this wait any time we have previously created a message-id, even if we +rejected the message. This gives unique IDs for logging done by ACLs. +The initial timestamp must have been obtained via exim_gettime() to avoid +issues on Linux with suspend/resume. */ + +if (message_id_tv.tv_sec) + { + message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution; + exim_wait_tick(&message_id_tv, id_resolution); + } + /* Remember the time of reception. Exim uses time+pid for uniqueness of message ids, and fractions of a second are required. See the comments that precede the message id creation below. We use a routine that if possible uses a monotonic clock, and can be used again after reception for the tick-wait even under the Linux non-Posix behaviour. */ -exim_gettime(&message_id_tv); +else + exim_gettime(&message_id_tv); /* For other uses of the received time we can operate with granularity of one second, and for that we use the global variable received_time. This is for @@ -2681,28 +2704,20 @@ message_id[6] = '-'; Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6); /* Deal with the case where the host number is set. The value of the number was -checked when it was read, to ensure it isn't too big. The timing granularity is -left in id_resolution so that an appropriate wait can be done after receiving -the message, if necessary (we hope it won't be). */ +checked when it was read, to ensure it isn't too big. */ if (host_number_string) - { - id_resolution = BASE_62 == 62 ? 5000 : 10000; sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s", string_base62((long int)( host_number * (1000000/id_resolution) + message_id_tv.tv_usec/id_resolution)) + 4); - } /* Host number not set: final field is just the fractional time at an appropriate resolution. */ else - { - id_resolution = BASE_62 == 62 ? 500 : 1000; sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s", string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4); - } /* Add the current message id onto the current process info string if it will fit. */ @@ -4323,26 +4338,6 @@ then we can think about properly declaring the message not-received. */ TIDYUP: -/* In SMTP sessions we may receive several messages in one connection. After -each one, we wait for the clock to tick at the level of message-id granularity. -This is so that the combination of time+pid is unique, even on systems where the -pid can be re-used within our time interval. We can't shorten the interval -without re-designing the message-id. See comments above where the message id is -created. This is Something For The Future. -Do this wait any time we have created a message-id, even if we rejected the -message. This gives unique IDs for logging done by ACLs. -The initial timestamp must have been obtained via exim_gettime() to avoid -issues on Linux with suspend/resume. -It would be Nicer to only pause before a follow-on message. */ - -if (id_resolution != 0) - { - message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution; - exim_wait_tick(&message_id_tv, id_resolution); - id_resolution = 0; - } - - process_info[process_info_len] = 0; /* Remove message id */ if (spool_data_file && cutthrough_done == NOT_TRIED) {