eb7e6ccb9b23c2dd5cd82de0237c6f25aecd2da1 max Thu Sep 17 06:02:11 2026 -0700 Hub tracks must not claim an undecorated name that a native track owns #Preview2 week - bugs introduced now will need a build patch to fix A hub track can be named on a URL, or found in the cart, without its "hub__" prefix, so that hub links stay readable. Nothing checked whether the assembly already had a track of that name, so when it did, the hub track took the variable: with the MethBase2 hub attached, setting the native hg38 Methbase track's visibility moved it to hub__Methbase and dropped it from the native track, which then did not draw. The two share the name "Methbase", and their subtracks share names too, so the same went for the _sel checkboxes. hubTrackOwnsBareName() now gates the seven places that fall back to the bare name - track and subtrack visibility, supertrack visibility, the two _hideKids variables, and the _sel checkbox. The bare name is the hub track's only where the assembly has no track of that name; otherwise it belongs to the native one, whose own pass over the track list consumes it. It answers from the track list loadFromTrackDb() has already built, so it costs a hash lookup: hub tracks are always prefixed in that list, so an undecorated name can only match a native track. A caller with no list to register (hgTrackUi) falls back to a single-row trackDb query per distinct bare name, cached. With 500 hub subtracks visible and 500 bare names on the URL - far past anything real - that is 189 queries either way, against 1189 for a query per name. Also clarifies the comments on hTrackDbWithCartVersion() and tdbForTrack(): the "this result is cached" note means the shared-memory trackDb cache only, which is off unless cacheTrackDbDir is set, and there is no memoizing besides it - so hTrackDbForTrack() per name reloads the whole trackDb each call. Measured at 57 seconds for 500 names before I abandoned that approach. refs #34246 diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c index 02b1954b3f5..2d223bf244a 100644 --- src/hg/lib/hdb.c +++ src/hg/lib/hdb.c @@ -4401,31 +4401,36 @@ struct trackDb *trackDbPolishAfterLinkup(struct trackDb *tdbList, char *db) /* Do various massaging that can only be done after parent/child * relationships are established. */ { tdbList = pruneEmpties(tdbList, db, hIsPrivateHost() || hIsPreviewHost(), 0); return trackDbPolishAfterLinkupKeepAll(tdbList); } struct trackDb *hTrackDbWithCartVersion(char *db, int *retCartVersion) /* Load tracks associated with current db. * Supertracks are loaded as a trackDb, but are not in the returned list, * but are accessible via the parent pointers of the member tracks. Also, * the supertrack trackDb subtrack fields are not set here (would be * incompatible with the returned list) * Returns list sorted by priority - * NOTE: this result is cached, do not free it ! + * NOTE: do not free this result - when the cache is on it is shared memory. + * NOTE: "cached" here means the shared-memory trackDb cache, which is only on when + * cacheTrackDbDir is set in hg.conf (it is not on a sandbox by default). There is no + * memoizing besides that: with the cache off, every call reloads and relinks the whole + * trackDb, so calling this once per track name is quadratic. Load the list once and + * pass it around - see tdbForTrack()'s tdbList argument. */ { if (trackHubDatabase(db)) return NULL; if (isHubTrack(db)) { // this means the db has a hub_#_ prefix but didn't get loaded at init time unsigned hubId = hubIdFromTrackName(db); struct hubConnectStatus *status = hubFromIdNoAbort(hubId); if (status == NULL) errAbort("Error: The database in the hub (%s) that is saved in your session is no longer accessible." " This may be due because the hub ID (%d) in your session cannot be transferred across" " different Genome Browser machines.\n",hubConnectSkipHubPrefix(db), hubId);