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_<id>_" 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_<id>_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/inc/hdb.h src/hg/inc/hdb.h index 7a1ae0dce09..f5092403dfa 100644 --- src/hg/inc/hdb.h +++ src/hg/inc/hdb.h @@ -569,31 +569,36 @@ * 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 ! */ struct trackDb *hTrackDbWithCartVersion(char *db, int *retCartVersion); /* Do hTrackDb AND return cartVersion. */ struct trackDb *tdbForTrack(char *db, char *track,struct trackDb **tdbList); /* Load trackDb object for a track. If track is composite, its subtracks * will also be loaded and inheritance will be handled; if track is a * subtrack then inheritance will be handled. (Unless a subtrack has * "noInherit on"...) This will die if the current database does not have * a trackDb, but will return NULL if track is not found. - * MAY pass in prepopulated trackDb list, or may receive the trackDb list as an inout. */ + * MAY pass in prepopulated trackDb list, or may receive the trackDb list as an inout. + * Pass tdbList whenever you look up more than one track. With it NULL this loads the + * whole trackDb to find one name, and that is only cheap where the shared-memory cache + * is on (cacheTrackDbDir in hg.conf) - with the cache off hTrackDb() does not memoize, + * so a loop over N names is N full trackDb loads. To ask only whether a name exists, + * hMaybeTrackInfo() is a single-row query instead. */ #define hTrackDbForTrack(db,track) tdbForTrack(db,track,NULL) struct trackDb *hTrackDbForTrackAndAncestors(char *db, char *track); /* Load trackDb object for a track. If need be grab its ancestors too. * This does not load children. hTrackDbForTrack will handle children, and * is actually faster if being called on lots of tracks. This function * though is faster on one or two tracks. */ // WARNING: this works for hub and db tracks but not custom tracks. struct trackDb *hCompositeTrackDbForSubtrack(char *db, struct trackDb *sTdb); /* Given a trackDb that may be for a subtrack of a composite track, * return the trackDb for the composite track if we can find it, else NULL. * Note: if the composite trackDb is found and returned, then its subtracks * member will contain a newly allocated tdb like sTdb (but not ==). */