--- cvs-1.11.22/src/rcs.c	2006-06-08 15:55:04.000000000 +0200
+++ cvs-1.11.22-fsync/src/rcs.c	2007-04-28 16:42:54.000000000 +0200
@@ -31,6 +31,7 @@
 #endif
 
 int preserve_perms = 0;
+int disable_fsync = 0;
 
 /* The RCS -k options, and a set of enums that must match the array.
    These come first so that we can use enum kflag in function
@@ -94,7 +95,8 @@
 static void rcsbuf_cache_close PROTO ((void));
 static void rcsbuf_cache_open PROTO ((RCSNode *, long, FILE **,
 				      struct rcsbuffer *));
-static int checkmagic_proc PROTO((Node *p, void *closure));
+/*static int checkmagic_proc PROTO((Node *p, void *closure));*/
+static int checkmagic_proc PROTO((Node *p));
 static void do_branches PROTO((List * list, char *val));
 static void do_symbols PROTO((List * list, char *val));
 static void do_locks PROTO((List * list, char *val));
@@ -2532,6 +2534,32 @@
  *
  * Note: We assume that REV is an RCS revision and not a branch number.
  */
+
+/* ---------------- ajw ---------------------
+
+The version of this as distributed is highly inefficient if there
+are many branch symbols. Something like 98% of the time in long
+tag -b operations is spent here, and in the checkmagic_proc (strcmp)
+that it calls.
+
+It has an n**2 scan, from rev 2 onwards, comparing all symbols
+against magic rev 2, then all symbols against magic rev 4 and
+so on. Because they use their list walking proc which applies the
+given proc to *every* element of the list, they compare against
+all symbols in each case, even if they should fail on the first.
+
+We have two enhancements here which give us substantial performance
+improvement.
+
+(1) Inline the 'walklist' call, and the strcomp proc. This
+    is quicker anyway, but gives us the control to terminate early.
+
+(2) We do an initial scan at 500 revision intervals for the highest
+    numbered n*500 rev that is already allocated, and start from there,
+    rather than 2.
+
+   ------------ end ajw ---------------------*/
+
 static char *check_rev;
 char *
 RCS_magicrev (rcs, rev)
@@ -2539,15 +2567,59 @@
     char *rev;
 {
     int rev_num;
-    char *xrev, *test_branch;
-
+    char *xrev, *test_branch,*s,*t;
+    Node *head, *p;
+    int found = 0;
+    int initial;
+    int start_pt;
+    int valid_start;
+
+    valid_start = 0;
+    disable_fsync = 1; 
+    
+    /* ------------ find a good rev number to start from ------------*/
+    
     xrev = xmalloc (strlen (rev) + 14); /* enough for .0.number */
     check_rev = xrev;
 
+    /* if 500, 1000, 1500, exist, start there.*/
+    for (start_pt=5000;!valid_start && start_pt>0;start_pt-=500)
+    {
+      /* already exists as a real branch?*/
+      (void) sprintf(xrev,"%s.%d",rev, rev_num);
+      test_branch = RCS_getbranch(rcs,xrev,1);
+      if(test_branch != NULL)
+      {
+	free(test_branch);
+	valid_start=start_pt;
+	break;
+      }
+
+      /* already exists as a magic branch?*/
+      (void) sprintf(xrev,"%s.%d.%d", rev, RCS_MAGIC_BRANCH, start_pt);
+      if(RCS_symbols(rcs)==NULL) continue;
+      head = (RCS_symbols(rcs))->list;
+      found = 0;
+      for(p=head->next; p!=head; p=p->next)
+      {  
+	if(checkmagic_proc(p)){ /* true if match*/
+	  valid_start=start_pt;
+	  break;
+	}
+      }
+    }
+
+    if(! valid_start)
+    {
+      valid_start=2;
+    }    
+    
+    /* -------------- now go from valid start-------------*/
+    
     /* only look at even numbered branches */
-    for (rev_num = 2; ; rev_num += 2)
+    for (rev_num = valid_start; ; rev_num += 2)
     {
-	/* see if the physical branch exists */
+        /* see if the physical branch exists */
 	(void) sprintf (xrev, "%s.%d", rev, rev_num);
 	test_branch = RCS_getbranch (rcs, xrev, 1);
 	if (test_branch != NULL)	/* it did, so keep looking */
@@ -2559,10 +2631,49 @@
 	/* now, create a "magic" revision */
 	(void) sprintf (xrev, "%s.%d.%d", rev, RCS_MAGIC_BRANCH, rev_num);
 
+	/* ---------------------- ajw ----------------------*/
+
+        /* if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0) */
+        /* 	    continue; */
+	/* with an inlining of walklist/checkmagic_proc, and optimise */
+
 	/* walk the symbols list to see if a magic one already exists */
-	if (walklist (RCS_symbols(rcs), checkmagic_proc, NULL) != 0)
-	    continue;
 
+	/* Branches are created by tagging with symbols, so every branch
+	 *will* have a symbol. The hope is that there are fewer symbols
+	 than revision numbers so its quicker than walking the version
+	 numbers. However in Transitive's case this is probably the wrong way
+	 around.
+	 */
+
+	/* no symbols - so our new one is ok */
+	if(RCS_symbols(rcs)==NULL) return(xrev);	
+
+	/* existing symbols - is our candidate one of them? */
+	head = (RCS_symbols(rcs))->list;
+	found = 0;
+	for(p=head->next; p!=head; p=p->next)
+	{  
+	  /* inlined checkmagic_proc (strcmp) */
+	  s=check_rev;
+	  t=p->data;
+          /* stcmp(s,t) : err=>different */
+	  while(*s==*t)
+	  {
+	    if(*s!=*t) break; /*differ*/
+	    if(*s=='\0'){
+	      /* same */
+	      found++;
+	      break;
+	    }
+	    s++;
+	    t++;
+	  }
+	  if(found) break;
+	}
+
+	/* symbol exists , so try next */
+	if (found)continue;
 	/* we found a free magic branch.  Claim it as ours */
 	return (xrev);
     }
@@ -2573,17 +2684,38 @@
  * Returns 0 if the symbol does not match, 1 if it does.
  */
 static int
-checkmagic_proc (p, closure)
+checkmagic_proc (p)
     Node *p;
-    void *closure;
 {
-    if (STREQ (check_rev, p->data))
+  if (STREQ (check_rev, p->data))
 	return (1);
     else
-	return (0);
+	return (0);   
 }
 
 /*
+ * walk a list with a specific proc
+ */
+/* int */
+/* walklist_local (list, proc, closure) */
+/*     List *list; */
+/*     int (*proc) PROTO ((Node *, void *)); */
+/*     void *closure; */
+/* { */
+/*     Node *head, *p; */
+/*     int err = 0; */
+
+/*     if (list == NULL) */
+/* 	return (0); */
+
+/*     head = list->list; */
+/*     for (p = head->next; p != head; p = p->next) */
+/* 	err += proc (p, closure); */
+/*     return (err); */
+/* } */
+
+
+/*
  * Given an RCSNode, returns non-zero if the specified revision number 
  * or symbolic tag resolves to a "branch" within the rcs file.
  *
@@ -5066,7 +5198,7 @@
 #ifdef PRESERVE_PERMISSIONS_SUPPORT
     struct stat sb;
 #endif
-
+    disable_fsync = 0;
     commitpt = NULL;
 
     if (rcs->flags & PARTIAL)
@@ -5866,6 +5998,7 @@
 {
     List *symbols;
     Node *node;
+    disable_fsync = 1;
 
     if (rcs->flags & PARTIAL)
 	RCS_reparsercsfile (rcs, (FILE **) NULL, (struct rcsbuffer *) NULL);
@@ -8654,8 +8787,17 @@
 	error (1, errno, "error flushing file `%s' to kernel buffers",
 	       rcs_lockfile);
 #ifdef HAVE_FSYNC
-    if (fsync (rcs_lockfd) < 0)
-	error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
+    /* Don't fsync when adding a branch, because:
+     * 1) Branching a large codebase is by far the most expensive operation
+     *    and it just needs to be a lot faster.
+     * 2) No actual code is lost if the branch operation gets dropped on
+     *    the floor because of a server crash and the branching operation
+     *    can and will be retried once the cvs server is back up.
+     */
+    if (!disable_fsync) {
+	if (fsync (rcs_lockfd) < 0)
+	    error (1, errno, "error fsyncing file `%s'", rcs_lockfile);
+    }
 #endif
 
     if (fclose (fp) == EOF)
