Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 1x 4x 4x 4x 4x 3x 3x 3x 4x 4x 1x 4x 4x 23x 23x 4x 1x | /**
* Which of the reader's work somebody is waiting for, and which can wait (§12).
*
* One worker reads for everything: the views, and two walks nobody is looking
* at — the census that counts a `.hic`'s contacts (§6.5) and the circularity
* check's reads (§8.15). Their reads interleave with a view's, and over a
* network each is a round trip that holds the thread, so a chromosome clicked
* while they ran waited for theirs as well as its own: on a 1 GB `.hic` from
* S3, 10 s for a picture that took 4 alone, under a veil that named the census.
*
* So a view's request counts itself in while it runs, and the background waits
* until none has run for {@link SETTLE_MS} — long enough to cover the round trip
* to the main thread between a view's `range` and its `matrix`, which would
* otherwise be a gap for a walk to step into.
*/
import { yieldToEventLoop } from '../async'
/** Quiet a background step waits for after the last view request ends. */
export const SETTLE_MS = 250
/** How often a waiting step looks again. */
const POLL_MS = 50
export class Foreground {
private reading = 0
private quietSince = Number.NEGATIVE_INFINITY
constructor(
private readonly now: () => number = () => performance.now(),
private readonly sleep: (ms: number) => Promise<void> = (ms) =>
new Promise((resolve) => setTimeout(resolve, ms)),
) {}
/** A request somebody is waiting for has started; call what it returns when it ends. */
begin(): () => void {
this.reading += 1
let ended = false
return () => {
if (ended) return
ended = true
this.reading -= 1
this.quietSince = this.now()
}
}
/**
* Resolve once no view has been reading for {@link SETTLE_MS}, or as soon as
* `stop` says the wait is over — a walk somebody has come to depend on, or a
* request called off. Always a real yield first, as the walks had before.
*/
async quiet(stop?: () => boolean): Promise<void> {
await yieldToEventLoop()
while (stop?.() !== true && (this.reading > 0 || this.now() - this.quietSince < SETTLE_MS)) {
await this.sleep(POLL_MS)
}
}
}
|