Skip to content

Track pair renders read canonical state after resuming — same in-flight hazard as #469 #473

Description

@turner

Found while fixing #469, not reproduced yet — filed so it is not lost.

#469 fixed ContactMatrixView.repaint: a render pass that resumed after reset() painted against canonical state that had been cleared or replaced. TrackPair has the same shape and was not touched.

js/trackPair.js:171 (updateViews) reads canonical state after an await:

const genomicStateX = this.browser.genomicState(this.x.axis);
let imageTileX = await this.getTileX(genomicStateX);   // <-- window
...
const genomicStateY = this.browser.genomicState(this.y.axis);   // resume-time read

browser.genomicState() (js/hicBrowser.js:370) dereferences this.dataset.bpResolutions[this.state.zoom] with no guard. reset() calls removeAllTrackXYPairs() and stateManager.clearState() (js/hicBrowser.js:508, :516), so an in-flight updateViews() on a pair that has just been removed should throw the same shape of TypeError — on dataset/state rather than on state.x.

js/trackPair.js:198 (repaintViews) has the same await-then-read pattern.

Suggested fix

The same remedy as #469: capture the State object at the start of the pass and bail if browser.state is no longer that object by the time it resumes. Identity is the right test — the chokepoint mutates in place, so pans keep the same object, while a clear or a bulk replacement swaps it.

Before fixing

Reproduce it first. #469's repro (a reset() between a track load and its render) should be adaptable; it needs a 1D track loaded so a TrackPair exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugneeds-triageMaintainer needs to evaluate this issue

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions