nmh-workers
[Top] [All Lists]

Re: current work on nmh

1998-06-17 08:36:29

Stephen McKay writes:
However, I am still looking more towards reliability than features at this
time.  I have large mail boxes (10000 or more messages) and frequently
allow my unseen sequence to grow very large as I (ab)use it as a simple
"look at this again" list.

Ever since I switched from plain 'inc' to a complex procmail and rcvstore
mail delivery mechanism, I have been plagued with disappearing sequences.

I've had troubles, too, but they mostly seem to be related to the size 
of sequences. Lots of the mh programs still have hard coded limits on
how large a set of arguments they will take on the command line, how
long a sequence can be, etc.

I have traced this to optimistic handling of context and .mh_sequences
files in nmh.  In particular, each .mh_sequences file is truncated before
the new sequences are written to it, and if another nmh command starts in
that small gap it will read an empty set of sequences.  When this second
nmh command completes, it will write its version of .mh_sequences, losing
data.

Absolutely perfect sequence manipulation would require complex interlocks,
but I have achieved very good results with the simple method of creating
a temporary file and linking it into place.

Appended is a patch for your consideration.  I have been using this patch
for several weeks now and have noticed nothing unusual except that my
sequences no longer disappear.  The patch is relative to nmh 0.26:

*** OLD/context_save.c        Mon Jan  5 04:15:54 1998
--- context_save.c    Fri May 29 14:33:25 1998
***************
*** 19,24 ****
--- 19,25 ----
  {
      int action;
      register struct node *np;
+     char *tmppath;
      FILE *out;
      sigset_t set, oset;
  
***************
*** 37,48 ****
      sigaddset (&set, SIGTERM);
      SIGPROCMASK (SIG_BLOCK, &set, &oset);
  
!     if (!(out = fopen (ctxpath, "w")))
!     adios (ctxpath, "unable to write");
      for (np = m_defs; np; np = np->n_next)
      if (np->n_context)
          fprintf (out, "%s: %s\n", np->n_name, np->n_field);
      fclose (out);
  
      SIGPROCMASK (SIG_SETMASK, &oset, &set); /* reset the signal mask */
  
--- 38,64 ----
      sigaddset (&set, SIGTERM);
      SIGPROCMASK (SIG_BLOCK, &set, &oset);
  
!     if ((tmppath = malloc (strlen (ctxpath) + 10)) == NULL)
!     adios (NULL, "unable to allocate string storage in context_save");
!     sprintf (tmppath, "%s.%d", ctxpath, getpid());
! 
!     if (!(out = fopen (tmppath, "w")))
!     adios (tmppath, "unable to write");
      for (np = m_defs; np; np = np->n_next)
      if (np->n_context)
          fprintf (out, "%s: %s\n", np->n_name, np->n_field);
+     fflush (out);
+     if (ferror (out)) {
+     unlink (tmppath);
+     adios (tmppath, "write error");
+     }
      fclose (out);
+ 
+     if (rename (tmppath, ctxpath)) {
+     unlink (tmppath);
+     adios (ctxpath, "cannot rename");
+     }
+     free (tmppath);
  
      SIGPROCMASK (SIG_SETMASK, &oset, &set); /* reset the signal mask */
  
*** OLD/seq_save.c    Mon Jan  5 04:22:50 1998
--- seq_save.c        Fri May 29 14:33:24 1998
***************
*** 24,29 ****
--- 24,30 ----
  {
      int i;
      char flags, *cp, attr[BUFSIZ], seqfile[PATH_MAX];
+     char *tmpfile;
      FILE *fp;
      sigset_t set, oset;
  
***************
*** 73,81 ****
               * If that fails (probably because folder is
               * readonly), then make sequence private.
               */
!             if ((fp = fopen (seqfile, "w")) == NULL
!                     && (unlink (seqfile) == -1 ||
!                         (fp = fopen (seqfile, "w")) == NULL)) {
                  admonish (attr, "unable to write");
                  goto priv;
              }
--- 74,86 ----
               * If that fails (probably because folder is
               * readonly), then make sequence private.
               */
!             if ((tmpfile = malloc (strlen (seqfile) + 10)) == NULL)
!                 adios (NULL, "unable to allocate string storage");
!             sprintf (tmpfile, "%s.%d", seqfile, getpid());
! 
!             if ((fp = fopen (tmpfile, "w")) == NULL
!                     && (unlink (tmpfile) == -1 ||
!                         (fp = fopen (tmpfile, "w")) == NULL)) {
                  admonish (attr, "unable to write");
                  goto priv;
              }
***************
*** 93,99 ****
--- 98,114 ----
      }
  
      if (fp) {
+     fflush (fp);
+     if (ferror (fp)) {
+         unlink (tmpfile);
+         adios (tmpfile, "write error");
+     }
      fclose (fp);
+     if (rename (tmpfile, seqfile)) {
+         unlink (tmpfile);
+         adios (seqfile, "cannot rename");
+     }
+     free (tmpfile);
      SIGPROCMASK (SIG_SETMASK, &oset, &set);  /* reset signal mask */
      } else {
      /*

The End.



<Prev in Thread] Current Thread [Next in Thread>