bfca2e5a7f3391f6b02581da7a84524fd8de66fb
angie
  Thu Mar 5 10:05:33 2015 -0800
Since groupedTrackDb is so large for hg19, it can actually arrive after
the user has already switched to a different database and received the
groupTrackDb for the new database.  Prevent clobbering by including the
database to which this particular groupedTrackDb belongs.

diff --git src/hg/lib/cartJson.c src/hg/lib/cartJson.c
index 884b96f..67deacf 100644
--- src/hg/lib/cartJson.c
+++ src/hg/lib/cartJson.c
@@ -387,64 +387,69 @@
     struct slRef *slr = slRefNew(tdb);
     if (hel)
 	slAddHead(&(hel->val), slr);
     else
 	hashAdd(hash, tdb->grp, slr);
     }
 struct hashCookie cookie = hashFirst(hash);
 struct hashEl *hel;
 while ((hel = hashNext(&cookie)) != NULL)
     slSort(&hel->val, trackDbRefCmp);
 return hash;
 }
 
 void cartJsonGetGroupedTrackDb(struct cartJson *cj, struct hash *paramHash)
 /* Translate trackDb list (only a subset of the fields) into JSON array of track group objects;
- * each group contains an array of track objects that may have subtracks. */
+ * each group contains an array of track objects that may have subtracks.  Send it in a wrapper
+ * object that includes the database from which it was taken; it's possible that by the time
+ * this reaches the client, the user might have switched to a new db. */
 {
 struct trackDb *fullTrackList = NULL;
 struct grp *fullGroupList = NULL;
 cartTrackDbInit(cj->cart, &fullTrackList, &fullGroupList, /* useAccessControl=*/TRUE);
 struct hash *groupedTrackRefList = hashTracksByGroup(fullTrackList);
 // If the optional param 'fields' is given, hash the field names that should be returned.
 char *fields = cartJsonOptionalParam(paramHash, "fields");
 struct hash *fieldHash = hashFromCommaString(fields);
 // Also check for optional parameter 'maxDepth':
 int maxDepth = -1;
 char *maxDepthStr = cartJsonOptionalParam(paramHash, "maxDepth");
 if (isNotEmpty(maxDepthStr))
     maxDepth = atoi(maxDepthStr);
 struct jsonWrite *jw = cj->jw;
+jsonWriteObjectStart(jw, "groupedTrackDb");
+jsonWriteString(jw, "db", cartString(cj->cart, "db"));
 jsonWriteListStart(jw, "groupedTrackDb");
 struct grp *grp;
 for (grp = fullGroupList;  grp != NULL;  grp = grp->next)
     {
     jsonWriteObjectStart(jw, NULL);
     jsonWriteString(jw, "name", grp->name);
     jsonWriteString(jw, "label", grp->label);
     jsonWriteListStart(jw, "tracks");
     struct slRef *tdbRefList = hashFindVal(groupedTrackRefList, grp->name);
     struct slRef *tdbRef;
     for (tdbRef = tdbRefList;  tdbRef != NULL;  tdbRef = tdbRef->next)
         {
         struct trackDb *tdb = tdbRef->val;
         rWriteTdb(jw, tdb, fieldHash, 1, maxDepth);
         }
     jsonWriteListEnd(jw);
     jsonWriteObjectEnd(jw);
     }
 jsonWriteListEnd(jw);
+jsonWriteObjectEnd(jw);
 }
 
 static char *hAssemblyDescription(char *db)
 /* Return a string containing db's description.html, or NULL if not found. */
 //#*** LIBIFY: Code lifted from hgFind.c's hgPositionsHelpHtml.
 {
 char *htmlPath = hHtmlPath(db);
 char *htmlString = NULL;
 if (htmlPath != NULL)
     {
     if (fileExists(htmlPath))
 	readInGulp(htmlPath, &htmlString, NULL);
     else if (startsWith("http://" , htmlPath) ||
 	     startsWith("https://", htmlPath) ||
 	     startsWith("ftp://"  , htmlPath))