c9b40ed334908a1b791191a3df227ae991b4810e
braney
  Fri Mar 22 18:07:12 2013 -0700
fold back in the changes Angie made in the commit before my last commit.  Change cartCopyCustomTracks() to not take a database argument since it's interation over all the "ctfile_*" in the cart anyway.All of this is to fix the problem that now loading a cart and connecting to hubs is what should be an atomic act.   As it was, there were some hdb routines called after a new cart was loaded, but before the referenced hubs were loaded.
As it is now, hgSession will load new carts without reloading the associated hubs.  This would only be a problem with assembly hubs, and I don't think it matters since hgSession isn't displaying hub data anyway.

diff --git src/hg/lib/cart.c src/hg/lib/cart.c
index c3649ca..d910905 100644
--- src/hg/lib/cart.c
+++ src/hg/lib/cart.c
@@ -228,40 +228,41 @@
 struct dyString *dy = dyStringNew(1024);
 int useCount;
 dyStringPrintf(dy, "SELECT useCount FROM %s "
 	       "WHERE userName = '%s' AND sessionName = '%s';",
 	       namedSessionTable, encUserName, encSessionName);
 useCount = sqlQuickNum(conn, dy->string) + 1;
 dyStringClear(dy);
 dyStringPrintf(dy, "UPDATE %s SET useCount = %d, lastUse=now() "
 	       "WHERE userName = '%s' AND sessionName = '%s';",
 	       namedSessionTable, useCount, encUserName, encSessionName);
 sqlUpdate(conn, dy->string);
 dyStringFree(&dy);
 }
 
 #ifndef GBROWSE
-void cartCopyCustomTracks(struct cart *cart, char *db)
+void cartCopyCustomTracks(struct cart *cart)
 /* If cart contains any live custom tracks, save off a new copy of them,
  * to prevent clashes by multiple uses of the same session.  */
 {
 struct hashEl *el, *elList = hashElListHash(cart->hash);
 
 for (el = elList; el != NULL; el = el->next)
     {
     if (startsWith(CT_FILE_VAR_PREFIX, el->name))
 	{
+	char *db = &el->name[strlen(CT_FILE_VAR_PREFIX)];
 	struct slName *browserLines = NULL;
 	struct customTrack *ctList = NULL;
 	char *ctFileName = (char *)(el->val);
 	if (fileExists(ctFileName))
 	    ctList = customFactoryParseAnyDb(db, ctFileName, TRUE, &browserLines);
         /* Save off only if the custom tracks are live -- if none are live,
          * leave cart variables in place so hgSession can detect and inform
          * the user. */
 	if (ctList)
 	    {
 	    struct customTrack *ct;
 	    static struct tempName tn;
 	    char *ctFileVar = el->name;
 	    char *ctFileName;
 	    for (ct = ctList;  ct != NULL;  ct = ct->next)
@@ -404,91 +405,89 @@
     hashRemove(hash, hel->name);
     }
 hashElFreeList(&helList);
 assert(hashNumEntries(hash) == 0);
 }
 
 INLINE char *getDb(struct cart *cart, struct hash *oldVars)
 /* Quick wrapper around getDbGenomeClade for when we only want db. */
 {
 char *db=NULL, *ignoreOrg, *ignoreClade;
 getDbGenomeClade(cart, &db, &ignoreOrg, &ignoreClade, oldVars);
 return db;
 }
 
 #ifndef GBROWSE
-boolean cartLoadUserSession(struct sqlConnection *conn, char *sessionOwner,
+void cartLoadUserSession(struct sqlConnection *conn, char *sessionOwner,
 			 char *sessionName, struct cart *cart,
 			 struct hash *oldVars, char *actionVar)
 /* If permitted, load the contents of the given user's session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. */
-/* Return TRUE if a session was loaded. */
 {
 struct sqlResult *sr = NULL;
 char **row = NULL;
 char *userName = wikiLinkUserName();
 char *encSessionName = cgiEncodeFull(sessionName);
 char *encSessionOwner = cgiEncodeFull(sessionOwner);
 char query[512];
-boolean loadedSession = FALSE;
 
 if (isEmpty(sessionOwner))
     errAbort("Please go back and enter a wiki user name for this session.");
 if (isEmpty(sessionName))
     errAbort("Please go back and enter a session name to load.");
 
 safef(query, sizeof(query), "SELECT shared, contents FROM %s "
       "WHERE userName = '%s' AND sessionName = '%s';",
       namedSessionTable, encSessionOwner, encSessionName);
 sr = sqlGetResult(conn, query);
 if ((row = sqlNextRow(sr)) != NULL)
     {
     boolean shared = atoi(row[0]);
     if (shared ||
 	(userName && sameString(sessionOwner, userName)))
 	{
 	char *sessionVar = cartSessionVarName();
 	unsigned hgsid = cartSessionId(cart);
 	struct sqlConnection *conn2 = hConnectCentral();
 	sessionTouchLastUse(conn2, encSessionOwner, encSessionName);
 	cartRemoveLike(cart, "*");
 	cartParseOverHash(cart, row[1]);
 	cartSetInt(cart, sessionVar, hgsid);
 	if (oldVars)
 	    hashEmpty(oldVars);
 	/* Overload settings explicitly passed in via CGI (except for the
 	 * command that sent us here): */
 	loadCgiOverHash(cart, oldVars);
+#ifndef GBROWSE
+	cartCopyCustomTracks(cart);
+#endif /* GBROWSE */
 	if (isNotEmpty(actionVar))
 	    cartRemove(cart, actionVar);
 	hDisconnectCentral(&conn2);
-	loadedSession = TRUE;
 	}
     else
 	errAbort("Sharing has not been enabled for user %s's session %s.",
 		 sessionOwner, sessionName);
     }
 else
     errAbort("Could not find session %s for user %s.",
 	     sessionName, sessionOwner);
 sqlFreeResult(&sr);
 freeMem(encSessionName);
-
-return loadedSession;
 }
 #endif /* GBROWSE */
 
 void cartLoadSettings(struct lineFile *lf, struct cart *cart,
 		      struct hash *oldVars, char *actionVar)
 /* Load settings (cartDump output) into current session, and then
  * reload the CGI settings (to support override of session settings).
  * If non-NULL, oldVars will contain values overloaded when reloading CGI.
  * If non-NULL, actionVar is a cartRemove wildcard string specifying the
  * CGI action variable that sent us here. */
 {
 char *line = NULL;
 int size = 0;
 char *sessionVar = cartSessionVarName();
 unsigned hgsid = cartSessionId(cart);
@@ -509,30 +508,33 @@
 	    struct dyString *dy = dyStringSub(val, "\\n", "\n");
 	    cartAddString(cart, var, dy->string);
 	    dyStringFree(&dy);
 	    }
 	else if (var != NULL)
 	    {
 	    cartSetString(cart, var, "");
 	    }
 	} /* not hgsid */
     } /* each line */
 if (oldVars)
     hashEmpty(oldVars);
 /* Overload settings explicitly passed in via CGI (except for the
  * command that sent us here): */
 loadCgiOverHash(cart, oldVars);
+#ifndef GBROWSE
+cartCopyCustomTracks(cart);
+#endif /* GBROWSE */
 
 if (isNotEmpty(actionVar))
     cartRemove(cart, actionVar);
 }
 
 static char *now()
 /* Return a mysql-formatted time like "2008-05-19 15:33:34". */
 {
 char nowBuf[256];
 time_t seconds = clock1();
 struct tm *theTime = localtime(&seconds);
 strftime(nowBuf, sizeof nowBuf, "%Y-%m-%d %H:%M:%S", theTime);
 return cloneString(nowBuf);
 }
 
@@ -607,65 +609,56 @@
 else if (userIdFound)
     cartParseOverHash(cart, cart->userInfo->contents);
 char when[1024];
 safef(when, sizeof(when), "open %d %d", userId, sessionId);
 cartTrace(cart, when, conn);
 
 loadCgiOverHash(cart, oldVars);
 
 // I think this is the place to justify old and new values
 cartJustify(cart, oldVars);
 
 #ifndef GBROWSE
 /* If some CGI other than hgSession been passed hgSession loading instructions,
  * apply those to cart before we do anything else.  (If this is hgSession,
  * let it handle the settings so it can display feedback to the user.) */
-boolean sessionLoaded = FALSE;
 if (! (cgiScriptName() && endsWith(cgiScriptName(), "hgSession")))
     {
     if (cartVarExists(cart, hgsDoOtherUser))
 	{
 	char *otherUser = cartString(cart, hgsOtherUserName);
 	char *sessionName = cartString(cart, hgsOtherUserSessionName);
 	struct sqlConnection *conn2 = hConnectCentral();
-	sessionLoaded = cartLoadUserSession(conn2, otherUser, sessionName, cart,
+	cartLoadUserSession(conn2, otherUser, sessionName, cart,
 			    oldVars, hgsDoOtherUser);
 	hDisconnectCentral(&conn2);
 	cartTrace(cart, "after cartLUS", conn);
 	}
     else if (cartVarExists(cart, hgsDoLoadUrl))
 	{
 	char *url = cartString(cart, hgsLoadUrlName);
 	struct lineFile *lf = netLineFileOpen(url);
-	sessionLoaded = TRUE;
 	cartLoadSettings(lf, cart, oldVars, hgsDoLoadUrl);
 	lineFileClose(&lf);
 	cartTrace(cart, "after cartLS", conn);
 	}
     }
 #endif /* GBROWSE */
 
 /* wire up the assembly hubs so we can operate without sql */
 hubConnectLoadHubs(cart);
 
-#ifndef GBROWSE
-// if we loaded a session, we want to copy the custom tracks so 
-// we don't change them in the session
-if (sessionLoaded)
-    cartCopyCustomTracks(cart, getDb(cart, oldVars));
-#endif /* GBROWSE */
-
 if (exclude != NULL)
     {
     while ((ex = *exclude++))
 	cartExclude(cart, ex);
     }
 
 cartDefaultDisconnector(&conn);
 return cart;
 }
 
 
 
 static void updateOne(struct sqlConnection *conn,
 	char *table, struct cartDb *cdb, char *contents, int contentSize)
 /* Update cdb in database. */