querysub 0.356.0 → 0.358.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/.cursorrules +9 -0
- package/bin/movelogs.js +4 -0
- package/package.json +13 -6
- package/scripts/postinstall.js +23 -0
- package/src/-a-archives/archiveCache.ts +10 -12
- package/src/-a-archives/archives.ts +29 -0
- package/src/-a-archives/archivesBackBlaze.ts +60 -12
- package/src/-a-archives/archivesDisk.ts +39 -13
- package/src/-a-archives/archivesLimitedCache.ts +21 -0
- package/src/-a-archives/archivesMemoryCache.ts +374 -0
- package/src/-a-archives/archivesPrivateFileSystem.ts +22 -0
- package/src/-g-core-values/NodeCapabilities.ts +3 -0
- package/src/0-path-value-core/auditLogs.ts +5 -1
- package/src/0-path-value-core/pathValueCore.ts +7 -7
- package/src/4-dom/qreact.tsx +1 -0
- package/src/4-querysub/Querysub.ts +1 -5
- package/src/config.ts +5 -0
- package/src/deployManager/components/MachineDetailPage.tsx +43 -2
- package/src/deployManager/components/MachinesListPage.tsx +10 -2
- package/src/deployManager/machineApplyMainCode.ts +3 -3
- package/src/deployManager/machineSchema.ts +39 -0
- package/src/diagnostics/MachineThreadInfo.tsx +235 -0
- package/src/diagnostics/NodeViewer.tsx +5 -3
- package/src/diagnostics/logs/FastArchiveAppendable.ts +79 -42
- package/src/diagnostics/logs/FastArchiveController.ts +102 -63
- package/src/diagnostics/logs/FastArchiveViewer.tsx +36 -8
- package/src/diagnostics/logs/IndexedLogs/BufferIndex.ts +462 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.cpp +327 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.d.ts +18 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexCPP.js +1 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexHelpers.ts +222 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexLogsOptimizationConstants.ts +22 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat +1145 -0
- package/src/diagnostics/logs/IndexedLogs/BufferIndexWAT.wat.d.ts +178 -0
- package/src/diagnostics/logs/IndexedLogs/BufferListStreamer.ts +208 -0
- package/src/diagnostics/logs/IndexedLogs/BufferUnitIndex.ts +716 -0
- package/src/diagnostics/logs/IndexedLogs/BufferUnitSet.ts +146 -0
- package/src/diagnostics/logs/IndexedLogs/FilePathSelector.tsx +569 -0
- package/src/diagnostics/logs/IndexedLogs/FindProgressTracker.ts +45 -0
- package/src/diagnostics/logs/IndexedLogs/IndexedLogs.ts +685 -0
- package/src/diagnostics/logs/IndexedLogs/LogStreamer.ts +47 -0
- package/src/diagnostics/logs/IndexedLogs/LogViewer3.tsx +901 -0
- package/src/diagnostics/logs/IndexedLogs/TimeFileTree.ts +236 -0
- package/src/diagnostics/logs/IndexedLogs/binding.gyp +23 -0
- package/src/diagnostics/logs/IndexedLogs/moveIndexLogsToPublic.ts +251 -0
- package/src/diagnostics/logs/IndexedLogs/moveLogsEntry.ts +10 -0
- package/src/diagnostics/logs/LogViewer2.tsx +120 -55
- package/src/diagnostics/logs/TimeRangeSelector.tsx +5 -2
- package/src/diagnostics/logs/diskLogger.ts +32 -48
- package/src/diagnostics/logs/errorNotifications/ErrorNotificationController.ts +3 -2
- package/src/diagnostics/logs/errorNotifications/errorDigests.tsx +1 -0
- package/src/diagnostics/logs/errorNotifications2/errorNotifications2.ts +0 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/LifeCyclePages.tsx +150 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/lifeCycles.tsx +150 -15
- package/src/diagnostics/logs/lifeCycleAnalysis/test.ts +0 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat +106 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/test.wat.d.ts +2 -0
- package/src/diagnostics/logs/lifeCycleAnalysis/testHoist.ts +5 -0
- package/src/diagnostics/logs/logViewerExtractField.ts +2 -3
- package/src/diagnostics/managementPages.tsx +10 -0
- package/src/diagnostics/trackResources.ts +1 -1
- package/src/functional/limitProcessing.ts +39 -0
- package/src/misc/lz4_wasm_nodejs.d.ts +34 -0
- package/src/misc/lz4_wasm_nodejs.js +178 -0
- package/src/misc/lz4_wasm_nodejs_bg.js +94 -0
- package/src/misc/lz4_wasm_nodejs_bg.wasm +0 -0
- package/src/misc/lz4_wasm_nodejs_bg.wasm.d.ts +15 -0
- package/src/storage/CompressedStream.ts +13 -0
- package/src/storage/LZ4.ts +32 -0
- package/src/storage/ZSTD.ts +10 -0
- package/src/wat/watCompiler.ts +1716 -0
- package/src/wat/watGrammar.pegjs +93 -0
- package/src/wat/watHandler.ts +179 -0
- package/src/wat/watInstructions.txt +707 -0
- package/src/zip.ts +3 -89
- package/src/diagnostics/logs/lifeCycleAnalysis/spec.md +0 -125
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { WatModuleExports } from "../../../wat/watHandler";
|
|
2
|
+
|
|
3
|
+
export interface UnitRefWatModule extends WatModuleExports {
|
|
4
|
+
/**
|
|
5
|
+
* Populate Units From Block: Extract units from concatenated block of buffers
|
|
6
|
+
* Block format: [count, length1, length2, ..., lengthN, buffer1_bytes, buffer2_bytes, ..., bufferN_bytes]
|
|
7
|
+
* @param blockDataPtr Pointer to concatenated block data
|
|
8
|
+
* @param blockDataSize Total size of block data in bytes
|
|
9
|
+
* @param blockIndex Block index value to store
|
|
10
|
+
* @param unitsOutputPtr Pointer to units output array
|
|
11
|
+
* @param bufferIndicesOutputPtr Pointer to buffer indices output array
|
|
12
|
+
* @param blocksOutputPtr Pointer to blocks output array
|
|
13
|
+
* @param startOffset Starting write position in output arrays
|
|
14
|
+
* @returns Number of units written
|
|
15
|
+
*/
|
|
16
|
+
populate_units_from_block(
|
|
17
|
+
blockDataPtr: bigint,
|
|
18
|
+
blockDataSize: number,
|
|
19
|
+
blockIndex: number,
|
|
20
|
+
unitsOutputPtr: bigint,
|
|
21
|
+
bufferIndicesOutputPtr: bigint,
|
|
22
|
+
blocksOutputPtr: bigint,
|
|
23
|
+
startOffset: number
|
|
24
|
+
): number;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Populate Units From Block (Loop Unrolled): Extract units from concatenated block of buffers
|
|
28
|
+
* Block format: [count, length1, length2, ..., lengthN, buffer1_bytes, buffer2_bytes, ..., bufferN_bytes]
|
|
29
|
+
* Uses loop unrolling to process 4 units at a time with optimized fast path for non-zero units
|
|
30
|
+
* @param blockDataPtr Pointer to concatenated block data
|
|
31
|
+
* @param blockDataSize Total size of block data in bytes
|
|
32
|
+
* @param blockIndex Block index value to store
|
|
33
|
+
* @param unitsOutputPtr Pointer to units output array
|
|
34
|
+
* @param bufferIndicesOutputPtr Pointer to buffer indices output array
|
|
35
|
+
* @param blocksOutputPtr Pointer to blocks output array
|
|
36
|
+
* @param startOffset Starting write position in output arrays
|
|
37
|
+
* @returns Number of units written
|
|
38
|
+
*/
|
|
39
|
+
populate_units_from_block_simd(
|
|
40
|
+
blockDataPtr: bigint,
|
|
41
|
+
blockDataSize: number,
|
|
42
|
+
blockIndex: number,
|
|
43
|
+
unitsOutputPtr: bigint,
|
|
44
|
+
bufferIndicesOutputPtr: bigint,
|
|
45
|
+
blocksOutputPtr: bigint,
|
|
46
|
+
startOffset: number
|
|
47
|
+
): number;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Populate Units From Buffer: Extract units from a buffer into three parallel arrays
|
|
51
|
+
* @param bufferPtr Pointer to source buffer bytes
|
|
52
|
+
* @param bufferLength Length of source buffer in bytes
|
|
53
|
+
* @param bufferIndex Buffer index value to store
|
|
54
|
+
* @param block Block value to store
|
|
55
|
+
* @param unitsOutputPtr Pointer to units output array
|
|
56
|
+
* @param bufferIndicesOutputPtr Pointer to buffer indices output array
|
|
57
|
+
* @param blocksOutputPtr Pointer to blocks output array
|
|
58
|
+
* @param startOffset Starting write position in output arrays
|
|
59
|
+
* @returns Number of units written
|
|
60
|
+
*/
|
|
61
|
+
populate_units_from_buffer(
|
|
62
|
+
bufferPtr: bigint,
|
|
63
|
+
bufferLength: number,
|
|
64
|
+
bufferIndex: number,
|
|
65
|
+
block: number,
|
|
66
|
+
unitsOutputPtr: bigint,
|
|
67
|
+
bufferIndicesOutputPtr: bigint,
|
|
68
|
+
blocksOutputPtr: bigint,
|
|
69
|
+
startOffset: number
|
|
70
|
+
): number;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Phase 1: Count & Deduplicate using hash table
|
|
74
|
+
* @param unitsPtr Pointer to units array
|
|
75
|
+
* @param totalUnits Number of units
|
|
76
|
+
* @param hashTablePtr Pointer to hash table
|
|
77
|
+
* @param hashTableCapacity Capacity of hash table
|
|
78
|
+
* @param uniqueUnitListPtr Pointer to store unique units
|
|
79
|
+
* @param maxUniqueCount Maximum fill threshold
|
|
80
|
+
* @returns uniqueCount (or -1 if exceeded threshold)
|
|
81
|
+
*/
|
|
82
|
+
phase1_count_deduplicate(
|
|
83
|
+
unitsPtr: bigint,
|
|
84
|
+
totalUnits: number,
|
|
85
|
+
hashTablePtr: bigint,
|
|
86
|
+
hashTableCapacity: number,
|
|
87
|
+
uniqueUnitListPtr: bigint,
|
|
88
|
+
maxUniqueCount: number
|
|
89
|
+
): number;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Phase 3: Calculate offsets for filtered arrays
|
|
93
|
+
* @param uniqueUnitListPtr Pointer to sorted unique units
|
|
94
|
+
* @param uniqueCount Number of unique units
|
|
95
|
+
* @param hashTablePtr Pointer to hash table
|
|
96
|
+
* @param hashTableCapacity Capacity of hash table
|
|
97
|
+
* @param maxPositionsPerUnit Max positions per unit (typically 1000)
|
|
98
|
+
* @returns Total offset (size of output arrays)
|
|
99
|
+
*/
|
|
100
|
+
phase3_calc_offsets(
|
|
101
|
+
uniqueUnitListPtr: bigint,
|
|
102
|
+
uniqueCount: number,
|
|
103
|
+
hashTablePtr: bigint,
|
|
104
|
+
hashTableCapacity: number,
|
|
105
|
+
maxPositionsPerUnit: number
|
|
106
|
+
): number;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Phase 4: Fill & Filter output arrays
|
|
110
|
+
* @param unitsPtr Pointer to units array
|
|
111
|
+
* @param bufferIndicesPtr Pointer to buffer indices array
|
|
112
|
+
* @param blocksPtr Pointer to blocks array
|
|
113
|
+
* @param totalUnits Number of units
|
|
114
|
+
* @param hashTablePtr Pointer to hash table
|
|
115
|
+
* @param hashTableCapacity Capacity of hash table
|
|
116
|
+
* @param maxPositionsPerUnit Max positions per unit
|
|
117
|
+
* @param filteredUnitsPtr Output array for units
|
|
118
|
+
* @param filteredBufferIndicesPtr Output array for buffer indices
|
|
119
|
+
* @param filteredBlocksPtr Output array for blocks
|
|
120
|
+
*/
|
|
121
|
+
phase4_fill_filter(
|
|
122
|
+
unitsPtr: bigint,
|
|
123
|
+
bufferIndicesPtr: bigint,
|
|
124
|
+
blocksPtr: bigint,
|
|
125
|
+
totalUnits: number,
|
|
126
|
+
hashTablePtr: bigint,
|
|
127
|
+
hashTableCapacity: number,
|
|
128
|
+
maxPositionsPerUnit: number,
|
|
129
|
+
filteredUnitsPtr: bigint,
|
|
130
|
+
filteredBufferIndicesPtr: bigint,
|
|
131
|
+
filteredBlocksPtr: bigint
|
|
132
|
+
): void;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Phase 4 Fill Filter Vector: Fill with collision detection (SIMD vectorized)
|
|
136
|
+
* @param unitsPtr Pointer to units array
|
|
137
|
+
* @param bufferIndicesPtr Pointer to buffer indices array
|
|
138
|
+
* @param blocksPtr Pointer to blocks array
|
|
139
|
+
* @param totalUnits Number of units
|
|
140
|
+
* @param hashTablePtr Pointer to hash table
|
|
141
|
+
* @param hashTableCapacity Capacity of hash table
|
|
142
|
+
* @param maxPositionsPerUnit Max positions per unit
|
|
143
|
+
* @param filteredUnitsPtr Output array for units
|
|
144
|
+
* @param filteredBufferIndicesPtr Output array for buffer indices
|
|
145
|
+
* @param filteredBlocksPtr Output array for blocks
|
|
146
|
+
* @returns Number of times slow path was taken (as f64)
|
|
147
|
+
*/
|
|
148
|
+
phase4_fill_filter_vector(
|
|
149
|
+
unitsPtr: bigint,
|
|
150
|
+
bufferIndicesPtr: bigint,
|
|
151
|
+
blocksPtr: bigint,
|
|
152
|
+
totalUnits: number,
|
|
153
|
+
hashTablePtr: bigint,
|
|
154
|
+
hashTableCapacity: number,
|
|
155
|
+
maxPositionsPerUnit: number,
|
|
156
|
+
filteredUnitsPtr: bigint,
|
|
157
|
+
filteredBufferIndicesPtr: bigint,
|
|
158
|
+
filteredBlocksPtr: bigint
|
|
159
|
+
): number;
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Count Collisions: Calculate collision count for hash table
|
|
163
|
+
* @param unitsPtr Pointer to units array
|
|
164
|
+
* @param totalUnits Number of units
|
|
165
|
+
* @param hashTablePtr Pointer to hash table
|
|
166
|
+
* @param hashTableCapacity Capacity of hash table
|
|
167
|
+
* @returns Total collision count
|
|
168
|
+
*/
|
|
169
|
+
count_collisions(
|
|
170
|
+
unitsPtr: bigint,
|
|
171
|
+
totalUnits: number,
|
|
172
|
+
hashTablePtr: bigint,
|
|
173
|
+
hashTableCapacity: number
|
|
174
|
+
): number;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
declare const module: UnitRefWatModule;
|
|
178
|
+
export default module;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { measureFnc } from "socket-function/src/profiling/measure";
|
|
2
|
+
import { BufferReader, Reader } from "./BufferIndexHelpers";
|
|
3
|
+
|
|
4
|
+
// Suffix layout (12 bytes), appended after each block's data:
|
|
5
|
+
// Int32LE dataLength — byte count of the block's data
|
|
6
|
+
// Int32LE blockIndex — 0-based ordinal of this block
|
|
7
|
+
// UInt32LE magic — configurable per instance
|
|
8
|
+
const BUFFER_LIST_STREAMER_SUFFIX_SIZE = 12;
|
|
9
|
+
|
|
10
|
+
interface BlockInfo {
|
|
11
|
+
suffixPos: number;
|
|
12
|
+
blockDataStart: number;
|
|
13
|
+
blockDataEnd: number;
|
|
14
|
+
dataLength: number;
|
|
15
|
+
blockIndex: number;
|
|
16
|
+
isIncomplete: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// NOTE: This is fully interruptable. You don't need to call finishBlock on your last block.
|
|
20
|
+
export class BufferListStreamer {
|
|
21
|
+
private magic: number;
|
|
22
|
+
private includeLastBlock: boolean;
|
|
23
|
+
|
|
24
|
+
constructor(magic: number, includeLastBlock: boolean = false) {
|
|
25
|
+
this.magic = magic;
|
|
26
|
+
this.includeLastBlock = includeLastBlock;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Iterator that yields blocks in reverse order (from last to first).
|
|
30
|
+
// If includeLastBlock is true, the incomplete block at the end is yielded first.
|
|
31
|
+
private async *iterateBlocksReverse(buffer: Buffer): AsyncGenerator<BlockInfo> {
|
|
32
|
+
let reader = new BufferReader(buffer);
|
|
33
|
+
for await (let blockInfo of this.iterateBlocksReverseAsync(reader)) {
|
|
34
|
+
yield blockInfo;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Async iterator for Reader interface - yields blocks in reverse order
|
|
39
|
+
private async *iterateBlocksReverseAsync(reader: Reader): AsyncGenerator<BlockInfo> {
|
|
40
|
+
let length = await reader.getLength();
|
|
41
|
+
|
|
42
|
+
const isValidHeader = async (suffixPos: number): Promise<number> => {
|
|
43
|
+
if (suffixPos < 0 || suffixPos + BUFFER_LIST_STREAMER_SUFFIX_SIZE > length) return -1;
|
|
44
|
+
|
|
45
|
+
let suffix = await reader.read(suffixPos, BUFFER_LIST_STREAMER_SUFFIX_SIZE);
|
|
46
|
+
if (suffix.length < BUFFER_LIST_STREAMER_SUFFIX_SIZE) return -1;
|
|
47
|
+
if (suffix.readUInt32LE(8) !== this.magic) return -1;
|
|
48
|
+
|
|
49
|
+
let dataLength = suffix.readInt32LE(0);
|
|
50
|
+
if (dataLength < 0) return -1;
|
|
51
|
+
|
|
52
|
+
let blockDataStart = suffixPos - dataLength;
|
|
53
|
+
if (blockDataStart < 0) return -1;
|
|
54
|
+
|
|
55
|
+
if (blockDataStart === 0) return blockDataStart;
|
|
56
|
+
|
|
57
|
+
let prevSuffixStart = blockDataStart - BUFFER_LIST_STREAMER_SUFFIX_SIZE;
|
|
58
|
+
if (prevSuffixStart < 0) return -1;
|
|
59
|
+
|
|
60
|
+
let prevSuffix = await reader.read(prevSuffixStart, BUFFER_LIST_STREAMER_SUFFIX_SIZE);
|
|
61
|
+
if (prevSuffix.length < BUFFER_LIST_STREAMER_SUFFIX_SIZE) return -1;
|
|
62
|
+
if (prevSuffix.readUInt32LE(8) !== this.magic) return -1;
|
|
63
|
+
|
|
64
|
+
return blockDataStart;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
let firstValidHeaderFound = false;
|
|
68
|
+
let suffixPos = length - BUFFER_LIST_STREAMER_SUFFIX_SIZE;
|
|
69
|
+
|
|
70
|
+
while (suffixPos >= 0) {
|
|
71
|
+
let blockDataStart = await isValidHeader(suffixPos);
|
|
72
|
+
if (blockDataStart < 0) {
|
|
73
|
+
suffixPos--;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!firstValidHeaderFound) {
|
|
78
|
+
firstValidHeaderFound = true;
|
|
79
|
+
|
|
80
|
+
if (this.includeLastBlock) {
|
|
81
|
+
let lastBlockEnd = suffixPos + BUFFER_LIST_STREAMER_SUFFIX_SIZE;
|
|
82
|
+
if (lastBlockEnd < length) {
|
|
83
|
+
let suffix = await reader.read(suffixPos, BUFFER_LIST_STREAMER_SUFFIX_SIZE);
|
|
84
|
+
let blockIndex = suffix.readInt32LE(4);
|
|
85
|
+
yield {
|
|
86
|
+
suffixPos: -1,
|
|
87
|
+
blockDataStart: lastBlockEnd,
|
|
88
|
+
blockDataEnd: length,
|
|
89
|
+
dataLength: length - lastBlockEnd,
|
|
90
|
+
blockIndex: blockIndex + 1,
|
|
91
|
+
isIncomplete: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let suffix = await reader.read(suffixPos, BUFFER_LIST_STREAMER_SUFFIX_SIZE);
|
|
98
|
+
let dataLength = suffixPos - blockDataStart;
|
|
99
|
+
let blockIndex = suffix.readInt32LE(4);
|
|
100
|
+
yield {
|
|
101
|
+
suffixPos,
|
|
102
|
+
blockDataStart,
|
|
103
|
+
blockDataEnd: suffixPos,
|
|
104
|
+
dataLength,
|
|
105
|
+
blockIndex,
|
|
106
|
+
isIncomplete: false,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
suffixPos = blockDataStart - BUFFER_LIST_STREAMER_SUFFIX_SIZE;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!firstValidHeaderFound && this.includeLastBlock && length > 0) {
|
|
113
|
+
yield {
|
|
114
|
+
suffixPos: -1,
|
|
115
|
+
blockDataStart: 0,
|
|
116
|
+
blockDataEnd: length,
|
|
117
|
+
dataLength: length,
|
|
118
|
+
blockIndex: 0,
|
|
119
|
+
isIncomplete: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
@measureFnc
|
|
125
|
+
public async getAllBlocks(buffer: Buffer): Promise<Buffer[]> {
|
|
126
|
+
let blocks: Buffer[] = [];
|
|
127
|
+
for await (let blockInfo of this.iterateBlocksReverse(buffer)) {
|
|
128
|
+
blocks.push(buffer.slice(blockInfo.blockDataStart, blockInfo.blockDataEnd));
|
|
129
|
+
}
|
|
130
|
+
blocks.reverse();
|
|
131
|
+
return blocks;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public async getBlockRange(config: {
|
|
135
|
+
reader: Reader;
|
|
136
|
+
startIndex: number;
|
|
137
|
+
endIndex: number;
|
|
138
|
+
}): Promise<Buffer[]> {
|
|
139
|
+
let { reader, startIndex, endIndex } = config;
|
|
140
|
+
let blocks: Buffer[] = [];
|
|
141
|
+
|
|
142
|
+
for await (let blockInfo of this.iterateBlocksReverseAsync(reader)) {
|
|
143
|
+
if (blockInfo.blockIndex >= startIndex && blockInfo.blockIndex < endIndex) {
|
|
144
|
+
let blockData = await reader.read(blockInfo.blockDataStart, blockInfo.dataLength);
|
|
145
|
+
blocks.push(blockData);
|
|
146
|
+
}
|
|
147
|
+
if (blockInfo.blockIndex < startIndex) break;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
blocks.reverse();
|
|
151
|
+
return blocks;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Efficiently gets the block count by finding the last valid suffix and reading its blockIndex.
|
|
155
|
+
public async getBlockCount(reader: Reader): Promise<number> {
|
|
156
|
+
let maxBlockIndex = -1;
|
|
157
|
+
for await (let blockInfo of this.iterateBlocksReverseAsync(reader)) {
|
|
158
|
+
if (blockInfo.blockIndex > maxBlockIndex) {
|
|
159
|
+
maxBlockIndex = blockInfo.blockIndex;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return maxBlockIndex + 1;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Returns true if the last block ends exactly at the end of the reader (not corrupted).
|
|
166
|
+
// If false, the reader can still be read but cannot be appended to efficiently.
|
|
167
|
+
// If includeLastBlock is true, this always returns true.
|
|
168
|
+
public async isClean(reader: Reader): Promise<boolean> {
|
|
169
|
+
if (this.includeLastBlock) return true;
|
|
170
|
+
|
|
171
|
+
let length = await reader.getLength();
|
|
172
|
+
if (length < BUFFER_LIST_STREAMER_SUFFIX_SIZE) return false;
|
|
173
|
+
|
|
174
|
+
// Get the first block info (which is the last block in the file)
|
|
175
|
+
for await (let blockInfo of this.iterateBlocksReverseAsync(reader)) {
|
|
176
|
+
// The first block we encounter should be a complete block ending at the file end
|
|
177
|
+
if (blockInfo.isIncomplete) return false;
|
|
178
|
+
return blockInfo.blockDataEnd + BUFFER_LIST_STREAMER_SUFFIX_SIZE === length;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public createStreamer(): {
|
|
185
|
+
add(data: Buffer): Buffer;
|
|
186
|
+
// NOTE: Finish block doesn't finish the BufferListStreamer, it just stops the current block. The BufferListStreamer has multiple blocks.
|
|
187
|
+
finishBlock(): Buffer;
|
|
188
|
+
} {
|
|
189
|
+
let currentBlockSize = 0;
|
|
190
|
+
let currentBlockIndex = 0;
|
|
191
|
+
let magic = this.magic;
|
|
192
|
+
return {
|
|
193
|
+
add(data: Buffer) {
|
|
194
|
+
currentBlockSize += data.length;
|
|
195
|
+
return data;
|
|
196
|
+
},
|
|
197
|
+
finishBlock() {
|
|
198
|
+
let suffix = Buffer.alloc(BUFFER_LIST_STREAMER_SUFFIX_SIZE);
|
|
199
|
+
suffix.writeInt32LE(currentBlockSize, 0);
|
|
200
|
+
suffix.writeInt32LE(currentBlockIndex, 4);
|
|
201
|
+
suffix.writeUInt32LE(magic, 8);
|
|
202
|
+
currentBlockIndex++;
|
|
203
|
+
currentBlockSize = 0;
|
|
204
|
+
return suffix;
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|