93a3129444064c4d19b4cb49e24b6de4bd0e06a6 markd Fri Oct 2 21:41:15 2026 -0700 Restore the superTrack nesting fix. refs #38460 Taking this off master was over-cautious. It is wanted on its own: #38460 is a real bug, a superTrack given a parent passes tdbQuery -check -strict and is then silently dropped at load, and the fix should get into a release rather than wait on a trackDb change that uses it. Nothing on master nests yet, and the fix is behaviour-identical where nothing does: trackDb built with it and with the released hgTrackDb is byte-identical on hg38, hs1 and mm39, and hgTracks renders the same rows and supertrack controls as dev. The TSS trackDb change that uses this stays reverted, on superTrackNesting, until this ships. Whoever releases it: trackDbToTxt has to be rebuilt too, or the curated hub it writes names a parent stanza it did not emit. diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c index 3ac8722e87c..6aa8b05af50 100644 --- src/hg/lib/hdb.c +++ src/hg/lib/hdb.c @@ -4330,40 +4330,45 @@ } static struct trackDb *rFindTrack(int level, struct trackDb *tdbList, char *track) /* Look for named track in list or children. */ { struct trackDb *tdb; for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { if (sameString(track, tdb->track)) return tdb; struct trackDb *matchingChild = rFindTrack(level+1, tdb->subtracks, track); if (matchingChild != NULL) return matchingChild; } -/* Look "to the sky" in parents of root generation as well. */ +/* Look "to the sky" in parents of root generation as well. Walk the whole + * chain: a supertrack may sit inside another supertrack, and neither is in the + * list itself, so the outer one is only reachable through the inner one. */ if (level == 0) { for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { - struct trackDb *p = tdb->parent; - if (p != NULL && sameString(track, p->track)) + struct trackDb *p; + for (p = tdb->parent; p != NULL; p = p->parent) + { + if (sameString(track, p->track)) return p; } } + } return NULL; } #ifdef DEBUG static void dumpFlagStatus(struct trackDb *tdbList, char *tableName, char *label) /* Look for tdbList for track matching tableName. Print out info on it starting with label. */ { struct trackDb *tdb = rFindTrack(0, tdbList, tableName); if (tdb == NULL) printf("%s: nil
\n", label); else printf("%s: treeNodeType %d, composite? %d, supertrack ? %d
\n", label, tdb->treeNodeType, COMPOSITE_NODE(tdb->treeNodeType), SUPERTRACK_NODE(tdb->treeNodeType)); } #endif /* DEBUG */ @@ -4372,30 +4377,35 @@ /* Go through tdbList and set up the ->children field in parents with references * to their children. */ { struct trackDb *tdb; /* Insert a little paranoid check here to make sure this doesn't get called twice. */ for (tdb = tdbList; tdb != NULL; tdb = tdb->next) if (tdb->children != NULL) internalErr(); for (tdb = tdbList; tdb != NULL; tdb = tdb->next) { struct trackDb *parent = tdb->parent; if (parent != NULL) refAdd(&parent->children, tdb); + /* A supertrack that is a member of another supertrack is not in tdbList + * itself, so the loop above never reaches it. Add it to its own parent's + * children the first time one of its members brings us here. */ + for (; parent != NULL && tdbIsSuperTrackChild(parent); parent = parent->parent) + refAddUnique(&parent->parent->children, parent); } } struct trackDb *trackDbPolishAfterLinkupKeepAll(struct trackDb *tdbList) /* The part of trackDbPolishAfterLinkup that every caller wants, without dropping * tracks whose data cannot be reached. hubCheck needs this: a track pruned because * its bigDataUrl does not resolve is exactly the track hubCheck has to report on. */ { addChildRefsToParents(tdbList); trackDbContainerMarkup(NULL, tdbList); rInheritFields(tdbList); slSort(&tdbList, trackDbCmp); return tdbList; }