5c2d251dadde6df5e79e6b989cd9e8326531b558
braney
  Fri Jun 21 16:43:27 2019 -0700
ongoing work on trackDb caching.    Random memory locations, and caching
hash tables

diff --git src/hg/lib/trackDbCustom.c src/hg/lib/trackDbCustom.c
index 9ebf2e6..4676de4 100644
--- src/hg/lib/trackDbCustom.c
+++ src/hg/lib/trackDbCustom.c
@@ -1599,30 +1599,66 @@
 if (superHash == NULL)
     errAbort("parsing supertrack without superHash");
 
 struct trackDb *super = (struct trackDb *)hashFindVal(superHash, tdb->parent->track);
 
 if (super == NULL)
     {
     super = lmCloneTdb(lm, tdb->parent, NULL, NULL);
     hashAdd(superHash, super->track, super);
     }
 lmRefAdd(lm, &super->children, tdb);
 
 return super;
 }
 
+struct hashEl *lmCloneHashElList(struct lm *lm, struct hashEl *list)
+/* Clone a list of hashEl's. */
+{
+struct hashEl *newList = NULL;
+
+for(; list; list = list->next)
+    {
+    struct hashEl *hel = lmAlloc(lm, sizeof(struct hashEl));
+    slAddHead(&newList, hel);
+    hel->name = lmCloneString(lm, list->name);
+    hel->val = lmCloneString(lm, (char *)list->val);  // we're assuming that the values are strings
+    hel->hashVal = list->hashVal;
+    }
+
+return newList;
+}
+
+struct hash *lmCloneHash(struct lm *lm, struct hash *hash)
+/* Clone a hash into local memory. */
+{
+struct hash *newHash = lmAlloc(lm, sizeof(struct hash));
+
+*newHash = *hash;
+newHash->lm = NULL;
+newHash->ownLm = FALSE;
+newHash->next = NULL;
+lmAllocArray(lm, newHash->table, hash->size);
+
+int ii;
+for(ii=0; ii < hash->size; ii++)
+    if (hash->table[ii] != NULL)
+        newHash->table[ii] = lmCloneHashElList(lm, hash->table[ii]);
+
+return newHash;
+}
+
 struct trackDb *lmCloneTdb(struct lm *lm, struct trackDb *tdb, struct trackDb *parent,  struct hash *superHash)
 /* clone a single tdb structure.  Will clone its children if it has any */
 {
 struct trackDb *newTdb = lmAlloc(lm, sizeof(struct trackDb));
 
 *newTdb = *tdb;
 
 if (tdb->subtracks)
     newTdb->subtracks = lmCloneTdbList(lm, tdb->subtracks, newTdb, NULL);
 
 if ((tdb->parent != NULL) && (superHash != NULL))
     {
     newTdb->parent = lmCloneSuper(lm, newTdb, superHash);
     }
 else
@@ -1638,43 +1674,33 @@
     lmAllocArray(lm, newTdb->restrictList, newTdb->restrictCount);
     int ii;
     for(ii=0; ii < newTdb->restrictCount; ii++)
         newTdb->restrictList[ii] = lmCloneString(lm, tdb->restrictList[ii]);
     }
 newTdb->url = lmCloneString(lm, tdb->url);
 newTdb->html = lmCloneString(lm, tdb->html);
 newTdb->grp = lmCloneString(lm, tdb->grp);
 newTdb->parentName = lmCloneString(lm, tdb->parentName);
 
 newTdb->viewHash =  NULL;
 newTdb->children = NULL;
 newTdb->overrides = NULL;
 newTdb->tdbExtras = NULL;
 
-// at this point the settingsHash has values in it that aren't recorded in the static settings 
-// string, and there are a couple of values in the settings string that for some reason aren't in the hash,
-// soo.... rebuild the settings string to have both its original contents, as well as everything that's
-// been added to the hash since it was first read in.   This string will be converted back into a hash 
-// (allocated in non-shared memory) the first time trackDbSetting() is called.   There will be some duplications,
-// but that won't cause problems.
-struct dyString *dy = newDyString(1000);
-struct hashEl *hel = hashElListHash(tdb->settingsHash);
-dyStringPrintf(dy,"%s\n", tdb->settings);
-for(; hel; hel = hel->next)
-    dyStringPrintf(dy,"%s %s\n", hel->name, (char *)hel->val);
-newTdb->settings = lmCloneString(lm, dy->string);
-newTdb->settingsHash = NULL;
+newTdb->settings = lmCloneString(lm, tdb->settings);
+newTdb->settingsHash = lmCloneHash(lm, tdb->settingsHash);
+
 return newTdb;
 }
 
 struct trackDb *lmCloneTdbList(struct lm *lm, struct trackDb *list, struct trackDb *parent, struct hash *superHash)
 /* clone a list of tdb structures. */
 {
 struct trackDb *tdb, *prevTdb = NULL, *newList = NULL;
 
 for(tdb = list; tdb; tdb = tdb->next)
     {
     struct trackDb *newTdb = lmCloneTdb(lm, tdb, parent, superHash); 
 
     if (prevTdb)
         prevTdb->next = newTdb;
     else
@@ -1703,39 +1729,39 @@
 // look for files named by the address they use
 struct slName *files = listDir(dirName, "*");
 char fileName[4096];
 for(; files; files = files->next)
     {
     char sharedMemoryName[4096];
     safef(sharedMemoryName, sizeof sharedMemoryName, "%s/%s/%s", trackDbCacheDir, string, files->name);
     safef(fileName, sizeof fileName, "/dev/shm/%s/%s/%s", trackDbCacheDir, string, 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);
-        unlink(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");
-        unlink(fileName);
+        mustRemove(fileName);
         continue;
         }
 
     int oflags = O_RDONLY;
     int fd = open(fileName, oflags);
     if (fd < 0)
         {
         cacheLog("cannot open %s", sharedMemoryName);
         continue;
         }
 
     unsigned long address = atoi(files->name); // the name of the file is the address it uses
     unsigned long size = fileSize(fileName);
 
     u_char *mem = (u_char *) mmap((void *)address, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
@@ -1766,83 +1792,98 @@
 struct trackDb *trackDbHubCache(char *trackDbUrl, time_t time, char *trackDbCacheDir)
 {
 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, trackDbCacheDir);
 }
 
 static void cloneTdbListToSharedMem(char *string, struct trackDb *list, unsigned long size, char *trackDbCacheDir)
 /* 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, "/dev/shm/%s/%s", trackDbCacheDir, string);
 
 if (!isDirectory(dirName))
     {
     cacheLog("making directory %s", dirName);
     makeDir(dirName);
     chmod(dirName, 0777);
     }
 
 char sharedMemoryName[4096];
 safef(sharedMemoryName, sizeof sharedMemoryName, "%s/%s", trackDbCacheDir, rTempName(string, "temp", ""));
 
 char tempFileName[4096];
 safef(tempFileName, sizeof tempFileName, "/dev/shm/%s",  sharedMemoryName);
 
 int fd = open(tempFileName, oflags, 0666 );
 if (fd < 0)
     {
-    unlink(tempFileName);
     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);
 
 size_t psize = getpagesize();
 unsigned long pageMask = psize - 1;
+unsigned long paddress = 0;
 
-// we should choose an address semi-randomly and make sure we can grab it rather than assume we can
-unsigned long address;
-unsigned long paddress;
 unsigned char *mem;
-for(address = 0x7000000; address < 0xf000000; address += 0x500000)
+int numTries = 20;
+
+// we try numTries times to connect to a random address 
+for(; numTries; numTries--)
     {
+    unsigned long address = random();
     paddress = (address + psize - 1) & ~pageMask;
 
-    mem = (u_char *) mmap((void *)address, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
-    cacheLog("asked for memory %lx of size %ld, got %lx",address, size, mem);
-    if ((unsigned long)mem == address)
+    mem = (u_char *) mmap((void *)paddress, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+    cacheLog("asked for memory %lx of size %ld, got %lx",paddress, size, mem);
+    if ((unsigned long)mem == paddress)
         break;
     cacheLog("unmapping memory at %lx",mem);
     munmap((void *)mem, size);
+    mem = 0;
     }
 
-if (address >= 0xf000000)
-    errAbort("can't get address");
+if (mem == 0)
+    {
+    cacheLog("giving up on finding memory");
+    mustRemove(tempFileName);
+    return;
+    }
 
 struct lm *lm = lmInitWMem(mem, size);
 struct hash *superHash = newHash(8);
 
 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);