b0828e726eba3cbd345f94f1ed0ad1b334424f7d angie Thu Mar 14 10:38:31 2013 -0700 Fixing bug reported via MLQ: When repeatedly adding/modifying customtracks and saving sessions without any cartResets or session loads, the same ctfile was used in both saved sessions and the user's active cart, so modifications after saving a session were leaking back to saved sessions. Fix: copy custom tracks not only when loading a saved session, but also immediately after saving a session, so that the user's active cart no longer has the same ctfile (and customTrash database tables, etc) as the saved session. fixes #10396, refs #10323 diff --git src/hg/lib/cart.c src/hg/lib/cart.c index a54eff4..6c4ea2d 100644 --- src/hg/lib/cart.c +++ src/hg/lib/cart.c @@ -228,37 +228,35 @@ 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 -static void cartCopyCustomTracks(struct cart *cart, struct hash *oldVars) +void cartCopyCustomTracks(struct cart *cart, char *db) /* If cart contains any live custom tracks, save off a new copy of them, - * to prevent clashes by multiple loaders of the same session. */ + * to prevent clashes by multiple uses of the same session. */ { struct hashEl *el, *elList = hashElListHash(cart->hash); -char *db=NULL, *ignored; -getDbAndGenome(cart, &db, &ignored, oldVars); for (el = elList; el != NULL; el = el->next) { if (startsWith(CT_FILE_VAR_PREFIX, el->name)) { 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) { @@ -397,30 +395,38 @@ } static void hashEmpty(struct hash *hash) /* Remove everything from hash. */ { struct hashEl *hel, *helList = hashElListHash(hash); for (hel = helList; hel != NULL; hel = hel->next) { freez(&(hel->val)); 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 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. */ { struct sqlResult *sr = NULL; char **row = NULL; char *userName = wikiLinkUserName(); char *encSessionName = cgiEncodeFull(sessionName); char *encSessionOwner = cgiEncodeFull(sessionOwner); @@ -442,31 +448,31 @@ (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, oldVars); + cartCopyCustomTracks(cart, getDb(cart, oldVars)); #endif /* GBROWSE */ if (isNotEmpty(actionVar)) cartRemove(cart, actionVar); hDisconnectCentral(&conn2); } 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); } @@ -502,31 +508,31 @@ 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, oldVars); +cartCopyCustomTracks(cart, getDb(cart, oldVars)); #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); }