Avoid wait-for-tick on single-message connections
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 2 Sep 2021 16:08:20 +0000 (17:08 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 2 Sep 2021 16:08:20 +0000 (17:08 +0100)
doc/doc-txt/ChangeLog
src/src/exim.c
src/src/globals.c
src/src/globals.h
src/src/receive.c

index 89df37585d249d91cecbdb861afa0208c47e712a..8e7749bbae3c4a60c70407a681d2a3ca2d42a1ac 100644 (file)
@@ -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
 -----------------
index 37e1b756a9a2641fdbf9dcc63e6dfab44b422dea..e15d5e4760d252557d471c5e4e53b645e1f45b19 100644 (file)
@@ -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;
 }
 
 
index c3e8a16cf3d38d24b2808f17c6faabf22d1a1022..50b9c2f2a93e3009f47ac07b9a2429807f275028 100644 (file)
@@ -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;
index d5d93148fc06385d520cd28301a67440f9d9e3c2..731408bd66be59557274dd3bc0739e2bca70df01 100644 (file)
@@ -724,7 +724,6 @@ extern uschar  message_id_option[];    /* -E<message-id> 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 */
index c2b313c637e5c7be54d6a0e5c25538afba14abbe..47c5977ee53db44ae0af187a3968ea64a5126ac9 100644 (file)
@@ -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)
   {