79ab7bed49d3d2a550d372fb58ab4bb283a6d31e
braney
  Thu Jan 30 00:08:47 2020 -0800
append trackDb names to the end of the db for trackDb cache directory to
support comma-separated lists of trackDb tables

diff --git src/hg/lib/trackDbCache.c src/hg/lib/trackDbCache.c
index dd4046c..e42c047 100644
--- src/hg/lib/trackDbCache.c
+++ src/hg/lib/trackDbCache.c
@@ -139,53 +139,62 @@
 for(tdb = list; tdb; tdb = tdb->next)
     {
     struct trackDb *newTdb = lmCloneTdb(lm, tdb, parent, superHash); 
 
     if (prevTdb)
         prevTdb->next = newTdb;
     else
         newList = newTdb;
 
     prevTdb = newTdb;
     }
 
 return newList;
 }
 
+static char *cacheDirForDbAndTable(char *string, char *tdbPathString)
+/* Determine the directory name for the trackDb cache files */
+{
+char dirName[4096];
+if (tdbPathString == NULL)
+    safef(dirName, sizeof dirName, "%s/%s", trackDbCacheDir, string);
+else
+    safef(dirName, sizeof dirName, "%s/%s.%s", trackDbCacheDir, string, tdbPathString);
+
+return cloneString(dirName);
+}
 
-static struct trackDb *checkCache(char *string, time_t time)
+static struct trackDb *checkCache(char *string, char *tdbPathString, time_t time)
 /* Check to see if this db or hub has a cached trackDb. string is either a db 
  * or a SHA1 calculated from a hubUrl. Use time to see if cache should be flushed. */
 {
-char dirName[4096];
-
-safef(dirName, sizeof dirName, "%s/%s", trackDbCacheDir, string);
+char *dirName = cacheDirForDbAndTable(string, tdbPathString);
 if (!isDirectory(dirName))
     {
     cacheLog("abandoning cache search for %s, no directory", string);
     return NULL;
     }
 
 // look for files named by the address they use
 struct slName *files = listDir(dirName, "*");
 char fileName[4096];
 for(; files; files = files->next)
     {
     if (sameString(files->name, "name.txt"))
         continue;
 
-    safef(fileName, sizeof fileName, "%s/%s/%s", trackDbCacheDir, string, files->name);
+    safef(fileName, sizeof fileName, "%s/%s", dirName, files->name);
     cacheLog("checking cache file %s", fileName);
     
     struct stat statBuf;
     if (stat(fileName, &statBuf) < 0)
         {
         // if we can't stat the shared memory, let's just toss it
         cacheLog("can't stat file %s, unlinking", fileName);
         mustRemove(fileName);
         continue;
         }
 
     if (statBuf.st_mtime < time)
         {
         // if the cache is older than the data, toss it
         cacheLog("cache is older than source, unlinking");
@@ -230,74 +239,73 @@
         u_char *ret = mem + lmBlockHeaderSize();
         maybeTouchFile(fileName);
         cacheLog("using cache memory at %lx", ret);
         return (struct trackDb *)ret;
         }
     cacheLog("unmapping cache memory at %lx", mem);
     munmap((void *)mem, size);
     close(fd);
     }
 
 cacheLog("abandoning cache search for %s", string);
 return NULL;
 }
 
 
-struct trackDb *trackDbCache(char *db, time_t time)
+struct trackDb *trackDbCache(char *db, char *tdbPathString, time_t time)
 /* Check to see if this db has a cached trackDb. */
 {
-cacheLog("checking for cache for db %s at time  %ld", db, time);
-return checkCache(db, time);
+cacheLog("checking for cache for db %s tdbPathString %s at time  %ld", db, tdbPathString,  time);
+return checkCache(db, tdbPathString, time);
 }
 
 struct trackDb *trackDbHubCache(char *trackDbUrl, time_t time)
 {
 cacheLog("checking for cache for hub %s at time  %ld", trackDbUrl, time);
 unsigned char hash[SHA_DIGEST_LENGTH];
 SHA1((const unsigned char *)trackDbUrl, strlen(trackDbUrl), hash);
 
 char newName[(SHA_DIGEST_LENGTH + 1) * 2];
 hexBinaryString(hash,  SHA_DIGEST_LENGTH, newName, (SHA_DIGEST_LENGTH + 1) * 2);
 
-return checkCache(newName, time);
+return checkCache(newName, NULL, time);
 }
 
-static void cloneTdbListToSharedMem(char *string, struct trackDb *list, unsigned long size, char *name)
+static void cloneTdbListToSharedMem(char *string, char *tdbPathString, struct trackDb *list, unsigned long size, char *name)
 /* Allocate shared memory and clone trackDb list into it. */
 {
 static int inited = 0;
 
 if (inited == 0)
     {
     srandom(time(NULL));
     inited = 1;
     }
     
 int oflags=O_RDWR | O_CREAT;
 
-char dirName[4096];
-safef(dirName, sizeof dirName, "%s/%s", trackDbCacheDir, string);
+char *dirName = cacheDirForDbAndTable(string, tdbPathString);
 
 if (!isDirectory(dirName))
     {
     cacheLog("making directory %s", dirName);
     makeDir(dirName);
     chmod(dirName, 0777);
     }
 
 char tempFileName[4096];
-safef(tempFileName, sizeof tempFileName, "%s/%s", trackDbCacheDir, rTempName(string, "temp", ""));
+safef(tempFileName, sizeof tempFileName, "%s",  rTempName(dirName, "temp", ""));
 
 int fd = open(tempFileName, oflags, 0666 );
 if (fd < 0)
     {
     cacheLog("unable to open shared memory %s errno %d", tempFileName, errno);
     mustRemove(tempFileName);
     return;
     }
 else
     {
     cacheLog("open shared memory %s", tempFileName);
     }
 ftruncate(fd, 0);
 ftruncate(fd, size);
 
@@ -335,62 +343,65 @@
 
 lmCloneTdbList(lm, list, NULL, superHash);
 
 unsigned long memUsed = lmUsed(lm) + lmBlockHeaderSize();
 cacheLog("cloning tdbList %p used %ld bytes called with %ld", list, memUsed, size);
 
 msync((void *)paddress, memUsed, MS_SYNC);
 ftruncate(fd, memUsed);
 
 // for the moment we're not unmapping these so multiple attached hubs will get
 // different addresses
 //munmap((void *)paddress, size);
 //close(fd);
 
 char fileName[4096];
-safef(fileName, sizeof fileName, "%s/%s/%ld.%d", trackDbCacheDir, string, paddress, TRACKDB_VERSION);
+safef(fileName, sizeof fileName, "%s/%ld.%d", dirName, paddress, TRACKDB_VERSION);
 
 cacheLog("renaming %s to %s", tempFileName, fileName);
 mustRename(tempFileName, fileName);
 
 // write out the name of the trackDb being cached.
-safef(fileName, sizeof fileName, "%s/%s/name.txt", trackDbCacheDir, string);
+safef(fileName, sizeof fileName, "%s/name.txt", dirName);
 FILE *stream = mustOpen(fileName, "w");
+if (tdbPathString == NULL)
     fprintf(stream, "%s\n", name);
+else
+    fprintf(stream, "%s.%s\n", name,tdbPathString);
 carefulClose(&stream);
 }
 
-void trackDbCloneTdbListToSharedMem(char *db, struct trackDb *list, unsigned long size)
+void trackDbCloneTdbListToSharedMem(char *db, char *tdbPathString, struct trackDb *list, unsigned long size)
 /* For this native db, allocate shared memory and clone trackDb list into it. */
 {
 cacheLog("cloning memory for db %s %ld", db, size);
-cloneTdbListToSharedMem(db, list, size, db);
+cloneTdbListToSharedMem(db, tdbPathString, list, size, db);
 }
 
 void trackDbHubCloneTdbListToSharedMem(char *trackDbUrl, struct trackDb *list, unsigned long size)
 /* For this hub, Allocate shared memory and clone trackDb list into it. */
 {
 if ((*trackDbUrl == '.') || (list == NULL)) // don't cache empty lists or collections
     return;
 cacheLog("cloning memory for hub %s %ld", trackDbUrl, size);
 unsigned char hash[SHA_DIGEST_LENGTH];
 SHA1((const unsigned char *)trackDbUrl, strlen(trackDbUrl), hash);
 
 char newName[(SHA_DIGEST_LENGTH + 1) * 2];
 hexBinaryString(hash,  SHA_DIGEST_LENGTH, newName, (SHA_DIGEST_LENGTH + 1) * 2);
 
-cloneTdbListToSharedMem(newName, list, size, trackDbUrl);
+cloneTdbListToSharedMem(newName, NULL, list, size, trackDbUrl);
 }
 
 boolean trackDbCacheOn()
 /* Check to see if we're caching trackDb contents. */
 {
 static boolean checkedCache = FALSE;
 static boolean doCache = FALSE;
 
 if (!checkedCache)
     {
     trackDbCacheDir = cfgOption("cacheTrackDbDir");
     if (isNotEmpty(trackDbCacheDir))
         {
         makeDirsOnPath(trackDbCacheDir);
         doCache = TRUE;