@gmod/gbz-base 1.1.0 → 2.0.0
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 +123 -24
- package/dist/cli.js +12 -11
- package/dist/cli.js.map +1 -1
- package/dist/db.d.ts +18 -9
- package/dist/db.js +95 -4
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/pathName.d.ts +17 -0
- package/dist/pathName.js +33 -0
- package/dist/pathName.js.map +1 -0
- package/dist/query.d.ts +8 -10
- package/dist/query.js +7 -19
- package/dist/query.js.map +1 -1
- package/dist/sqlite/btree.d.ts +2 -0
- package/dist/sqlite/btree.js +48 -18
- package/dist/sqlite/btree.js.map +1 -1
- package/dist/subgraph.d.ts +25 -12
- package/dist/subgraph.js +33 -16
- package/dist/subgraph.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +19 -13
- package/src/db.ts +153 -13
- package/src/index.ts +12 -10
- package/src/pathName.ts +54 -0
- package/src/query.ts +17 -32
- package/src/sqlite/btree.ts +61 -17
- package/src/subgraph.ts +59 -30
- package/tools/haplotype-index/src/main.rs +13 -5
package/src/query.ts
CHANGED
|
@@ -1,29 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pathNameFor } from './pathName.ts'
|
|
2
2
|
import { Subgraph } from './subgraph.ts'
|
|
3
3
|
|
|
4
|
-
import type { GBZBase
|
|
4
|
+
import type { GBZBase } from './db.ts'
|
|
5
|
+
import type { PathQuery } from './pathName.ts'
|
|
5
6
|
import type { HaplotypeOutput, SnarlOutput } from './subgraph.ts'
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
-
context?: number
|
|
9
|
-
haplotypes?: HaplotypeOutput
|
|
10
|
-
snarls?: SnarlOutput
|
|
11
|
-
limit?: number
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface PathQuery {
|
|
15
|
-
sample?: string
|
|
16
|
-
contig: string
|
|
17
|
-
haplotype?: number
|
|
18
|
-
}
|
|
8
|
+
export type { PathQuery } from './pathName.ts'
|
|
19
9
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
10
|
+
export interface QueryOptions {
|
|
11
|
+
context?: number | undefined
|
|
12
|
+
haplotypes?: HaplotypeOutput | undefined
|
|
13
|
+
snarls?: SnarlOutput | undefined
|
|
14
|
+
limit?: number | undefined
|
|
15
|
+
signal?: AbortSignal | undefined
|
|
27
16
|
}
|
|
28
17
|
|
|
29
18
|
export async function subgraphAtOffset(
|
|
@@ -32,9 +21,8 @@ export async function subgraphAtOffset(
|
|
|
32
21
|
offset: number,
|
|
33
22
|
opts: QueryOptions = {},
|
|
34
23
|
) {
|
|
35
|
-
const subgraph = new Subgraph(db)
|
|
36
|
-
|
|
37
|
-
const reference = await subgraph.pathPosition(pathName(query, offset))
|
|
24
|
+
const subgraph = new Subgraph(db, opts)
|
|
25
|
+
const reference = await subgraph.pathPosition(pathNameFor(query, offset))
|
|
38
26
|
await subgraph.aroundPosition(
|
|
39
27
|
reference.position.handle,
|
|
40
28
|
reference.position.nodeOffset,
|
|
@@ -52,9 +40,8 @@ export async function subgraphInInterval(
|
|
|
52
40
|
end: number,
|
|
53
41
|
opts: QueryOptions = {},
|
|
54
42
|
) {
|
|
55
|
-
const subgraph = new Subgraph(db)
|
|
56
|
-
|
|
57
|
-
const reference = await subgraph.pathPosition(pathName(query, start))
|
|
43
|
+
const subgraph = new Subgraph(db, opts)
|
|
44
|
+
const reference = await subgraph.pathPosition(pathNameFor(query, start))
|
|
58
45
|
await subgraph.aroundInterval(
|
|
59
46
|
reference.position,
|
|
60
47
|
end - start,
|
|
@@ -80,8 +67,7 @@ export async function subgraphAroundNodes(
|
|
|
80
67
|
'Overlapping snarls cannot be extracted for a node-based query with multiple nodes',
|
|
81
68
|
)
|
|
82
69
|
}
|
|
83
|
-
const subgraph = new Subgraph(db)
|
|
84
|
-
subgraph.limit = opts.limit
|
|
70
|
+
const subgraph = new Subgraph(db, opts)
|
|
85
71
|
await subgraph.aroundNodes(nodes, opts.context ?? 100)
|
|
86
72
|
await subgraph.extractSnarls(snarls)
|
|
87
73
|
subgraph.extractPaths(undefined, haplotypes)
|
|
@@ -92,14 +78,13 @@ export async function subgraphBetween(
|
|
|
92
78
|
db: GBZBase,
|
|
93
79
|
start: number,
|
|
94
80
|
end: number,
|
|
95
|
-
opts: Pick<QueryOptions, 'haplotypes' | 'limit'> = {},
|
|
81
|
+
opts: Pick<QueryOptions, 'haplotypes' | 'limit' | 'signal'> = {},
|
|
96
82
|
) {
|
|
97
83
|
const haplotypes = opts.haplotypes ?? 'all'
|
|
98
84
|
if (haplotypes === 'reference-only') {
|
|
99
85
|
throw new Error('Cannot output a reference path in a node-based query')
|
|
100
86
|
}
|
|
101
|
-
const subgraph = new Subgraph(db)
|
|
102
|
-
subgraph.limit = opts.limit
|
|
87
|
+
const subgraph = new Subgraph(db, opts)
|
|
103
88
|
await subgraph.betweenNodes(start, end)
|
|
104
89
|
subgraph.extractPaths(undefined, haplotypes)
|
|
105
90
|
return subgraph
|
package/src/sqlite/btree.ts
CHANGED
|
@@ -15,8 +15,20 @@ interface PageHeader {
|
|
|
15
15
|
cellPointers: number
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function readUint16(page: Uint8Array, offset: number) {
|
|
19
|
+
return page[offset]! * 256 + page[offset + 1]!
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readUint32(page: Uint8Array, offset: number) {
|
|
23
|
+
return (
|
|
24
|
+
page[offset]! * 16777216 +
|
|
25
|
+
page[offset + 1]! * 65536 +
|
|
26
|
+
page[offset + 2]! * 256 +
|
|
27
|
+
page[offset + 3]!
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
function readHeader(page: Uint8Array, start: number): PageHeader {
|
|
19
|
-
const view = new DataView(page.buffer, page.byteOffset, page.byteLength)
|
|
20
32
|
const type = page[start]
|
|
21
33
|
if (
|
|
22
34
|
type !== INTERIOR_INDEX &&
|
|
@@ -29,25 +41,27 @@ function readHeader(page: Uint8Array, start: number): PageHeader {
|
|
|
29
41
|
const interior = type === INTERIOR_INDEX || type === INTERIOR_TABLE
|
|
30
42
|
return {
|
|
31
43
|
type,
|
|
32
|
-
cellCount:
|
|
33
|
-
rightChild: interior ?
|
|
44
|
+
cellCount: readUint16(page, start + 3),
|
|
45
|
+
rightChild: interior ? readUint32(page, start + 8) : 0,
|
|
34
46
|
cellPointers: start + (interior ? 12 : 8),
|
|
35
47
|
}
|
|
36
48
|
}
|
|
37
49
|
|
|
38
50
|
function cellOffset(page: Uint8Array, header: PageHeader, index: number) {
|
|
39
|
-
|
|
40
|
-
return view.getUint16(header.cellPointers + 2 * index)
|
|
51
|
+
return readUint16(page, header.cellPointers + 2 * index)
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
interface IndexCell {
|
|
55
|
+
values: SqlValue[]
|
|
56
|
+
leftChild: number
|
|
46
57
|
}
|
|
47
58
|
|
|
59
|
+
const MAX_DECODED_INDEX_PAGES = 4096
|
|
60
|
+
|
|
48
61
|
export class BTree {
|
|
49
62
|
private readonly usable: number
|
|
50
63
|
private pager: Pager
|
|
64
|
+
private decodedIndexPages = new Map<number, (IndexCell | undefined)[]>()
|
|
51
65
|
|
|
52
66
|
constructor(pager: Pager, reservedBytes: number) {
|
|
53
67
|
this.pager = pager
|
|
@@ -179,12 +193,42 @@ export class BTree {
|
|
|
179
193
|
}
|
|
180
194
|
}
|
|
181
195
|
|
|
182
|
-
private
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
private decodedCells(pageNumber: number, header: PageHeader) {
|
|
197
|
+
let cells = this.decodedIndexPages.get(pageNumber)
|
|
198
|
+
if (cells) {
|
|
199
|
+
this.decodedIndexPages.delete(pageNumber)
|
|
200
|
+
} else {
|
|
201
|
+
cells = new Array<IndexCell | undefined>(header.cellCount)
|
|
202
|
+
if (this.decodedIndexPages.size >= MAX_DECODED_INDEX_PAGES) {
|
|
203
|
+
const oldest = this.decodedIndexPages.keys().next().value
|
|
204
|
+
if (oldest !== undefined) {
|
|
205
|
+
this.decodedIndexPages.delete(oldest)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.decodedIndexPages.set(pageNumber, cells)
|
|
210
|
+
return cells
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private async indexCell(
|
|
214
|
+
pageNumber: number,
|
|
215
|
+
page: Uint8Array,
|
|
216
|
+
header: PageHeader,
|
|
217
|
+
index: number,
|
|
218
|
+
): Promise<IndexCell> {
|
|
219
|
+
const cells = this.decodedCells(pageNumber, header)
|
|
220
|
+
let cell = cells[index]
|
|
221
|
+
if (!cell) {
|
|
222
|
+
const offset = cellOffset(page, header, index)
|
|
223
|
+
const interior = header.type === INTERIOR_INDEX
|
|
224
|
+
const [size, afterSize] = readVarint(page, interior ? offset + 4 : offset)
|
|
225
|
+
cell = {
|
|
226
|
+
values: decodeRecord(await this.payload(page, afterSize, size, true)),
|
|
227
|
+
leftChild: interior ? readUint32(page, offset) : 0,
|
|
228
|
+
}
|
|
229
|
+
cells[index] = cell
|
|
230
|
+
}
|
|
231
|
+
return cell
|
|
188
232
|
}
|
|
189
233
|
|
|
190
234
|
async *indexScanFrom(
|
|
@@ -196,7 +240,7 @@ export class BTree {
|
|
|
196
240
|
let high = header.cellCount
|
|
197
241
|
while (first < high) {
|
|
198
242
|
const mid = (first + high) >> 1
|
|
199
|
-
const cell = await this.indexCell(page, header, mid)
|
|
243
|
+
const cell = await this.indexCell(root, page, header, mid)
|
|
200
244
|
if (compareKey(cell.values, low) < 0) {
|
|
201
245
|
first = mid + 1
|
|
202
246
|
} else {
|
|
@@ -204,7 +248,7 @@ export class BTree {
|
|
|
204
248
|
}
|
|
205
249
|
}
|
|
206
250
|
for (let i = first; i < header.cellCount; i++) {
|
|
207
|
-
const cell = await this.indexCell(page, header, i)
|
|
251
|
+
const cell = await this.indexCell(root, page, header, i)
|
|
208
252
|
if (header.type === INTERIOR_INDEX) {
|
|
209
253
|
yield* this.indexScanFrom(cell.leftChild, low)
|
|
210
254
|
}
|
|
@@ -228,7 +272,7 @@ export class BTree {
|
|
|
228
272
|
let child = 0
|
|
229
273
|
while (low < high) {
|
|
230
274
|
const mid = (low + high) >> 1
|
|
231
|
-
const cell = await this.indexCell(page, header, mid)
|
|
275
|
+
const cell = await this.indexCell(pageNumber, page, header, mid)
|
|
232
276
|
if (compareKey(cell.values, key) <= 0) {
|
|
233
277
|
best = cell.values
|
|
234
278
|
low = mid + 1
|
package/src/subgraph.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { formatPathName } from './db.ts'
|
|
2
1
|
import {
|
|
3
2
|
ENDMARKER,
|
|
4
3
|
edgeIsCanonical,
|
|
@@ -16,16 +15,12 @@ import {
|
|
|
16
15
|
} from './gbwt/node.ts'
|
|
17
16
|
import { gfaHeaderLines, sha256Hex, subgraphName } from './graphName.ts'
|
|
18
17
|
import { weightedLcs } from './lcs.ts'
|
|
18
|
+
import { formatPathName } from './pathName.ts'
|
|
19
19
|
|
|
20
|
-
import type {
|
|
21
|
-
GBZBase,
|
|
22
|
-
GbzPath,
|
|
23
|
-
GbzRecord,
|
|
24
|
-
HaplotypeSample,
|
|
25
|
-
PathName,
|
|
26
|
-
} from './db.ts'
|
|
20
|
+
import type { GBZBase, GbzPath, GbzRecord, HaplotypeSample } from './db.ts'
|
|
27
21
|
import type { NodeSide, Orientation } from './gbwt/node.ts'
|
|
28
22
|
import type { Pos } from './gbwt/record.ts'
|
|
23
|
+
import type { PathName } from './pathName.ts'
|
|
29
24
|
|
|
30
25
|
export type HaplotypeOutput = 'all' | 'distinct' | 'reference-only' | 'none'
|
|
31
26
|
|
|
@@ -86,12 +81,8 @@ export interface SubgraphJson {
|
|
|
86
81
|
paths: SubgraphPath[]
|
|
87
82
|
}
|
|
88
83
|
|
|
89
|
-
export interface
|
|
90
|
-
pathHandle: number | undefined
|
|
91
|
-
name: PathName | undefined
|
|
84
|
+
export interface AlignmentSpan {
|
|
92
85
|
strand: '+' | '-'
|
|
93
|
-
hapStart: number | undefined
|
|
94
|
-
hapEnd: number | undefined
|
|
95
86
|
refStart: number
|
|
96
87
|
refEnd: number
|
|
97
88
|
cigar: string
|
|
@@ -100,8 +91,27 @@ export interface HaplotypeAlignment {
|
|
|
100
91
|
start: Pos
|
|
101
92
|
}
|
|
102
93
|
|
|
103
|
-
export
|
|
104
|
-
|
|
94
|
+
export type HaplotypeAlignment = AlignmentSpan &
|
|
95
|
+
(
|
|
96
|
+
| {
|
|
97
|
+
resolved: true
|
|
98
|
+
name: PathName
|
|
99
|
+
label: string
|
|
100
|
+
pathHandle: number
|
|
101
|
+
hapStart: number
|
|
102
|
+
hapEnd: number
|
|
103
|
+
}
|
|
104
|
+
| { resolved: false }
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
export interface SubgraphOutputOptions {
|
|
108
|
+
cigar?: boolean | undefined
|
|
109
|
+
names?: 'anonymous' | 'resolved' | undefined
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface SubgraphOptions {
|
|
113
|
+
limit?: number | undefined
|
|
114
|
+
signal?: AbortSignal | undefined
|
|
105
115
|
}
|
|
106
116
|
|
|
107
117
|
function sideBefore(
|
|
@@ -183,7 +193,6 @@ export class Subgraph {
|
|
|
183
193
|
private refInterval: [number, number] | undefined
|
|
184
194
|
private refIndexCache: Map<number, number[]> | undefined
|
|
185
195
|
private refPrefixCache: number[] | undefined
|
|
186
|
-
limit: number | undefined
|
|
187
196
|
readonly stats = {
|
|
188
197
|
orderedAlignments: 0,
|
|
189
198
|
lcsAlignments: 0,
|
|
@@ -192,9 +201,13 @@ export class Subgraph {
|
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
private db: GBZBase
|
|
204
|
+
private readonly limit: number | undefined
|
|
205
|
+
private readonly signal: AbortSignal | undefined
|
|
195
206
|
|
|
196
|
-
constructor(db: GBZBase) {
|
|
207
|
+
constructor(db: GBZBase, opts: SubgraphOptions = {}) {
|
|
197
208
|
this.db = db
|
|
209
|
+
this.limit = opts.limit
|
|
210
|
+
this.signal = opts.signal
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
get nodeCount() {
|
|
@@ -236,6 +249,7 @@ export class Subgraph {
|
|
|
236
249
|
}
|
|
237
250
|
|
|
238
251
|
private async addNode(id: number) {
|
|
252
|
+
this.signal?.throwIfAborted()
|
|
239
253
|
if (this.limit !== undefined && this.nodeCount >= this.limit) {
|
|
240
254
|
throw new Error(`Subgraph size limit of ${this.limit} nodes exceeded`)
|
|
241
255
|
}
|
|
@@ -800,6 +814,7 @@ export class Subgraph {
|
|
|
800
814
|
let current: number | undefined = start
|
|
801
815
|
let pos: Pos | undefined
|
|
802
816
|
while (anchor === undefined) {
|
|
817
|
+
this.signal?.throwIfAborted()
|
|
803
818
|
if (current !== undefined) {
|
|
804
819
|
if (visited.has(current)) {
|
|
805
820
|
break
|
|
@@ -1094,24 +1109,17 @@ export class Subgraph {
|
|
|
1094
1109
|
last -= 1
|
|
1095
1110
|
}
|
|
1096
1111
|
const identity = info.identity
|
|
1097
|
-
const
|
|
1112
|
+
const walkStrand =
|
|
1098
1113
|
info.path.some(handle => isReverse(handle)) &&
|
|
1099
1114
|
!info.path.some(handle => !isReverse(handle))
|
|
1100
1115
|
? '-'
|
|
1101
1116
|
: '+'
|
|
1102
|
-
|
|
1103
|
-
pathHandle: identity?.pathHandle,
|
|
1104
|
-
name: identity?.name,
|
|
1117
|
+
const span: AlignmentSpan = {
|
|
1105
1118
|
strand: identity
|
|
1106
1119
|
? identity.orientation === 'forward'
|
|
1107
1120
|
? '+'
|
|
1108
1121
|
: '-'
|
|
1109
|
-
:
|
|
1110
|
-
hapStart: identity
|
|
1111
|
-
? identity.name.fragment + identity.hapStart
|
|
1112
|
-
: undefined,
|
|
1113
|
-
hapEnd: identity ? identity.name.fragment + identity.hapEnd : undefined,
|
|
1114
|
-
start: info.positions[0]!,
|
|
1122
|
+
: walkStrand,
|
|
1115
1123
|
refStart: reference.start + leading,
|
|
1116
1124
|
refEnd: reference.start + refTotal - trailing,
|
|
1117
1125
|
cigar: edits
|
|
@@ -1120,7 +1128,26 @@ export class Subgraph {
|
|
|
1120
1128
|
.join(''),
|
|
1121
1129
|
weight: info.weight,
|
|
1122
1130
|
path: info.path,
|
|
1123
|
-
|
|
1131
|
+
start: info.positions[0]!,
|
|
1132
|
+
}
|
|
1133
|
+
if (identity) {
|
|
1134
|
+
const hapStart = identity.name.fragment + identity.hapStart
|
|
1135
|
+
const hapEnd = identity.name.fragment + identity.hapEnd
|
|
1136
|
+
result.push({
|
|
1137
|
+
...span,
|
|
1138
|
+
resolved: true,
|
|
1139
|
+
name: identity.name,
|
|
1140
|
+
label: formatPathName(
|
|
1141
|
+
{ ...identity.name, fragment: hapStart },
|
|
1142
|
+
hapEnd,
|
|
1143
|
+
),
|
|
1144
|
+
pathHandle: identity.pathHandle,
|
|
1145
|
+
hapStart,
|
|
1146
|
+
hapEnd,
|
|
1147
|
+
})
|
|
1148
|
+
} else {
|
|
1149
|
+
result.push({ ...span, resolved: false })
|
|
1150
|
+
}
|
|
1124
1151
|
})
|
|
1125
1152
|
return result
|
|
1126
1153
|
}
|
|
@@ -1165,7 +1192,8 @@ export class Subgraph {
|
|
|
1165
1192
|
return sha256Hex(chunks)
|
|
1166
1193
|
}
|
|
1167
1194
|
|
|
1168
|
-
async toGFA(
|
|
1195
|
+
async toGFA(opts: SubgraphOutputOptions = {}) {
|
|
1196
|
+
const cigar = opts.cigar ?? false
|
|
1169
1197
|
const lines = [
|
|
1170
1198
|
this.refPath ? `H\tVN:Z:1.1\tRS:Z:${this.refPath.sample}` : 'H\tVN:Z:1.1',
|
|
1171
1199
|
...gfaHeaderLines(
|
|
@@ -1244,7 +1272,8 @@ export class Subgraph {
|
|
|
1244
1272
|
return `${lines.join('\n')}\n`
|
|
1245
1273
|
}
|
|
1246
1274
|
|
|
1247
|
-
|
|
1275
|
+
toSubgraphJson(opts: SubgraphOutputOptions = {}): SubgraphJson {
|
|
1276
|
+
const cigar = opts.cigar ?? false
|
|
1248
1277
|
const handles = this.sortedHandles()
|
|
1249
1278
|
const nodes = handles
|
|
1250
1279
|
.filter(handle => !isReverse(handle))
|
|
@@ -208,15 +208,22 @@ fn orientations(args: &Args) -> Vec<Orientation> {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
fn walk_paths(source: &dyn PathSource, handles: std::ops::Range<usize>, args: &Args) -> (Vec<Sample>, Vec<(usize, usize)>) {
|
|
211
|
+
fn walk_paths(source: &dyn PathSource, handles: std::ops::Range<usize>, args: &Args, label: &str) -> (Vec<Sample>, Vec<(usize, usize)>) {
|
|
212
212
|
let mut samples = Vec::new();
|
|
213
213
|
let mut lengths = Vec::new();
|
|
214
|
-
|
|
214
|
+
let started = Instant::now();
|
|
215
|
+
let total = handles.len();
|
|
216
|
+
let mut walked_bp: usize = 0;
|
|
217
|
+
for (done, path_handle) in handles.enumerate() {
|
|
215
218
|
let mut length = 0;
|
|
216
219
|
for &orientation in orientations(args).iter() {
|
|
217
220
|
length = walk(source, path_handle, orientation, args.interval, &mut samples);
|
|
218
221
|
}
|
|
222
|
+
walked_bp += length;
|
|
219
223
|
lengths.push((path_handle, length));
|
|
224
|
+
if (done + 1) % 500 == 0 || done + 1 == total {
|
|
225
|
+
eprintln!("{}: {} / {} paths, {:.2} Gbp, {} samples, {:.0} s", label, done + 1, total, walked_bp as f64 / 1e9, samples.len(), started.elapsed().as_secs_f64());
|
|
226
|
+
}
|
|
220
227
|
}
|
|
221
228
|
(samples, lengths)
|
|
222
229
|
}
|
|
@@ -230,8 +237,9 @@ fn walk_gbz(graph: &GBZ, paths: usize, args: &Args) -> (Vec<Sample>, Vec<(usize,
|
|
|
230
237
|
let range = (t * chunk).min(paths)..((t + 1) * chunk).min(paths);
|
|
231
238
|
scope.spawn(move || {
|
|
232
239
|
let source = GbzSource { graph };
|
|
233
|
-
let
|
|
234
|
-
|
|
240
|
+
let label = format!("thread {} (paths {}..{})", t, range.start, range.end);
|
|
241
|
+
let result = walk_paths(&source, range.clone(), args, &label);
|
|
242
|
+
eprintln!("{} done in {:.0} s", label, started.elapsed().as_secs_f64());
|
|
235
243
|
result
|
|
236
244
|
})
|
|
237
245
|
})
|
|
@@ -341,7 +349,7 @@ fn main() {
|
|
|
341
349
|
});
|
|
342
350
|
let interface = GraphInterface::new(&database).unwrap();
|
|
343
351
|
let source = DbSource { interface: std::cell::RefCell::new(interface) };
|
|
344
|
-
let (samples, lengths) = walk_paths(&source, 0..paths, &args);
|
|
352
|
+
let (samples, lengths) = walk_paths(&source, 0..paths, &args, "database walk");
|
|
345
353
|
(samples, lengths, paths)
|
|
346
354
|
}
|
|
347
355
|
};
|