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);