CVS update: /ccvs/src/

[email protected] 30 Apr 2005 03:55:10 -0000
Newsgroups gmane.comp.version-control.cvs.cvs
Message-ID <[email protected]>
User: dprice  
Date: 05/04/29 20:55:10

Modified:
 /ccvs/src/
  ChangeLog, cvs.h, history.c, lock.c, sanity.sh

Log:
 Merge changes from 1.11.x.

File Changes:

Directory: /ccvs/src/
=====================

File [changed]: ChangeLog
Url: https://ccvs.cvshome.org/source/browse/ccvs/src/ChangeLog?r1=1.3179&r2=1.3180
Delta lines:  +21 -1
--------------------
--- ChangeLog	28 Apr 2005 18:06:05 -0000	1.3179
+++ ChangeLog	30 Apr 2005 03:55:07 -0000	1.3180
@@ -1,4 +1,24 @@
-2005-04-27  Derek Price  <[email protected]>
+2005-04-28  Derek Price  <[email protected]>
+
+	* cvs.h (history_lock, clear_history_lock): New protos.
+	* lock.c (struct lock): Add lockdirname.
+	(global_history_lock): New global.
+	(global_read_lock): Initialize.
+	(lock_name): Handle const args.
+	(lock_simple_remove): Factor out code in favor of clear_lock call.
+	(set_lock): Handle variable lockdirname.
+	(lock_filesdoneproc): Set new lockdirname.
+	(history_lock, clear_history_lock): New functions.
+	(clear_lock): Avoid segfault on missing lock.
+	(Lock_Cleanup): Clean up history locks when necessary.
+	* history.c (history_write): Use new lock.
+	* sanity.sh (lockfiles-20): Test new lock.
+
+2005-04-28  Derek Price  <[email protected]>
+
+	* sanity.sh (lockfiles): Port some locking tests over from 1.12.x.
+
+2005-04-28  Derek Price  <[email protected]>
 
 	* lock.c (clear_lock): Improve comment.
 

File [changed]: cvs.h
Url: https://ccvs.cvshome.org/source/browse/ccvs/src/cvs.h?r1=1.331&r2=1.332
Delta lines:  +5 -0
-------------------
--- cvs.h	16 Mar 2005 15:52:14 -0000	1.331
+++ cvs.h	30 Apr 2005 03:55:07 -0000	1.332
@@ -193,6 +193,7 @@
 #define	CVSATTIC	"Attic"
 
 #define	CVSLCK		"#cvs.lock"
+#define	CVSHISTLCK	"#cvs.history.lock"
 #define	CVSRFL		"#cvs.rfl"
 #define	CVSPFL		"#cvs.pfl"
 #define	CVSWFL		"#cvs.wfl"
@@ -556,6 +557,10 @@
 /* See lock.c for description.  */
 void lock_dir_for_write (const char *);
 
+/* Get a write lock for the history file.  */
+int history_lock (const char *);
+void clear_history_lock (void);
+
 void Scratch_Entry (List * list, const char *fname);
 void ParseTag (char **tagp, char **datep, int *nonbranchp);
 void WriteTag (const char *dir, const char *tag, const char *date,

File [changed]: history.c
Url: https://ccvs.cvshome.org/source/browse/ccvs/src/history.c?r1=1.89&r2=1.90
Delta lines:  +6 -0
-------------------
--- history.c	16 Mar 2005 22:00:49 -0000	1.89
+++ history.c	30 Apr 2005 03:55:07 -0000	1.90
@@ -735,6 +735,11 @@
 
     if (noexec)
 	goto out;
+
+    if (!history_lock (current_parsed_root->directory))
+	/* history_lock() will already have printed an error on failure.  */
+	goto out;
+
     fd = CVS_OPEN (fname, O_WRONLY | O_APPEND | OPEN_BINARY, 0666);
     if (fd < 0)
     {
@@ -875,6 +880,7 @@
 	error (1, errno, "cannot close history file: %s", fname);
     free (workdir);
  out:
+    clear_history_lock ();
     free (fname);
 }
 

File [changed]: lock.c
Url: https://ccvs.cvshome.org/source/browse/ccvs/src/lock.c?r1=1.112&r2=1.113
Delta lines:  +83 -33
---------------------
--- lock.c	28 Apr 2005 18:06:05 -0000	1.112
+++ lock.c	30 Apr 2005 03:55:07 -0000	1.113
@@ -88,13 +88,20 @@
     char *file2;
 #endif /* LOCK_COMPATIBILITY */
 
-    /* The lock dir (usually CVSLCK), if we are currently holding it.  */
+    /* The name of the master lock dir.  Usually CVSLCK.  */
+    const char *lockdirname;
+
+    /* The full path to the lock dir, if we are currently holding it.
+     *
+     * This will be LOCKDIRNAME catted onto REPOSITORY.  We waste a little
+     * space by storing it, but save a later malloc/free.
+     */
     char *lockdir;
 
     /* Note there is no way of knowing whether the readlock and writelock
        exist.  The code which sets the locks doesn't use SIG_beginCrSect
        to set a flag like we do for CVSLCK.  */
-    int free_repository;
+    bool free_repository;
 };
 
 static void remove_locks (void);
@@ -122,8 +129,11 @@
 
 /* This is the (single) readlock which is set by Reader_Lock.  The
    repository field is NULL if there is no such lock.  */
-static struct lock global_readlock;
-static struct lock global_writelock;
+static struct lock global_readlock = {NULL, NULL, NULL, CVSLCK, NULL, false};
+static struct lock global_writelock = {NULL, NULL, NULL, CVSLCK, NULL, false};
+
+static struct lock global_history_lock = {NULL, NULL, NULL, CVSHISTLCK,
+					  NULL, false};
 
 /* List of locks set by lock_tree_for_write.  This is redundant
    with locklist, sort of.  */
@@ -279,11 +289,11 @@
  *
  * INPUTS
  *   lock	The lock to remove.
- *   free	True if this lock directory will not5 be reused (free
+ *   free	True if this lock directory will not be reused (free
  *		lock->repository if necessary).
  */
 static void
-remove_lock_files (struct lock *lock, int free_repository)
+remove_lock_files (struct lock *lock, bool free_repository)
 {
     TRACE (TRACE_FLOW, "remove_lock_files (%s)", lock->repository);
 
@@ -311,15 +321,7 @@
     }
 #endif /* LOCK_COMPATIBILITY */
 
-    if (lock->lockdir)
-    {
-	SIG_beginCrSect ();
-	if (CVS_RMDIR (lock->lockdir) < 0)
-	    error (0, errno, "failed to remove lock dir %s", lock->lockdir);
-	free (lock->lockdir);
-	lock->lockdir = NULL;
-	SIG_endCrSect ();
-    }
+    clear_lock (lock);
 
     /* And free the repository string.  We don't really have to set the
      * repository string to NULL first since there is no harm in running any of
@@ -334,7 +336,7 @@
 	if (lock->free_repository)
 	{
 	    free ((char *)lock->repository);
-	    lock->free_repository = 0;
+	    lock->free_repository = false;
 	}
 	lock->repository = NULL;
 	SIG_endCrSect ();
@@ -358,7 +360,7 @@
 
     /* clean up simple read locks (if any) */
     if (global_readlock.repository != NULL)
-	remove_lock_files (&global_readlock, 1);
+	remove_lock_files (&global_readlock, true);
     /* See note in Lock_Cleanup() below.  */
     SIG_endCrSect();
 
@@ -366,7 +368,15 @@
 
     /* clean up simple write locks (if any) */
     if (global_writelock.repository != NULL)
-	remove_lock_files (&global_writelock, 1);
+	remove_lock_files (&global_writelock, true);
+    /* See note in Lock_Cleanup() below.  */
+    SIG_endCrSect();
+
+    SIG_beginCrSect();
+
+    /* clean up simple write locks (if any) */
+    if (global_history_lock.repository)
+	remove_lock_files (&global_history_lock, true);
     /* See note in Lock_Cleanup() below.  */
     SIG_endCrSect();
 }
@@ -423,7 +433,7 @@
 static int
 unlock_proc (Node *p, void *closure)
 {
-    remove_lock_files (p->data, 0);
+    remove_lock_files (p->data, false);
     return 0;
 }
 
@@ -500,7 +510,7 @@
 
     /* remember what we're locking (for Lock_Cleanup) */
     global_readlock.repository = xstrdup (xrepository);
-    global_readlock.free_repository = 1;
+    global_readlock.free_repository = true;
 
     /* get the lock dir for our own */
     if (set_lock (&global_readlock, 1) != L_OK)
@@ -768,7 +778,7 @@
 
 	    /* Remove the promotable lock.  */
 	    lock->file2 = NULL;
-	    remove_lock_files (lock, 0);
+	    remove_lock_files (lock, false);
 
 	    /* return the error */
 	    error (0, xerrno,
@@ -994,7 +1004,7 @@
     TRACE (TRACE_FLOW, "set_lock (%s, %d)",
 	   lock->repository ? lock->repository : "(null)", will_wait);
 
-    masterlock = lock_name (lock->repository, CVSLCK);
+    masterlock = lock_name (lock->repository, lock->lockdirname);
 
     /*
      * Note that it is up to the callers of set_lock() to arrange for signal
@@ -1105,19 +1115,20 @@
  *   freeing the storage.
  *
  * ASSUMPTIONS
- *   We own the master lock directory.
- *   Its name is stored in LOCK->lockdir.
+ *   If we own the master lock directory, its name is stored in LOCK->lockdir.
  *   We may free LOCK->lockdir.
- *
  */
 static void
 clear_lock (struct lock *lock)
 {
     SIG_beginCrSect ();
+    if (lock->lockdir)
+    {
     if (CVS_RMDIR (lock->lockdir) < 0)
 	error (0, errno, "failed to remove lock dir `%s'", lock->lockdir);
     free (lock->lockdir);
     lock->lockdir = NULL;
+    }
     SIG_endCrSect ();
 }
 
@@ -1142,8 +1153,9 @@
 #ifdef LOCK_COMPATIBILITY
     ((struct lock *)p->data)->file2 = NULL;
 #endif /* LOCK_COMPATIBILITY */
+    ((struct lock *)p->data)->lockdirname = CVSLCK;
     ((struct lock *)p->data)->lockdir = NULL;
-    ((struct lock *)p->data)->free_repository = 0;
+    ((struct lock *)p->data)->free_repository = false;
 
     /* FIXME-KRP: this error condition should not simply be passed by. */
     if (p->key == NULL || addnode (lock_tree_list, p) != 0)
@@ -1206,10 +1218,10 @@
 	}
 
 	if (global_writelock.repository != NULL)
-	    remove_lock_files (&global_writelock, 1);
+	    remove_lock_files (&global_writelock, true);
 
 	global_writelock.repository = xstrdup (repository);
-	global_writelock.free_repository = 1;
+	global_writelock.free_repository = true;
 
 	for (;;)
 	{
@@ -1262,7 +1274,7 @@
 		Node *p = findnode (locklist, repository);
 		if (p)
 		{
-		    remove_lock_files (p->data, 1);
+		    remove_lock_files (p->data, true);
 		    delnode (p);
 		}
 	    }
@@ -1271,3 +1283,41 @@
 	}
     }
 }
+
+
+
+/* Get a write lock for the history file.  Return true on success and false on
+ * error.
+ */
+int
+history_lock (xrepository)
+    const char *xrepository;
+{
+    /* remember what we're locking (for Lock_Cleanup) */
+    assert (!global_history_lock.repository);
+    global_history_lock.repository = Xasprintf ("%s/%s", xrepository,
+						CVSROOTADM);
+    global_history_lock.free_repository = true;
+
+    /* get the lock dir for our own */
+    if (set_lock (&global_history_lock, 1) != L_OK)
+    {
+	if (!really_quiet)
+	    error (0, 0, "failed to obtain history lock in repository `%s'",
+		   xrepository);
+
+	return 0;
+    }
+
+    return 1;
+}
+
+
+
+/* Remove the history lock, if it exists.
+ */
+void
+clear_history_lock ()
+{
+    remove_lock_files (&global_history_lock, true);
+}

File [changed]: sanity.sh
Url: https://ccvs.cvshome.org/source/browse/ccvs/src/sanity.sh?r1=1.1058&r2=1.1059
Delta lines:  +10 -0
--------------------
--- sanity.sh	22 Apr 2005 11:59:00 -0000	1.1058
+++ sanity.sh	30 Apr 2005 03:55:07 -0000	1.1059
@@ -22549,6 +22549,16 @@
 $CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v  <--  first-dir/sdir/ssdir/file1
 new revision: 1\.4; previous revision: 1\.3"
 
+	  # 10. Don't write when history locks are present...
+	  echo have you ever heard a poem quite so vile\? >>first-dir/sdir/ssdir/file1
+	  mkdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock"
+	  (sleep 5; rmdir "$TESTDIR/locks/CVSROOT/#cvs.history.lock")&
+	  dotest lockfiles-20 "$testcvs -q ci -mnot-up-to-date first-dir" \
+"$CVSROOT_DIRNAME/first-dir/sdir/ssdir/file1,v  <--  first-dir/sdir/ssdir/file1
+new revision: 1\.5; previous revision: 1\.4
+$SPROG commit: \[[0-9:]*\] waiting for $username's lock in $CVSROOT_DIRNAME/CVSROOT
+$SPROG commit: \[[0-9:]*\] obtained lock in $CVSROOT_DIRNAME/CVSROOT"
+
 	  cd CVSROOT
 	  dotest lockfiles-cleanup-1 "$testcvs -q up -pr1.1 config >config" ""
 	  dotest lockfiles-cleanup-2 "$testcvs -q ci -m config-it" \