@gmod/bam 8.2.0 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -11
- package/dist/bai.d.ts +1 -0
- package/dist/bai.js +15 -0
- package/dist/bai.js.map +1 -1
- package/dist/bamFile.d.ts +34 -18
- package/dist/bamFile.js +23 -59
- package/dist/bamFile.js.map +1 -1
- package/dist/csi.d.ts +1 -0
- package/dist/csi.js +5 -0
- package/dist/csi.js.map +1 -1
- package/dist/htsget.d.ts +13 -0
- package/dist/htsget.js +6 -1
- package/dist/htsget.js.map +1 -1
- package/dist/indexFile.d.ts +44 -22
- package/dist/indexFile.js +55 -60
- package/dist/indexFile.js.map +1 -1
- package/dist/util.d.ts +40 -1
- package/dist/util.js +66 -6
- package/dist/util.js.map +1 -1
- package/esm/bai.d.ts +1 -0
- package/esm/bai.js +15 -0
- package/esm/bai.js.map +1 -1
- package/esm/bamFile.d.ts +34 -18
- package/esm/bamFile.js +21 -57
- package/esm/bamFile.js.map +1 -1
- package/esm/csi.d.ts +1 -0
- package/esm/csi.js +5 -0
- package/esm/csi.js.map +1 -1
- package/esm/htsget.d.ts +13 -0
- package/esm/htsget.js +6 -1
- package/esm/htsget.js.map +1 -1
- package/esm/indexFile.d.ts +44 -22
- package/esm/indexFile.js +56 -61
- package/esm/indexFile.js.map +1 -1
- package/esm/util.d.ts +40 -1
- package/esm/util.js +63 -4
- package/esm/util.js.map +1 -1
- package/package.json +2 -2
- package/src/bai.ts +16 -0
- package/src/bamFile.ts +40 -65
- package/src/csi.ts +6 -0
- package/src/htsget.ts +19 -1
- package/src/indexFile.ts +67 -64
- package/src/util.ts +73 -5
package/esm/indexFile.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { SharedReadCache } from '@gmod/shared-read-cache';
|
|
1
2
|
import QuickLRU from '@jbrowse/quick-lru';
|
|
2
|
-
import {
|
|
3
|
+
import { chunksLikelyRead, optimizeChunks } from "./util.js";
|
|
3
4
|
// SYNC: ~/src/gmod/tabix-js/src/util.ts memoizeByRefId
|
|
4
5
|
// LRU-cache the result of getIndices(refId) so repeated lookups for the same
|
|
5
6
|
// reference don't re-walk the index bytes.
|
|
@@ -22,14 +23,11 @@ export function memoizeByRefId(getIndices, maxSize = 5) {
|
|
|
22
23
|
export default class IndexFile {
|
|
23
24
|
filehandle;
|
|
24
25
|
renameRefSeq;
|
|
25
|
-
parseP;
|
|
26
26
|
/**
|
|
27
|
-
* The
|
|
28
|
-
*
|
|
29
|
-
* this the first query to arrive would own a read all the others depend on —
|
|
30
|
-
* see {@link parse}.
|
|
27
|
+
* The parsed index, as a shared read — see {@link parse}. One entry, never
|
|
28
|
+
* evicted, which is what a memo is.
|
|
31
29
|
*/
|
|
32
|
-
|
|
30
|
+
parseCache = new SharedReadCache({});
|
|
33
31
|
constructor({ filehandle, renameRefSeq = (n) => n, }) {
|
|
34
32
|
this.filehandle = filehandle;
|
|
35
33
|
this.renameRefSeq = renameRefSeq;
|
|
@@ -61,68 +59,32 @@ export default class IndexFile {
|
|
|
61
59
|
}
|
|
62
60
|
return optimizeChunks(chunks, this.getLowestChunk(ba, min));
|
|
63
61
|
}
|
|
64
|
-
// SYNC: ~/src/gmod/tabix-js/src/indexFile.ts parse — same
|
|
65
|
-
//
|
|
62
|
+
// SYNC: ~/src/gmod/tabix-js/src/indexFile.ts parse — same shape and the same
|
|
63
|
+
// reasoning below.
|
|
66
64
|
/**
|
|
67
65
|
* Parse the index, or join the parse already running.
|
|
68
66
|
*
|
|
69
67
|
* The index is downloaded and parsed once for the life of this object, so it
|
|
70
68
|
* is the one read here that is shared between queries — and therefore the one
|
|
71
69
|
* place a cancellation can leak from the query that asked for it to a query
|
|
72
|
-
* that did not. `_parse` hands `opts` straight to `filehandle.readFile`, so
|
|
73
|
-
*
|
|
74
|
-
* depends on: when it pans away, every concurrent query
|
|
70
|
+
* that did not. `_parse` hands `opts` straight to `filehandle.readFile`, so a
|
|
71
|
+
* bare memoized promise makes the first query to arrive the owner of a read
|
|
72
|
+
* every other query depends on: when it pans away, every concurrent query
|
|
73
|
+
* fails with its abort.
|
|
75
74
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* duplicate parse rather than a recursion whose depth depends on how the
|
|
82
|
-
* aborts interleave.
|
|
75
|
+
* The same cache the chunk reads use, for the same reason and with the same
|
|
76
|
+
* rule: the parse runs under a signal of its own and is cancelled only once
|
|
77
|
+
* every caller waiting on it has given up, so one query's abort is reported
|
|
78
|
+
* to that query alone. A rejection is dropped rather than cached, so a
|
|
79
|
+
* transient failure does not poison the index for the life of the file.
|
|
83
80
|
*
|
|
84
|
-
*
|
|
85
|
-
* the
|
|
86
|
-
*
|
|
87
|
-
*
|
|
81
|
+
* The fill is per call rather than on the cache so that the caller who starts
|
|
82
|
+
* the parse has its `onProgress` reach `filehandle.readFile` — the index is a
|
|
83
|
+
* whole-file read, and a determinate "downloading index" bar is what that
|
|
84
|
+
* callback exists for.
|
|
88
85
|
*/
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const pending = this.parseP;
|
|
92
|
-
if (!pending) {
|
|
93
|
-
return this.startParse(opts);
|
|
94
|
-
}
|
|
95
|
-
// read before awaiting: the owner is forgotten as soon as the parse settles
|
|
96
|
-
const ownerSignal = this.parseSignal;
|
|
97
|
-
try {
|
|
98
|
-
return await pending;
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
if (retried || !ownerSignal?.aborted || opts.signal?.aborted) {
|
|
102
|
-
throw e;
|
|
103
|
-
}
|
|
104
|
-
return this.parse(opts, true);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
startParse(opts) {
|
|
108
|
-
const pending = this._parse(opts);
|
|
109
|
-
this.parseP = pending;
|
|
110
|
-
this.parseSignal = opts.signal;
|
|
111
|
-
// Drop a rejection rather than keeping it, so one transient failure does not
|
|
112
|
-
// poison the index for the lifetime of the file. Both branches are
|
|
113
|
-
// identity-checked so a retry started after this settles is not cleared by
|
|
114
|
-
// the attempt it already replaced.
|
|
115
|
-
pending.then(() => {
|
|
116
|
-
if (this.parseP === pending) {
|
|
117
|
-
this.parseSignal = undefined;
|
|
118
|
-
}
|
|
119
|
-
}, () => {
|
|
120
|
-
if (this.parseP === pending) {
|
|
121
|
-
this.parseP = undefined;
|
|
122
|
-
this.parseSignal = undefined;
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
return pending;
|
|
86
|
+
parse(opts = {}) {
|
|
87
|
+
return this.parseCache.get('index', opts.signal, signal => this._parse({ ...opts, signal }));
|
|
126
88
|
}
|
|
127
89
|
async lineCount(refId, opts) {
|
|
128
90
|
const indexData = await this.parse(opts);
|
|
@@ -132,8 +94,41 @@ export default class IndexFile {
|
|
|
132
94
|
const indexData = await this.parse(opts);
|
|
133
95
|
return !!indexData.indices(seqId);
|
|
134
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Compressed bytes a `getRecordsForRange` over these regions is expected to
|
|
99
|
+
* download, from the index alone.
|
|
100
|
+
*
|
|
101
|
+
* Per region this is `chunksLikelyRead`, not every chunk `blocksForRange`
|
|
102
|
+
* returns: the difference is the whole point on a long-read file, where a
|
|
103
|
+
* narrow window inherits every chunk of every overlapping bin and reads a
|
|
104
|
+
* handful of them. Measured on a 40x ONT BAM (COLO829BL, chr3), summing all
|
|
105
|
+
* chunks against the bytes the same query really pulls:
|
|
106
|
+
*
|
|
107
|
+
* | window | all chunks | actually read | this estimate |
|
|
108
|
+
* | ------ | ---------- | ------------- | ------------- |
|
|
109
|
+
* | 380bp | 43.5MB | 7.8MB | 7.8MB |
|
|
110
|
+
* | 3.4kb | 43.5MB | 7.8MB | 7.8MB |
|
|
111
|
+
* | 100kb | 46.6MB | 10.4MB | 10.4MB |
|
|
112
|
+
* | 2Mb | 155.9MB | 155.9MB | 123.8MB |
|
|
113
|
+
*
|
|
114
|
+
* A caller gating on this — jbrowse's "too much data" banner is the one that
|
|
115
|
+
* exists — was being told 5.6x the truth on exactly the windows a reader
|
|
116
|
+
* spends their time in, and cannot answer it by zooming: every window narrower
|
|
117
|
+
* than a linear-index interval resolves to the same chunks and so to the same
|
|
118
|
+
* number.
|
|
119
|
+
*
|
|
120
|
+
* Still summed over merged chunks rather than per region, so two regions
|
|
121
|
+
* sharing a chunk are charged for it once.
|
|
122
|
+
*/
|
|
135
123
|
async estimatedBytesForRegions(regions, opts) {
|
|
136
|
-
const
|
|
124
|
+
const indexData = await this.parse(opts);
|
|
125
|
+
const blockResults = await Promise.all(regions.map(async (r) => {
|
|
126
|
+
const chunks = await this.blocksForRange(r.refId, r.start, r.end, opts);
|
|
127
|
+
const refIndex = indexData.indices(r.refId);
|
|
128
|
+
return refIndex
|
|
129
|
+
? chunksLikelyRead(chunks, this.getHighestChunk(refIndex, r.end))
|
|
130
|
+
: chunks;
|
|
131
|
+
}));
|
|
137
132
|
// Deduplicate and merge overlapping blocks across all regions
|
|
138
133
|
const mergedBlocks = optimizeChunks(blockResults.flat());
|
|
139
134
|
let total = 0;
|
package/esm/indexFile.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexFile.js","sourceRoot":"","sources":["../src/indexFile.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,oBAAoB,CAAA;AAEzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"indexFile.js","sourceRoot":"","sources":["../src/indexFile.ts"],"names":[],"mappings":"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"}
|
package/esm/util.d.ts
CHANGED
|
@@ -25,6 +25,46 @@ export interface BaseOpts {
|
|
|
25
25
|
*/
|
|
26
26
|
onProgress?: (bytesDownloaded: number, totalBytes?: number) => void;
|
|
27
27
|
}
|
|
28
|
+
export { throwIfAborted } from '@gmod/shared-read-cache';
|
|
29
|
+
export declare const MAX_CONCURRENT_CHUNK_READS = 6;
|
|
30
|
+
/**
|
|
31
|
+
* The prefix of `chunks` a query is expected to actually read, for callers that
|
|
32
|
+
* want to forecast a query's cost without running it.
|
|
33
|
+
*
|
|
34
|
+
* `blocksForRange` returns every chunk of every bin overlapping the query, at
|
|
35
|
+
* every level of the binning scheme, minus the ones the linear index puts
|
|
36
|
+
* entirely before it. On a long-read file that is wildly more than the query
|
|
37
|
+
* reads: a coarse bin's chunks run to the end of the bin's span, so a 380bp
|
|
38
|
+
* window on a deep ONT BAM resolves to 90 chunks / 43.5MB, of which
|
|
39
|
+
* `getRecordsForRange` reads 6 / 7.8MB before the early stop fires.
|
|
40
|
+
*
|
|
41
|
+
* Two bounds, and the answer is the larger:
|
|
42
|
+
*
|
|
43
|
+
* - `upperBoundBlockPosition` — the file offset past which a chunk holds no
|
|
44
|
+
* record the query wants, from the linear index one window beyond the query
|
|
45
|
+
* end. Chunks come back sorted by `minv`, so the ones under it are a prefix.
|
|
46
|
+
* - `MAX_CONCURRENT_CHUNK_READS` — the first batch is read unconditionally, so
|
|
47
|
+
* no query ever costs less than that however tight the upper bound is.
|
|
48
|
+
*
|
|
49
|
+
* **This is a forecast, not a bound the reader obeys**, and it is deliberately
|
|
50
|
+
* only used to describe a query rather than to answer one. The upper bound is
|
|
51
|
+
* an approximation: a record starting before the query end can sit at a higher
|
|
52
|
+
* offset than the linear-index entry past it (a long read reaching into the
|
|
53
|
+
* next window pins that entry low), so pruning a fetch this way would drop
|
|
54
|
+
* records. A forecast that is occasionally 20% under warns slightly early;
|
|
55
|
+
* a fetch that is occasionally short returns wrong data.
|
|
56
|
+
*
|
|
57
|
+
* An EMPTY prefix is that pin at its worst — the bound has landed at or before
|
|
58
|
+
* the query's own first chunk, so it orders nothing — and the answer there is
|
|
59
|
+
* every chunk rather than the batch floor. Without it this returns the floor on
|
|
60
|
+
* a file whose features are long against the linear-index interval, which is
|
|
61
|
+
* where the same forecast really does go wrong: ported to tabix-js and measured
|
|
62
|
+
* on the 1000 Genomes SV callset, whose 1.4Mb deletions pin the entry at the
|
|
63
|
+
* data start, it forecast 0.04MB against the 0.22MB the query read. On this
|
|
64
|
+
* corpus the fallback costs one fixture's win (chr22_nanopore, whose 10kb
|
|
65
|
+
* window keeps summing all 22 chunks) and no accuracy anywhere else.
|
|
66
|
+
*/
|
|
67
|
+
export declare function chunksLikelyRead(chunks: Chunk[], upperBoundBlockPosition?: number): Chunk[];
|
|
28
68
|
/**
|
|
29
69
|
* Merge and order the chunks a query resolved to.
|
|
30
70
|
*
|
|
@@ -35,7 +75,6 @@ export interface BaseOpts {
|
|
|
35
75
|
* underneath you. (The Chunk objects themselves are never mutated; a merged
|
|
36
76
|
* span produces a new instance.)
|
|
37
77
|
*/
|
|
38
|
-
export { throwIfAborted } from '@gmod/shared-read-cache';
|
|
39
78
|
export declare function optimizeChunks(chunks: Chunk[], lowest?: OffsetCoords): Chunk[];
|
|
40
79
|
export declare function parsePseudoBin(bytes: Uint8Array, offset: number): {
|
|
41
80
|
lineCount: number;
|
package/esm/util.js
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
import Chunk from "./chunk.js";
|
|
2
2
|
import { VirtualOffset } from "./virtualOffset.js";
|
|
3
|
+
// Re-exported so the internal import path stays './util.ts'. The
|
|
4
|
+
// implementation moved to @gmod/shared-read-cache, which needs it anyway --
|
|
5
|
+
// every consumer of that package was carrying an identical copy.
|
|
6
|
+
export { throwIfAborted } from '@gmod/shared-read-cache';
|
|
7
|
+
// How many of a query's chunks to read at once. Six is the HTTP/1.1 per-host
|
|
8
|
+
// connection cap browsers enforce, so going much above it buys nothing on the
|
|
9
|
+
// transport that matters and only widens peak memory.
|
|
10
|
+
//
|
|
11
|
+
// It is also the SMALLEST number of chunks any query reads, because
|
|
12
|
+
// `_fetchChunkFeatures` checks its early stop once, after this first batch
|
|
13
|
+
// (ADR 0010) — which is what `chunksLikelyRead` below is built on.
|
|
14
|
+
export const MAX_CONCURRENT_CHUNK_READS = 6;
|
|
15
|
+
/**
|
|
16
|
+
* The prefix of `chunks` a query is expected to actually read, for callers that
|
|
17
|
+
* want to forecast a query's cost without running it.
|
|
18
|
+
*
|
|
19
|
+
* `blocksForRange` returns every chunk of every bin overlapping the query, at
|
|
20
|
+
* every level of the binning scheme, minus the ones the linear index puts
|
|
21
|
+
* entirely before it. On a long-read file that is wildly more than the query
|
|
22
|
+
* reads: a coarse bin's chunks run to the end of the bin's span, so a 380bp
|
|
23
|
+
* window on a deep ONT BAM resolves to 90 chunks / 43.5MB, of which
|
|
24
|
+
* `getRecordsForRange` reads 6 / 7.8MB before the early stop fires.
|
|
25
|
+
*
|
|
26
|
+
* Two bounds, and the answer is the larger:
|
|
27
|
+
*
|
|
28
|
+
* - `upperBoundBlockPosition` — the file offset past which a chunk holds no
|
|
29
|
+
* record the query wants, from the linear index one window beyond the query
|
|
30
|
+
* end. Chunks come back sorted by `minv`, so the ones under it are a prefix.
|
|
31
|
+
* - `MAX_CONCURRENT_CHUNK_READS` — the first batch is read unconditionally, so
|
|
32
|
+
* no query ever costs less than that however tight the upper bound is.
|
|
33
|
+
*
|
|
34
|
+
* **This is a forecast, not a bound the reader obeys**, and it is deliberately
|
|
35
|
+
* only used to describe a query rather than to answer one. The upper bound is
|
|
36
|
+
* an approximation: a record starting before the query end can sit at a higher
|
|
37
|
+
* offset than the linear-index entry past it (a long read reaching into the
|
|
38
|
+
* next window pins that entry low), so pruning a fetch this way would drop
|
|
39
|
+
* records. A forecast that is occasionally 20% under warns slightly early;
|
|
40
|
+
* a fetch that is occasionally short returns wrong data.
|
|
41
|
+
*
|
|
42
|
+
* An EMPTY prefix is that pin at its worst — the bound has landed at or before
|
|
43
|
+
* the query's own first chunk, so it orders nothing — and the answer there is
|
|
44
|
+
* every chunk rather than the batch floor. Without it this returns the floor on
|
|
45
|
+
* a file whose features are long against the linear-index interval, which is
|
|
46
|
+
* where the same forecast really does go wrong: ported to tabix-js and measured
|
|
47
|
+
* on the 1000 Genomes SV callset, whose 1.4Mb deletions pin the entry at the
|
|
48
|
+
* data start, it forecast 0.04MB against the 0.22MB the query read. On this
|
|
49
|
+
* corpus the fallback costs one fixture's win (chr22_nanopore, whose 10kb
|
|
50
|
+
* window keeps summing all 22 chunks) and no accuracy anywhere else.
|
|
51
|
+
*/
|
|
52
|
+
export function chunksLikelyRead(chunks, upperBoundBlockPosition) {
|
|
53
|
+
if (upperBoundBlockPosition === undefined ||
|
|
54
|
+
chunks.length <= MAX_CONCURRENT_CHUNK_READS) {
|
|
55
|
+
return chunks;
|
|
56
|
+
}
|
|
57
|
+
let n = 0;
|
|
58
|
+
while (n < chunks.length &&
|
|
59
|
+
chunks[n].minv.blockPosition < upperBoundBlockPosition) {
|
|
60
|
+
n++;
|
|
61
|
+
}
|
|
62
|
+
return n === 0 || n >= chunks.length
|
|
63
|
+
? chunks
|
|
64
|
+
: chunks.slice(0, Math.max(n, MAX_CONCURRENT_CHUNK_READS));
|
|
65
|
+
}
|
|
3
66
|
/**
|
|
4
67
|
* Merge and order the chunks a query resolved to.
|
|
5
68
|
*
|
|
@@ -10,10 +73,6 @@ import { VirtualOffset } from "./virtualOffset.js";
|
|
|
10
73
|
* underneath you. (The Chunk objects themselves are never mutated; a merged
|
|
11
74
|
* span produces a new instance.)
|
|
12
75
|
*/
|
|
13
|
-
// Re-exported so the internal import path stays './util.ts'. The
|
|
14
|
-
// implementation moved to @gmod/shared-read-cache, which needs it anyway --
|
|
15
|
-
// every consumer of that package was carrying an identical copy.
|
|
16
|
-
export { throwIfAborted } from '@gmod/shared-read-cache';
|
|
17
76
|
export function optimizeChunks(chunks, lowest) {
|
|
18
77
|
const n = chunks.length;
|
|
19
78
|
if (n === 0) {
|
package/esm/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gmod/bam",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.1",
|
|
4
4
|
"packageManager": "pnpm@11.15.1",
|
|
5
5
|
"description": "Parser for BAM and BAM index (bai) files",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@gmod/bgzf-filehandle": "^6.3.2",
|
|
55
|
-
"@gmod/shared-read-cache": "^1.4.
|
|
55
|
+
"@gmod/shared-read-cache": "^1.4.4",
|
|
56
56
|
"@jbrowse/quick-lru": "^7.3.5",
|
|
57
57
|
"crc": "^4.3.2",
|
|
58
58
|
"generic-filehandle2": "^2.2.1"
|
package/src/bai.ts
CHANGED
|
@@ -281,4 +281,20 @@ export default class BAI extends IndexFile<BaiParsed> {
|
|
|
281
281
|
dataPosition: linearDataPositions[i]!,
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
|
+
|
|
285
|
+
// The linear-index entry one window PAST the query: the smallest file offset
|
|
286
|
+
// of any record overlapping the window after it. Records the query wants are
|
|
287
|
+
// overwhelmingly below it, which is what makes it a usable forecast — but not
|
|
288
|
+
// a bound, because a long read reaching into that next window pins the entry
|
|
289
|
+
// at ITS offset, and records starting later (still before the query end) sit
|
|
290
|
+
// above it. chunksLikelyRead says why an estimate may use it and a fetch may
|
|
291
|
+
// not.
|
|
292
|
+
//
|
|
293
|
+
// undefined past the end of the linear index, i.e. for a query running to the
|
|
294
|
+
// end of the reference, where there is no next window to bound anything with.
|
|
295
|
+
protected getHighestChunk(refIndex: BaiRefIndex, max: number) {
|
|
296
|
+
const { linearBlockPositions } = refIndex
|
|
297
|
+
const i = (max >> BAI_LINEAR_SHIFT) + 1
|
|
298
|
+
return i < linearBlockPositions.length ? linearBlockPositions[i] : undefined
|
|
299
|
+
}
|
|
284
300
|
}
|
package/src/bamFile.ts
CHANGED
|
@@ -8,7 +8,12 @@ import CSI from './csi.ts'
|
|
|
8
8
|
import NullFilehandle from './nullFilehandle.ts'
|
|
9
9
|
import BAMFeature from './record.ts'
|
|
10
10
|
import { parseHeaderText } from './sam.ts'
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
MAX_CONCURRENT_CHUNK_READS,
|
|
13
|
+
appendInRange,
|
|
14
|
+
parseRefSeqs,
|
|
15
|
+
throwIfAborted,
|
|
16
|
+
} from './util.ts'
|
|
12
17
|
|
|
13
18
|
import type Chunk from './chunk.ts'
|
|
14
19
|
import type { BamOpts, BaseOpts } from './util.ts'
|
|
@@ -138,11 +143,6 @@ export const DEFAULT_MAX_CACHE_BYTES = 1024 * 1024 * 1024
|
|
|
138
143
|
// region a minute later should still hit (ADR 0015).
|
|
139
144
|
export const DEFAULT_CACHE_IDLE_TIMEOUT_MS = 3 * 60 * 1000
|
|
140
145
|
|
|
141
|
-
// How many of a query's chunks to read at once. Six is the HTTP/1.1
|
|
142
|
-
// per-host connection cap browsers enforce, so going much above it buys
|
|
143
|
-
// nothing on the transport that matters and only widens peak memory.
|
|
144
|
-
const MAX_CONCURRENT_CHUNK_READS = 6
|
|
145
|
-
|
|
146
146
|
export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
147
147
|
public renameRefSeq: (a: string) => string
|
|
148
148
|
public bam: GenericFilehandle
|
|
@@ -151,14 +151,15 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
151
151
|
public indexToChr?: { refName: string; length: number }[]
|
|
152
152
|
public index?: BAI | CSI
|
|
153
153
|
public htsget = false
|
|
154
|
-
|
|
154
|
+
|
|
155
155
|
/**
|
|
156
|
-
* The
|
|
157
|
-
*
|
|
158
|
-
* query to arrive would own a read all the others depend on — see
|
|
159
|
-
* {@link getHeader}.
|
|
156
|
+
* The parsed header, as a shared read — see {@link getHeader}. One entry,
|
|
157
|
+
* never evicted, which is what a memo is.
|
|
160
158
|
*/
|
|
161
|
-
private
|
|
159
|
+
private headerCache = new SharedReadCache<
|
|
160
|
+
string,
|
|
161
|
+
ReturnType<typeof parseHeaderText>
|
|
162
|
+
>({})
|
|
162
163
|
|
|
163
164
|
// Parsed features by chunk, bounded by decompressed bytes. Also the
|
|
164
165
|
// in-flight map: concurrent queries for the same chunk share one read rather
|
|
@@ -200,13 +201,21 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
200
201
|
* {@link DEFAULT_MAX_CACHE_BYTES}.
|
|
201
202
|
*
|
|
202
203
|
* A **retention** bound, not a bound on peak memory, and the difference is
|
|
203
|
-
* not small on deep data.
|
|
204
|
+
* not small on deep data. Four things sit outside it. A read still in
|
|
204
205
|
* flight is never evicted, and up to `MAX_CONCURRENT_CHUNK_READS` of those
|
|
205
206
|
* run at once; the last settled entry is kept whatever the budget; and a
|
|
206
207
|
* query holds every chunk it parsed until it returns, whether or not the
|
|
207
208
|
* cache still does. On 1000x long-read data a single chunk decompresses to
|
|
208
209
|
* 180MB and six in flight is 476MB, neither of which this number can bound.
|
|
209
210
|
*
|
|
211
|
+
* The fourth is that an entry is weighed ONCE, when its read settles, and
|
|
212
|
+
* records grow after that: `end`, `CIGAR` and `tags` each memoize onto the
|
|
213
|
+
* record the first time they are read, which is what a renderer does to
|
|
214
|
+
* every visible read. Measured on `chr22_nanopore_subset.bam`, a chunk
|
|
215
|
+
* weighed at 20.4MB retained a further 7.8MB — +38% — once its 383 records
|
|
216
|
+
* had been consumed. So a budget of N bytes can hold appreciably more than
|
|
217
|
+
* N; the number is a bound on decompressed bytes, not on the heap.
|
|
218
|
+
*
|
|
210
219
|
* Set it too low and the cache does not degrade gracefully — it inverts. A
|
|
211
220
|
* budget under one query's working set evicts each chunk before the next pan
|
|
212
221
|
* reuses it, so the hit rate is zero, the full re-decompress is paid on every
|
|
@@ -356,62 +365,28 @@ export default class BamFile<T extends BamRecordLike = BAMFeature> {
|
|
|
356
365
|
* shared between queries, and the third place in this file where a
|
|
357
366
|
* cancellation could leak from the query that asked for it to a query that
|
|
358
367
|
* did not. `getHeaderPre` threads `opts` into both the index parse and the
|
|
359
|
-
* BAM read, so
|
|
360
|
-
* query depends on: when it pans away, every
|
|
361
|
-
* abort even though its own signal is
|
|
368
|
+
* BAM read, so a bare memoized promise makes the first query to arrive the
|
|
369
|
+
* owner of a read every other query depends on: when it pans away, every
|
|
370
|
+
* concurrent query fails with its abort even though its own signal is
|
|
371
|
+
* untouched.
|
|
372
|
+
*
|
|
373
|
+
* The cache is what avoids that, on the same terms as the chunk reads: the
|
|
374
|
+
* parse runs under a signal of its own and is cancelled only once every
|
|
375
|
+
* caller waiting on it has given up, so an owner's abort is reported to the
|
|
376
|
+
* owner alone and the bystanders get the header from the read already in
|
|
377
|
+
* flight. There is no retry here because there is nothing to retry — the
|
|
378
|
+
* parse a bystander joined is not cancelled by someone else's abort.
|
|
362
379
|
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
* one attempt so the pathological case is a duplicate parse rather than a
|
|
366
|
-
* recursion whose depth depends on how the aborts interleave.
|
|
380
|
+
* The fill is per call rather than on the cache so that the caller who
|
|
381
|
+
* starts the parse has its `onProgress` reach the index download inside it.
|
|
367
382
|
*
|
|
368
|
-
* SYNC: ~/src/gmod/tabix-js/src/tabixIndexedFile.ts getParsedHeader
|
|
369
|
-
* shape for the same reason.
|
|
383
|
+
* SYNC: ~/src/gmod/tabix-js/src/tabixIndexedFile.ts getParsedHeader,
|
|
384
|
+
* ~/src/gmod/bbi-js/src/bbi.ts getHeader — same shape for the same reason.
|
|
370
385
|
*/
|
|
371
|
-
|
|
372
|
-
opts
|
|
373
|
-
|
|
374
|
-
): Promise<Awaited<ReturnType<BamFile<T>['getHeaderPre']>>> {
|
|
375
|
-
throwIfAborted(opts?.signal)
|
|
376
|
-
const pending = this.headerP
|
|
377
|
-
if (!pending) {
|
|
378
|
-
return this.startHeaderParse(opts)
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// read before awaiting: the owner is forgotten as soon as the parse settles
|
|
382
|
-
const ownerSignal = this.headerSignal
|
|
383
|
-
try {
|
|
384
|
-
return await pending
|
|
385
|
-
} catch (e) {
|
|
386
|
-
if (retried || !ownerSignal?.aborted || opts?.signal?.aborted) {
|
|
387
|
-
throw e
|
|
388
|
-
}
|
|
389
|
-
return this.getHeader(opts, true)
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
private startHeaderParse(opts?: BaseOpts) {
|
|
394
|
-
const pending = this.getHeaderPre(opts)
|
|
395
|
-
this.headerP = pending
|
|
396
|
-
this.headerSignal = opts?.signal
|
|
397
|
-
// Drop a rejection rather than keeping it, so one transient failure does not
|
|
398
|
-
// poison the header for the lifetime of the file. Both branches are
|
|
399
|
-
// identity-checked so a retry started after this settles is not cleared by
|
|
400
|
-
// the attempt it already replaced.
|
|
401
|
-
pending.then(
|
|
402
|
-
() => {
|
|
403
|
-
if (this.headerP === pending) {
|
|
404
|
-
this.headerSignal = undefined
|
|
405
|
-
}
|
|
406
|
-
},
|
|
407
|
-
() => {
|
|
408
|
-
if (this.headerP === pending) {
|
|
409
|
-
this.headerP = undefined
|
|
410
|
-
this.headerSignal = undefined
|
|
411
|
-
}
|
|
412
|
-
},
|
|
386
|
+
getHeader(opts?: BaseOpts) {
|
|
387
|
+
return this.headerCache.get('header', opts?.signal, signal =>
|
|
388
|
+
this.getHeaderPre({ ...opts, signal }),
|
|
413
389
|
)
|
|
414
|
-
return pending
|
|
415
390
|
}
|
|
416
391
|
|
|
417
392
|
async getHeaderText(opts: BaseOpts = {}) {
|
package/src/csi.ts
CHANGED
|
@@ -193,6 +193,12 @@ export default class CSI extends IndexFile {
|
|
|
193
193
|
return ZERO_OFFSET
|
|
194
194
|
}
|
|
195
195
|
|
|
196
|
+
// ...and so there is nothing to bound the far end of a query with either, so
|
|
197
|
+
// estimatedBytesForRegions keeps summing every chunk on a CSI-indexed file.
|
|
198
|
+
protected getHighestChunk() {
|
|
199
|
+
return undefined
|
|
200
|
+
}
|
|
201
|
+
|
|
196
202
|
/**
|
|
197
203
|
* calculate the list of bins that may overlap with region [beg,end)
|
|
198
204
|
* (zero-based half-open). Follows the reference implementation in hts-specs
|
package/src/htsget.ts
CHANGED
|
@@ -132,8 +132,26 @@ export default class HtsgetFile<
|
|
|
132
132
|
* `headers` field, which is applied either way.
|
|
133
133
|
*/
|
|
134
134
|
fetch?: Fetcher
|
|
135
|
+
/**
|
|
136
|
+
* Passed on to {@link BamFile}, where it bounds `chunkFeatureCache` —
|
|
137
|
+
* which htsget mode never fills. `getRecordsForRange` below reads whole
|
|
138
|
+
* ticket blocks rather than index chunks, so nothing here reaches that
|
|
139
|
+
* cache and neither of these options changes anything today. Accepted
|
|
140
|
+
* rather than rejected because the inherited cache is the thing that
|
|
141
|
+
* should eventually hold ticket responses (there is no read sharing or
|
|
142
|
+
* reuse in htsget mode at all right now), and that is when they start to
|
|
143
|
+
* bite.
|
|
144
|
+
*/
|
|
145
|
+
maxCacheBytes?: number
|
|
146
|
+
/** see {@link maxCacheBytes}: inherited, and inert in htsget mode */
|
|
147
|
+
cacheIdleTimeoutMs?: number
|
|
135
148
|
}) {
|
|
136
|
-
super({
|
|
149
|
+
super({
|
|
150
|
+
htsget: true,
|
|
151
|
+
recordClass: args.recordClass,
|
|
152
|
+
maxCacheBytes: args.maxCacheBytes,
|
|
153
|
+
cacheIdleTimeoutMs: args.cacheIdleTimeoutMs,
|
|
154
|
+
})
|
|
137
155
|
this.baseUrl = args.baseUrl
|
|
138
156
|
this.trackId = args.trackId
|
|
139
157
|
this.fetchFn = args.fetch ?? ((input, init) => fetch(input, init))
|