src.lock_maildirsize
changeset 7 3e755b50b6a4
parent 6 d2183655483b
child 8 282974b20ef8
equal deleted inserted replaced
6:d2183655483b 7:3e755b50b6a4
     1 # HG changeset patch
     1 # HG changeset patch
     2 # Parent 5037ac63d7aece4b5e96e26bace1ab4b7e791804
     2 # Parent d54ee7005f7f7b5970ce45caf7487a9fd929e55f
     3 
     3 
     4 diff -r 5037ac63d7ae Local/Makefile
     4 diff -r d54ee7005f7f Local/Makefile
     5 --- a/Local/Makefile	Sat Feb 19 13:42:16 2011 +0100
     5 --- a/Local/Makefile	Mon Feb 21 22:52:42 2011 +0100
     6 +++ b/Local/Makefile	Sun Feb 20 23:37:25 2011 +0100
     6 +++ b/Local/Makefile	Wed Feb 23 00:53:29 2011 +0100
     7 @@ -1,4 +1,5 @@
     7 @@ -1,4 +1,5 @@
     8  # $Cambridge: exim/src/src/EDITME,v 1.27 2010/06/12 15:21:25 jetmore Exp $
     8  # $Cambridge: exim/src/src/EDITME,v 1.27 2010/06/12 15:21:25 jetmore Exp $
     9 +EXTRALIBS_EXIM=-lrt
     9 +EXTRALIBS_EXIM=-lrt
    10  
    10  
    11  ##################################################
    11  ##################################################
    12  #          The Exim mail transport agent         #
    12  #          The Exim mail transport agent         #
    13 diff -r 5037ac63d7ae src/transports/appendfile.c
    13 diff -r d54ee7005f7f src/transports/appendfile.c
    14 --- a/src/transports/appendfile.c	Sat Feb 19 13:42:16 2011 +0100
    14 --- a/src/transports/appendfile.c	Mon Feb 21 22:52:42 2011 +0100
    15 +++ b/src/transports/appendfile.c	Sun Feb 20 23:37:25 2011 +0100
    15 +++ b/src/transports/appendfile.c	Wed Feb 23 00:53:29 2011 +0100
    16 @@ -13,6 +13,7 @@
    16 @@ -13,6 +13,7 @@
    17  
    17  
    18  #ifdef SUPPORT_MAILDIR
    18  #ifdef SUPPORT_MAILDIR
    19  #include "tf_maildir.h"
    19  #include "tf_maildir.h"
    20 +extern int lockfd;				/* from tf_maildir */	// hs12
    20 +extern int lockfd;				/* from tf_maildir */	// hs12
    21  #endif
    21  #endif
    22  
    22  
    23  
    23  
    24 @@ -278,8 +279,8 @@
    24 @@ -239,6 +240,30 @@
       
    25    TRUE            /* quota_is_inclusive */
       
    26  };
       
    27  
       
    28 +void hs12_lock(int fd, int type, const char* msg)
       
    29 +{
       
    30 +	struct timespec t0, t1;
       
    31 +	clock_gettime(CLOCK_REALTIME, &t0);
       
    32 +	const char *ltype =
       
    33 +			type == F_UNLCK ? "UNLOCK"
       
    34 +			: type == F_RDLCK ? "READ LOCK"
       
    35 +			: "WRITE LOCK";
       
    36 +
       
    37 +	DEBUG(D_transport) debug_printf("%s: %s\n", ltype, msg);
       
    38 +					
       
    39 +
       
    40 +	(void)apply_lock(fd, type, 1, 120, 0, 0);
       
    41 +	if (type == F_UNLCK) return;
       
    42 +
       
    43 +	clock_gettime(CLOCK_REALTIME, &t1);
       
    44 +	t1.tv_sec -= t0.tv_sec;
       
    45 +	t1.tv_nsec -= t0.tv_nsec;
       
    46 +	if (t1.tv_nsec < 0) { t1.tv_sec--; t1.tv_nsec *= -1; }
       
    47 +	DEBUG(D_transport) 
       
    48 +		 debug_printf("%s: %s was waiting for %d.%09d seconds\n", 
       
    49 +			 ltype, msg, t1.tv_sec, t1.tv_nsec);
       
    50 +	return;
       
    51 +}
       
    52  
       
    53  
       
    54  /*************************************************
       
    55 @@ -278,8 +303,8 @@
    25  gid = gid;
    56  gid = gid;
    26  
    57  
    27  if (ob->expand_maildir_use_size_file)
    58  if (ob->expand_maildir_use_size_file)
    28 -	ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
    59 -	ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
    29 -		US"`maildir_use_size_file` in transport", tblock->name);
    60 -		US"`maildir_use_size_file` in transport", tblock->name);
    30 +  ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
    61 +  ob->maildir_use_size_file = expand_check_condition(ob->expand_maildir_use_size_file, 
    31 +    US"`maildir_use_size_file` in transport", tblock->name);
    62 +    US"`maildir_use_size_file` in transport", tblock->name);
    32  
    63  
    33  /* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size,
    64  /* Loop for quota, quota_filecount, quota_warn_threshold, mailbox_size,
    34  mailbox_filecount */
    65  mailbox_filecount */
    35 @@ -841,7 +842,7 @@
    66 @@ -841,7 +866,7 @@
    36                sigalrm_seen set if there has been a timeout
    67                sigalrm_seen set if there has been a timeout
    37  */
    68  */
    38  
    69  
    39 -static int
    70 -static int
    40 +int
    71 +int
    41  apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
    72  apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
    42      int flocktime)
    73      int flocktime)
    43  {
    74  {
    44 @@ -887,7 +888,6 @@
    75 @@ -887,7 +912,6 @@
    45  
    76  
    46  
    77  
    47  
    78  
    48 -
    79 -
    49  #ifdef SUPPORT_MBX
    80  #ifdef SUPPORT_MBX
    50  /*************************************************
    81  /*************************************************
    51  *         Copy message into MBX mailbox          *
    82  *         Copy message into MBX mailbox          *
    52 @@ -2416,18 +2416,32 @@
    83 @@ -2416,18 +2440,19 @@
    53        {
    84        {
    54        off_t size;
    85        off_t size;
    55        int filecount;
    86        int filecount;
    56 +      uschar *excuse;
    87 +      uschar *excuse;
    57 +
       
    58 +      struct timespec t0, t1;
       
    59 +      clock_gettime(CLOCK_REALTIME, &t0);
       
    60  
    88  
    61        maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex,
    89        maildirsize_fd = maildir_ensure_sizefile(check_path, ob, regex, dir_regex,
    62 -        &size, &filecount);
    90 -        &size, &filecount);
    63 +        &size, &filecount, &excuse);
    91 +        &size, &filecount, &excuse);
    64  
    92  
    65        if (maildirsize_fd == -1)
    93        if (maildirsize_fd == -1)
    66          {
    94          {
    67          addr->basic_errno = errno;
    95          addr->basic_errno = errno;
    68 -        addr->message = string_sprintf("while opening or reading "
    96 -        addr->message = string_sprintf("while opening or reading "
    69 -          "%s/maildirsize", check_path);
    97 -          "%s/maildirsize", check_path);
    70 +        //addr->message = string_sprintf("%s", excuse);
       
    71 +        addr->message = excuse;
    98 +        addr->message = excuse;
    72          return FALSE;
    99          return FALSE;
    73          }
   100          }
    74  
   101  
    75 +
   102 +
    76 +      clock_gettime(CLOCK_REALTIME, &t1);
       
    77 +      t1.tv_sec -= t0.tv_sec;
       
    78 +      t1.tv_nsec -= t0.tv_nsec;
       
    79 +      if (t1.tv_nsec < 0) { t1.tv_sec--; t1.tv_nsec *= -1; }
       
    80 +      DEBUG(D_transport) {
       
    81 +         if (t1.tv_sec >= 1) debug_printf("%s/maildirsize was locked for %d.09ld seconds\n",
       
    82 +          check_path, t1.tv_sec, t1.tv_nsec);
       
    83 +      }
       
    84 +          
       
    85        if (mailbox_size < 0) mailbox_size = size;
   103        if (mailbox_size < 0) mailbox_size = size;
    86        if (mailbox_filecount < 0) mailbox_filecount = filecount;
   104        if (mailbox_filecount < 0) mailbox_filecount = filecount;
    87        }
   105        }
    88 @@ -3125,6 +3139,8 @@
   106 @@ -3125,6 +3150,8 @@
    89        uschar *renamename = newname;
   107        uschar *renamename = newname;
    90        fd = -1;
   108        fd = -1;
    91  
   109  
    92 +			if (lockfd >= 0) (void)apply_lock(lockfd, F_RDLCK, 1, 120, 0, 0);  // hs12
   110 +			if (lockfd >= 0) hs12_lock(lockfd, F_RDLCK, "delivery");
    93 +
   111 +
    94        DEBUG(D_transport) debug_printf("renaming temporary file\n");
   112        DEBUG(D_transport) debug_printf("renaming temporary file\n");
    95  
   113  
    96        /* If there is no rename name set, we are in a non-maildir, non-mailstore
   114        /* If there is no rename name set, we are in a non-maildir, non-mailstore
    97 @@ -3245,6 +3261,7 @@
   115 @@ -3245,6 +3272,7 @@
    98            filename = dataname = NULL;   /* Prevents attempt to unlink at end */
   116            filename = dataname = NULL;   /* Prevents attempt to unlink at end */
    99            }
   117            }
   100          }        /* maildir or mailstore */
   118          }        /* maildir or mailstore */
   101 +
   119 +
   102        }          /* successful write + close */
   120        }          /* successful write + close */
   103      }            /* isdirectory */
   121      }            /* isdirectory */
   104    }              /* write success */
   122    }              /* write success */
   105 @@ -3280,6 +3297,11 @@
   123 @@ -3280,6 +3308,11 @@
   106  detected, in order to get the file closed and the lock file tidied away. */
   124  detected, in order to get the file closed and the lock file tidied away. */
   107  
   125  
   108  RETURN:
   126  RETURN:
   109 +if (lockfd >= 0) 
   127 +if (lockfd >= 0) 
   110 +  {
   128 +  {
   111 +	(void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0); // hs12
   129 +	hs12_lock(lockfd, F_UNLCK, "done delivery");
   112 +	(void)close(lockfd);
   130 +	(void)close(lockfd);
   113 +	}
   131 +	}
   114  
   132  
   115  #ifdef SUPPORT_MBX
   133  #ifdef SUPPORT_MBX
   116  if (mbx_lockfd >= 0)
   134  if (mbx_lockfd >= 0)
   117 diff -r 5037ac63d7ae src/transports/appendfile.h
   135 diff -r d54ee7005f7f src/transports/appendfile.h
   118 --- a/src/transports/appendfile.h	Sat Feb 19 13:42:16 2011 +0100
   136 --- a/src/transports/appendfile.h	Mon Feb 21 22:52:42 2011 +0100
   119 +++ b/src/transports/appendfile.h	Sun Feb 20 23:37:25 2011 +0100
   137 +++ b/src/transports/appendfile.h	Wed Feb 23 00:53:29 2011 +0100
   120 @@ -95,5 +95,8 @@
   138 @@ -95,5 +95,8 @@
   121  /* Function that is shared with tf_maildir.c */
   139  /* Function that is shared with tf_maildir.c */
   122  
   140  
   123  extern off_t  check_dir_size(uschar *, int *, const pcre *);
   141  extern off_t  check_dir_size(uschar *, int *, const pcre *);
   124 +extern int apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
   142 +extern int apply_lock(int fd, int fcntltype, BOOL dofcntl, int fcntltime, BOOL doflock,
   125 +    int flocktime);
   143 +    int flocktime);
   126 +
   144 +
   127  
   145  
   128  /* End of transports/appendfile.h */
   146  /* End of transports/appendfile.h */
   129 diff -r 5037ac63d7ae src/transports/tf_maildir.c
   147 diff -r d54ee7005f7f src/transports/tf_maildir.c
   130 --- a/src/transports/tf_maildir.c	Sat Feb 19 13:42:16 2011 +0100
   148 --- a/src/transports/tf_maildir.c	Mon Feb 21 22:52:42 2011 +0100
   131 +++ b/src/transports/tf_maildir.c	Sun Feb 20 23:37:25 2011 +0100
   149 +++ b/src/transports/tf_maildir.c	Wed Feb 23 00:53:29 2011 +0100
   132 @@ -367,13 +367,16 @@
   150 @@ -367,13 +367,16 @@
   133  
   151  
   134  Returns:           >=0  a file descriptor for an open maildirsize file
   152  Returns:           >=0  a file descriptor for an open maildirsize file
   135                     -1   there was an error opening or accessing the file
   153                     -1   there was an error opening or accessing the file
   136 +				        or locking
   154 +				        or locking
   145 -  int *returned_filecount)
   163 -  int *returned_filecount)
   146 +  int *returned_filecount, uschar **excuse)
   164 +  int *returned_filecount, uschar **excuse)
   147  {
   165  {
   148  int count, fd;
   166  int count, fd;
   149  off_t cached_quota = 0;
   167  off_t cached_quota = 0;
   150 @@ -381,25 +384,80 @@
   168 @@ -381,25 +384,48 @@
   151  int filecount = 0;
   169  int filecount = 0;
   152  int linecount = 0;
   170  int linecount = 0;
   153  off_t size = 0;
   171  off_t size = 0;
   154 -uschar *filename;
   172 -uschar *filename;
   155 +uschar *filename, *lockname, *hitchname;
   173 +uschar *filename, *lockname, *hitchname;
   156  uschar buffer[MAX_FILE_SIZE];
   174  uschar buffer[MAX_FILE_SIZE];
   157  uschar *ptr = buffer;
   175  uschar *ptr = buffer;
   158  uschar *endptr;
   176  uschar *endptr;
   159  
   177  
       
   178 -/* Try a few times to open or create the file, in case another process is doing
       
   179 -the same thing. */
   160 +filename = string_sprintf("%s/maildirsize", path);
   180 +filename = string_sprintf("%s/maildirsize", path);
   161 +lockname = string_sprintf("%s.lock", filename);
   181 +lockname = string_sprintf("%s.lock", filename);
   162 +hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname,
   182 +hitchname = string_sprintf( "%s.%s.%08x.%08x", lockname, primary_hostname,
   163 +      (unsigned int)(time(NULL)), (unsigned int)getpid());
   183 +      (unsigned int)(time(NULL)), (unsigned int)getpid());
   164 +
   184  
       
   185 -filename = string_sprintf("%s/maildirsize", path);
   165 +/* Try to create a lock file. Here we should copy the loop from appendfile.c,
   186 +/* Try to create a lock file. Here we should copy the loop from appendfile.c,
   166 +since our approach is quite simplified */
   187 +since our approach is quite simplified */
   167 +lockfd = Uopen(lockname, O_CREAT|O_RDWR, ob->mode ? ob->mode : 0600);
   188 +lockfd = Uopen(lockname, O_CREAT|O_RDWR, ob->mode ? ob->mode : 0600);
   168 +if (lockfd < 0)
   189 +if (lockfd < 0)
   169 +  {
       
   170 +    if (errno != ENOENT)
       
   171 +	  {
   190 +	  {
   172 +	  *excuse = string_sprintf("open %s", lockname);
   191 +	  *excuse = string_sprintf("open %s", lockname);
   173 +	  return -1;
   192 +	  return -1;
   174 +	  }
   193 +	  }
   175 +
   194 +
   176 +	lockfd = Uopen(hitchname, O_WRONLY|O_CREAT|O_EXCL, ob->mode ? ob->mode : 0600);
       
   177 +	if (lockfd < 0) 
       
   178 +	  {
       
   179 +		*excuse = string_sprintf("open %s", hitchname);
       
   180 +		return -1;
       
   181 +	  }
       
   182 +	if (link(hitchname, lockname) < 0)
       
   183 +	  {
       
   184 +	  int save_errno = errno;
       
   185 +	  (void)unlink(hitchname);
       
   186 +	  errno = save_errno;
       
   187 +	  if (errno != EEXIST) 
       
   188 +		{
       
   189 +		  *excuse = string_sprintf("link %s -> %s", hitchname, lockname);
       
   190 +		  return -1;
       
   191 +		}
       
   192 +	  (void)close(lockfd);
       
   193 +	  lockfd = Uopen(lockname, O_WRONLY, ob->mode ? ob->mode : 0600);
       
   194 +	  if (lockfd < 0) 
       
   195 +		{
       
   196 +		*excuse = string_sprintf("open %s", lockname);
       
   197 +		return -1;
       
   198 +		}
       
   199 +	  }
       
   200 +	(void)unlink(hitchname);
       
   201 +  }
       
   202 +	
       
   203 +
       
   204 +/* Before doing anything here we try to open and lock the maildirsize.lock
   195 +/* Before doing anything here we try to open and lock the maildirsize.lock
   205 +file. This should prevent/avoid races and parallel recalculations. We
   196 +file. This should prevent/avoid races and parallel recalculations. We
   206 +need to do this on an extra lockfile, since the maildirsize file itself
   197 +need to do this on an extra lockfile, since the maildirsize file itself
   207 +gets renamed during the recalculation. */
   198 +gets renamed during the recalculation. */
   208 +
   199 +
   209 +if (lockfd >= 0)
   200 +hs12_lock(lockfd, F_WRLCK, "checking");
   210 +(void)apply_lock(lockfd, F_WRLCK, 1, 120, 0, 0);	// hs12
       
   211 +if (sigalrm_seen) 
   201 +if (sigalrm_seen) 
   212 +  {
   202 +  {
   213 +  *excuse = string_sprintf("timeout locking %s", lockname);
   203 +  *excuse = string_sprintf("timeout locking %s", lockname);
   214 +  return -1;
   204 +  return -1;
   215 +  }
   205 +  }
   216 +DEBUG(D_transport) debug_printf("locked (WR) %s\n", lockname);
   206 +
   217 +
   207  
   218  /* Try a few times to open or create the file, in case another process is doing
       
   219  the same thing. */
       
   220  
       
   221 -filename = string_sprintf("%s/maildirsize", path);
       
   222 -
       
   223  DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path);
   208  DEBUG(D_transport) debug_printf("looking for maildirsize in %s\n", path);
   224  fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600);
   209  fd = Uopen(filename, O_RDWR|O_APPEND, ob->mode ? ob->mode : 0600);
   225 -if (fd < 0)
   210 -if (fd < 0)
   226 -  {
   211 -  {
   227 +if (fd < 0) {
   212 +if (fd < 0) {
   229    DEBUG(D_transport)
   214    DEBUG(D_transport)
   230      debug_printf("%s does not exist: recalculating\n", filename);
   215      debug_printf("%s does not exist: recalculating\n", filename);
   231    goto RECALCULATE;
   216    goto RECALCULATE;
   232 -  }
   217 -  }
   233 +}
   218 +}
       
   219 +(void)lseek(fd, 0, SEEK_SET);
       
   220 +
   234  
   221  
   235  /* The file has been successfully opened. Check that the cached quota value is
   222  /* The file has been successfully opened. Check that the cached quota value is
   236  still correct, and that the size of the file is still small enough. If so,
   223  still correct, and that the size of the file is still small enough. If so,
   237 @@ -588,8 +646,10 @@
   224 @@ -520,16 +546,12 @@
       
   225        }
   238      }
   226      }
   239    }
   227    }
   240  
   228 -
   241 +	DEBUG(D_transport) debug_printf("releasing lock\n");
   229 -
   242 +  (void)apply_lock(lockfd, F_UNLCK, 1, 120, 0, 0);
   230 -/* If *endptr is not zero, there was a syntax error in the file. */
       
   231 -
       
   232 -else
       
   233 +else /* If *endptr is not zero, there was a syntax error in the file. */
       
   234    {
       
   235 +  time_t old_latest, new_latest;
       
   236    int len;
       
   237 -  time_t old_latest, new_latest;
       
   238    uschar *tempname;
       
   239 -  struct timeval tv;
       
   240 +	struct timeval tv;
       
   241  
       
   242    DEBUG(D_transport)
       
   243      {
       
   244 @@ -549,6 +571,13 @@
       
   245  
       
   246    RECALCULATE:
       
   247  
       
   248 +	//hs12_lock(lockfd, F_WRLCK, "recalc");
       
   249 +	if (sigalrm_seen)
       
   250 +		{
       
   251 +			*excuse = "timeout while locking for recalc";
       
   252 +			return -1;
       
   253 +		}
       
   254 +
       
   255    if (fd >= 0) (void)close(fd);
       
   256    old_latest = 0;
       
   257    filecount = 0;
       
   258 @@ -586,10 +615,14 @@
       
   259      (void)close(fd);
       
   260      fd = -2;
       
   261      }
       
   262 +    hs12_lock(lockfd, F_UNLCK, "done recalc");
       
   263    }
       
   264  
       
   265 +   hs12_lock(lockfd, F_UNLCK, "done check");
       
   266 +	
       
   267 +
   243 +
   268 +
   244  /* Return the sizes and the file descriptor, if any */
   269  /* Return the sizes and the file descriptor, if any */
   245 -
   270 -
   246  DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT
   271  DEBUG(D_transport) debug_printf("returning maildir size=" OFF_T_FMT
   247    " filecount=%d\n", size, filecount);
   272    " filecount=%d\n", size, filecount);
   248  *returned_size = size;
   273  *returned_size = size;
   249 diff -r 5037ac63d7ae src/transports/tf_maildir.h
   274 diff -r d54ee7005f7f src/transports/tf_maildir.h
   250 --- a/src/transports/tf_maildir.h	Sat Feb 19 13:42:16 2011 +0100
   275 --- a/src/transports/tf_maildir.h	Mon Feb 21 22:52:42 2011 +0100
   251 +++ b/src/transports/tf_maildir.h	Sun Feb 20 23:37:25 2011 +0100
   276 +++ b/src/transports/tf_maildir.h	Wed Feb 23 00:53:29 2011 +0100
   252 @@ -16,7 +16,7 @@
   277 @@ -16,7 +16,7 @@
   253                  uschar *);
   278                  uschar *);
   254  extern int    maildir_ensure_sizefile(uschar *,
   279  extern int    maildir_ensure_sizefile(uschar *,
   255                  appendfile_transport_options_block *, const pcre *,
   280                  appendfile_transport_options_block *, const pcre *,
   256 -                const pcre *, off_t *, int *);
   281 -                const pcre *, off_t *, int *);