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.
 
 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
 -----------------
 
 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:
 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.
                  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)
 
   resolution   The resolution that was used to divide the microseconds
                  (1 for maildir, larger for message ids)
 
@@ -454,7 +455,7 @@ Returns:       nothing
 */
 
 void
 */
 
 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;
 {
 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;
 
 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;
   {
   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"
 
   /* 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",
     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);
                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;
   }
   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;
 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;
 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 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 */
 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;
        ? 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;
 int  had_zero = 0;
 int  prevlines_length = 0;
+const int id_resolution = BASE_62 == 62 ? 5000 : 10000;
 
 int ptr = 0;
 
 
 int ptr = 0;
 
@@ -1720,6 +1720,10 @@ BOOL msgid_header_newly_created = FALSE;
 uschar *timestamp;
 int tslen;
 
 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
 
 /* 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
 
 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. */
 
 /* 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
 
 /* 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
 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)
 
 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);
   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
 
 /* 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);
   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. */
 
 /* 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:
 
 
 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)
   {
 process_info[process_info_len] = 0;                    /* Remove message id */
 if (spool_data_file && cutthrough_done == NOT_TRIED)
   {