ec4aa63c0938b8166f55a9cab045e12827685742
kent
  Tue Jul 19 13:50:10 2011 -0700
Optimizing parentChildCartCleanup by creating a faster version of cartVarsWithPrefix that works in local memory.
diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index 15080fe..d875ee8 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -846,30 +846,56 @@
 struct slPair *cartVarsWithPrefix(struct cart *cart, char *prefix)
 /* Return a slPair list of cart vars that begin with prefix */
 {
 struct slPair *cartVars = NULL;
 struct hashEl *el, *elList = hashElListHash(cart->hash);
 slSort(&elList, hashElCmp);
 for (el = elList; el != NULL; el = el->next)
     {
     if (startsWith(prefix, el->name))
         slAddHead(&cartVars,slPairNew(el->name,el->val));
     }
 hashElFreeList(&elList);
 return cartVars;
 }
 
+struct slPair *cartVarsWithPrefixLm(struct cart *cart, char *prefix, struct lm *lm)
+/* Return list of cart vars that begin with prefix allocated in local memory. 
+ * Quite a lot faster than cartVarsWithPrefix. */
+{
+struct slPair *cartVars = NULL;
+struct hash *hash = cart->hash;
+int hashSize = hash->size;
+struct hashEl *hel;
+int i;
+for (i=0; i<hashSize; ++i)
+    {
+    for (hel = hash->table[i]; hel != NULL; hel = hel->next)
+        {
+	if (startsWith(prefix, hel->name))
+	    {
+	    struct slPair *pair;
+	    lmAllocVar(lm, pair);
+	    pair->name = lmCloneString(lm, hel->name);
+	    pair->val = lmCloneString(lm, hel->val);
+	    slAddHead(&cartVars, pair);
+	    }
+	}
+    }
+return cartVars;
+}
+
 void cartRemoveLike(struct cart *cart, char *wildCard)
 /* Remove all variable from cart that match wildCard. */
 {
 struct slPair *cartVars = cartVarsLike(cart,wildCard);
 while(cartVars != NULL)
     {
     struct slPair *cartVar = slPopHead(&cartVars);
     cartRemove(cart, cartVar->name);
     freeMem(cartVar);
     }
 }
 
 void cartRemovePrefix(struct cart *cart, char *prefix)
 /* Remove variables with given prefix from cart. */
 {
@@ -1941,47 +1967,46 @@
     return (!ignoreRemoved);
 
 #ifdef CART_DIFFS_INCLUDE_EMPTIES
 if (sameString(oldValue,CART_VAR_EMPTY))
     {
     if (sameString(newValue,"hide")
     ||  sameString(newValue,"off")
     ||  sameString(newValue,"0"))   // Special cases DANGER!
         return FALSE;
     }
 #endif///def CART_DIFFS_INCLUDE_EMPTIES
 
 return (differentString(newValue,oldValue));
 }
 
-int cartNamesPruneChanged(struct cart *newCart,struct hash *oldVars,
+static int cartNamesPruneChanged(struct cart *newCart,struct hash *oldVars,
                           struct slPair **cartNames,boolean ignoreRemoved,boolean unChanged)
 /* Prunes a list of cartNames if the settings have changed between new and old cart.
    Returns pruned count */
 {
 int pruned = 0;
 struct slPair *oldList = *cartNames;
 struct slPair *newList = NULL;
 struct slPair *oneName = NULL;
 while ((oneName = slPopHead(&oldList)) != NULL)
     {
     boolean thisOneChanged = cartValueHasChanged(newCart,oldVars,oneName->name,ignoreRemoved,TRUE);
     if (unChanged != thisOneChanged)
         slAddHead(&newList,oneName);
     else
         {
-        freeMem(oneName);
         pruned++;
         }
     }
 *cartNames = newList;
 return pruned;
 }
 
 
 int cartRemoveFromTdbTree(struct cart *cart,struct trackDb *tdb,char *suffix,boolean skipParent)
 /* Removes a 'trackName.suffix' from all tdb descendents (but not parent).
    If suffix NULL then removes 'trackName' which holds visibility */
 {
 int removed = 0;
 boolean vis = (suffix == NULL || *suffix == '\0');
 struct slRef *tdbRef, *tdbRefList = trackDbListGetRefsToDescendants(skipParent?tdb->subtracks:tdb);
@@ -2257,31 +2282,31 @@
         }
     }
 else // If no views then composite is not set to fuul but to max of subtracks
     count = cartTdbParentShapeVis(cart,tdbContainer,NULL,subVisHash,reshapeFully);
 
 hashFree(&subVisHash);
 
 // If reshaped, be sure to set flag to stop composite cleanup
 #define RESHAPED_COMPOSITE "reshaped"
 if (count > 0)
     tdbExtrasAddOrUpdate(tdbContainer,RESHAPED_COMPOSITE,(void *)(long)TRUE); // Exists for the life of the cgi only
 
 return TRUE;
 }
 
-boolean cartTdbTreeCleanupOverrides(struct trackDb *tdb,struct cart *newCart,struct hash *oldVars)
+boolean cartTdbTreeCleanupOverrides(struct trackDb *tdb,struct cart *newCart,struct hash *oldVars, struct lm *lm)
 /* When container or composite/view settings changes, remove subtrack specific settings
    Returns TRUE if any cart vars are removed */
 {
 boolean anythingChanged = cartTdbOverrideSuperTracks(newCart,tdb,TRUE);
 if (!tdbIsContainer(tdb))
     return anythingChanged;
 
 // If composite has been reshaped then don't clean it up
 if ((boolean)(long)tdbExtrasGetOrDefault(tdb,RESHAPED_COMPOSITE,(void *)(long)FALSE))
     return anythingChanged;
 
 // vis is a special additive case! composite or view level changes then remove subtrack vis
 boolean containerVisChanged = cartValueHasChanged(newCart,oldVars,tdb->track,TRUE,FALSE);
 if (containerVisChanged)
     {
@@ -2289,39 +2314,39 @@
     char *cartVis = cartOptionalString(newCart,tdb->track);
     char *oldValue = hashFindVal(oldVars,tdb->track);
     if (cartVis && oldValue == NULL && hTvFromString(cartVis) == tdb->visibility)
         containerVisChanged = FALSE;
     }
 struct trackDb *tdbView = NULL;
 struct slPair *oneName = NULL;
 char *suffix = NULL;
 int clensed = 0;
 
 // Build list of current settings for container or composite and views
 char setting[512];
 safef(setting,sizeof(setting),"%s.",tdb->track);
 char * view = NULL;
 boolean hasViews = FALSE;
-struct slPair *changedSettings = cartVarsWithPrefix(newCart, setting);
+struct slPair *changedSettings = cartVarsWithPrefixLm(newCart, setting, lm);
 for (tdbView = tdb->subtracks;tdbView != NULL; tdbView = tdbView->next)
     {
     if (!tdbIsView(tdbView,&view))
         break;
     hasViews = TRUE;
     safef(setting,sizeof(setting),"%s.",tdbView->track);          // unfortunatly setting name could be viewTrackName.???
     //safef(setting,   sizeof(setting),"%s.%s.",tdb->track,view); // or containerName.Sig.???   HOWEVER: this are picked up by containerName prefix
-    struct slPair *changeViewSettings = cartVarsWithPrefix(newCart, setting);
+    struct slPair *changeViewSettings = cartVarsWithPrefixLm(newCart, setting, lm);
     changedSettings = slCat(changedSettings, changeViewSettings);
     }
 if (changedSettings == NULL && !containerVisChanged)
     return anythingChanged;
 
 // Prune list to only those which have changed
 if(changedSettings != NULL)
     {
     (void)cartNamesPruneChanged(newCart,oldVars,&changedSettings,TRUE,FALSE);
     if (changedSettings == NULL && !containerVisChanged)
         return anythingChanged;
     }
 
 // Walk through views
 if (hasViews)
@@ -2344,59 +2369,57 @@
             else if(startsWith(settingAlt,oneName->name))
                 suffix = oneName->name + strlen(settingAlt);
             else
                 {
                 slAddHead(&leftOvers,oneName);
                 continue;
                 }
 
             if (sameString(suffix,"vis"))
                 {
                 viewVisChanged = TRUE;
                 }
             else if (cartRemoveOldFromTdbTree(newCart,oldVars,tdbView,suffix,oneName->val,TRUE) > 0)
                     clensed++;
 
-            freeMem(oneName);
             }
         if (viewVisChanged)
             {
             // If just created and if vis is the same as tdb default then vis has not changed
             safef(setting,sizeof(setting),"%s.%s.vis",tdb->track,view);
             char *cartVis = cartOptionalString(newCart,setting);
             char *oldValue = hashFindVal(oldVars,setting);
             if (cartVis && oldValue == NULL && hTvFromString(cartVis) != tdbView->visibility)
                 viewVisChanged = FALSE;
             }
 
         if  (containerVisChanged || viewVisChanged)
             { // vis is a special additive case!
             WARN("Removing subtrack vis for %s.%s",tdb->track,view);
             char *viewVis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdbView, FALSE));
             if (cartRemoveOldFromTdbTree(newCart,oldVars,tdbView,NULL,viewVis,TRUE) > 0)
                 clensed++;
             }
         changedSettings = leftOvers;
         }
     }
 
 // Now deal with anything remaining at the container level
 while ((oneName = slPopHead(&changedSettings)) != NULL)
     {
     suffix = oneName->name + strlen(tdb->track) + 1;
     if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,suffix,oneName->val,TRUE) > 0)
         clensed++;
-    freeMem(oneName);
     }
 if  (containerVisChanged && !hasViews)
     { // vis is a special additive case!
     char *vis = hStringFromTv(tdbVisLimitedByAncestry(newCart, tdb, FALSE));
     if (cartRemoveOldFromTdbTree(newCart,oldVars,tdb,NULL,vis,TRUE) > 0)
         clensed++;
     }
 
 anythingChanged = (anythingChanged || (clensed > 0));
 return anythingChanged;
 }