@peerbit/native-backbone 0.2.7 → 0.2.9
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/dist/src/index.d.ts +58 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +191 -0
- package/dist/src/index.js.map +1 -1
- package/dist/wasm/native_backbone.d.ts +48 -40
- package/dist/wasm/native_backbone.js +92 -0
- package/dist/wasm/native_backbone_bg.wasm +0 -0
- package/dist/wasm/native_backbone_bg.wasm.d.ts +44 -40
- package/package.json +1 -1
- package/src/index.ts +367 -0
- package/src/shared_log_plan.rs +24 -0
package/src/index.ts
CHANGED
|
@@ -61,6 +61,20 @@ type NativePeerbitBackboneHandle = {
|
|
|
61
61
|
start2: string,
|
|
62
62
|
end2: string,
|
|
63
63
|
) => BigUint64Array;
|
|
64
|
+
entry_hash_numbers_in_range_limited?: (
|
|
65
|
+
start1: string,
|
|
66
|
+
end1: string,
|
|
67
|
+
start2: string,
|
|
68
|
+
end2: string,
|
|
69
|
+
limit: number,
|
|
70
|
+
) => unknown[];
|
|
71
|
+
entry_hash_numbers_in_range_u64_limited?: (
|
|
72
|
+
start1: string,
|
|
73
|
+
end1: string,
|
|
74
|
+
start2: string,
|
|
75
|
+
end2: string,
|
|
76
|
+
limit: number,
|
|
77
|
+
) => BigUint64Array;
|
|
64
78
|
count_entry_coordinates_in_ranges: (
|
|
65
79
|
start1: string[],
|
|
66
80
|
end1: string[],
|
|
@@ -2959,6 +2973,14 @@ export type NativeBackboneCoordinatePersistenceOptions =
|
|
|
2959
2973
|
|
|
2960
2974
|
export type NativeBackboneCoordinatePersistenceStore = {
|
|
2961
2975
|
read(name: string): Promise<Uint8Array | undefined>;
|
|
2976
|
+
/**
|
|
2977
|
+
* Read a named file without materializing more than `maxBytes`.
|
|
2978
|
+
*
|
|
2979
|
+
* The optional method is an explicit capability: callers that require a
|
|
2980
|
+
* pre-allocation bound must fail closed when it is absent and must not fall
|
|
2981
|
+
* back to `read`.
|
|
2982
|
+
*/
|
|
2983
|
+
readLimited?(name: string, maxBytes: number): Promise<Uint8Array | undefined>;
|
|
2962
2984
|
write(name: string, bytes: Uint8Array): Promise<void>;
|
|
2963
2985
|
/**
|
|
2964
2986
|
* Appends `bytes` to the named file. Callers hand over ownership of
|
|
@@ -2977,6 +2999,21 @@ export type NativeBackboneCoordinatePersistenceStore = {
|
|
|
2977
2999
|
close?(options?: { flush?: boolean }): Promise<void>;
|
|
2978
3000
|
};
|
|
2979
3001
|
|
|
3002
|
+
export class NativeBackboneCoordinatePersistenceReadLimitError extends Error {
|
|
3003
|
+
readonly code = "ERR_NATIVE_BACKBONE_COORDINATE_READ_LIMIT";
|
|
3004
|
+
|
|
3005
|
+
constructor(
|
|
3006
|
+
readonly file: string,
|
|
3007
|
+
readonly maxBytes: number,
|
|
3008
|
+
readonly observedBytes: bigint,
|
|
3009
|
+
) {
|
|
3010
|
+
super(
|
|
3011
|
+
`Native backbone coordinate persistence file ${file} exceeds the ${maxBytes} byte read limit (${observedBytes.toString()} bytes)`,
|
|
3012
|
+
);
|
|
3013
|
+
this.name = "NativeBackboneCoordinatePersistenceReadLimitError";
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
|
|
2980
3017
|
export type NativeBackboneCoordinatePersistenceAdapter = {
|
|
2981
3018
|
/**
|
|
2982
3019
|
* Optional durable capability used by higher layers for atomic operation
|
|
@@ -3140,6 +3177,10 @@ type NativeBackboneNodeFs = {
|
|
|
3140
3177
|
readFile(path: string): Promise<Uint8Array>;
|
|
3141
3178
|
writeFile(path: string, data: Uint8Array): Promise<unknown>;
|
|
3142
3179
|
appendFile(path: string, data: Uint8Array): Promise<unknown>;
|
|
3180
|
+
/** Explicit capability for pre-allocation-bounded positional reads. */
|
|
3181
|
+
openBoundedRead?(
|
|
3182
|
+
path: string,
|
|
3183
|
+
): Promise<NativeBackboneNodeBoundedReadFileHandle>;
|
|
3143
3184
|
open?(
|
|
3144
3185
|
path: string,
|
|
3145
3186
|
flags: string,
|
|
@@ -3149,10 +3190,28 @@ type NativeBackboneNodeFs = {
|
|
|
3149
3190
|
|
|
3150
3191
|
type NativeBackboneNodeAppendFileHandle = {
|
|
3151
3192
|
write(data: Uint8Array): Promise<{ bytesWritten: number }>;
|
|
3193
|
+
read?(
|
|
3194
|
+
buffer: Uint8Array,
|
|
3195
|
+
offset: number,
|
|
3196
|
+
length: number,
|
|
3197
|
+
position: number,
|
|
3198
|
+
): Promise<{ bytesRead: number }>;
|
|
3199
|
+
stat?(options: { bigint: true }): Promise<{ size: bigint }>;
|
|
3152
3200
|
sync?(): Promise<unknown>;
|
|
3153
3201
|
close(): Promise<unknown>;
|
|
3154
3202
|
};
|
|
3155
3203
|
|
|
3204
|
+
type NativeBackboneNodeBoundedReadFileHandle = {
|
|
3205
|
+
read(
|
|
3206
|
+
buffer: Uint8Array,
|
|
3207
|
+
offset: number,
|
|
3208
|
+
length: number,
|
|
3209
|
+
position: number,
|
|
3210
|
+
): Promise<{ bytesRead: number }>;
|
|
3211
|
+
stat(options: { bigint: true }): Promise<{ size: bigint }>;
|
|
3212
|
+
close(): Promise<unknown>;
|
|
3213
|
+
};
|
|
3214
|
+
|
|
3156
3215
|
type NativeBackboneOPFSFile = {
|
|
3157
3216
|
arrayBuffer(): Promise<ArrayBuffer>;
|
|
3158
3217
|
size: number;
|
|
@@ -3260,6 +3319,31 @@ const validateCoordinatePersistenceName = (name: string): string => {
|
|
|
3260
3319
|
return name;
|
|
3261
3320
|
};
|
|
3262
3321
|
|
|
3322
|
+
const validateCoordinatePersistenceReadMaxBytes = (
|
|
3323
|
+
maxBytes: number,
|
|
3324
|
+
): number => {
|
|
3325
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {
|
|
3326
|
+
throw new RangeError(
|
|
3327
|
+
"Native backbone coordinate persistence read limit must be a non-negative safe integer",
|
|
3328
|
+
);
|
|
3329
|
+
}
|
|
3330
|
+
return maxBytes;
|
|
3331
|
+
};
|
|
3332
|
+
|
|
3333
|
+
const assertCoordinatePersistenceReadWithinLimit = (
|
|
3334
|
+
name: string,
|
|
3335
|
+
maxBytes: number,
|
|
3336
|
+
observedBytes: number | bigint,
|
|
3337
|
+
): void => {
|
|
3338
|
+
if (BigInt(observedBytes) > BigInt(maxBytes)) {
|
|
3339
|
+
throw new NativeBackboneCoordinatePersistenceReadLimitError(
|
|
3340
|
+
name,
|
|
3341
|
+
maxBytes,
|
|
3342
|
+
BigInt(observedBytes),
|
|
3343
|
+
);
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
|
|
3263
3347
|
type NativeBackboneCoordinateDropTombstoneBody = {
|
|
3264
3348
|
format: "peerbit-native-backbone-coordinate-drop";
|
|
3265
3349
|
version: 1;
|
|
@@ -6364,6 +6448,52 @@ export class NativePeerbitBackbone {
|
|
|
6364
6448
|
);
|
|
6365
6449
|
}
|
|
6366
6450
|
|
|
6451
|
+
getEntryHashNumbersInRangeLimited(range: {
|
|
6452
|
+
start1: bigint | number | string;
|
|
6453
|
+
end1: bigint | number | string;
|
|
6454
|
+
start2: bigint | number | string;
|
|
6455
|
+
end2: bigint | number | string;
|
|
6456
|
+
limit: number;
|
|
6457
|
+
}): bigint[] | undefined {
|
|
6458
|
+
if (
|
|
6459
|
+
typeof this.native.entry_hash_numbers_in_range_limited !== "function"
|
|
6460
|
+
) {
|
|
6461
|
+
return undefined;
|
|
6462
|
+
}
|
|
6463
|
+
return rowsToNumbers(
|
|
6464
|
+
"u64",
|
|
6465
|
+
this.native.entry_hash_numbers_in_range_limited(
|
|
6466
|
+
integerString(range.start1),
|
|
6467
|
+
integerString(range.end1),
|
|
6468
|
+
integerString(range.start2),
|
|
6469
|
+
integerString(range.end2),
|
|
6470
|
+
range.limit,
|
|
6471
|
+
),
|
|
6472
|
+
) as bigint[];
|
|
6473
|
+
}
|
|
6474
|
+
|
|
6475
|
+
getEntryHashNumbersInRangeU64Limited(range: {
|
|
6476
|
+
start1: bigint | number | string;
|
|
6477
|
+
end1: bigint | number | string;
|
|
6478
|
+
start2: bigint | number | string;
|
|
6479
|
+
end2: bigint | number | string;
|
|
6480
|
+
limit: number;
|
|
6481
|
+
}): BigUint64Array | undefined {
|
|
6482
|
+
if (
|
|
6483
|
+
typeof BigUint64Array === "undefined" ||
|
|
6484
|
+
typeof this.native.entry_hash_numbers_in_range_u64_limited !== "function"
|
|
6485
|
+
) {
|
|
6486
|
+
return undefined;
|
|
6487
|
+
}
|
|
6488
|
+
return this.native.entry_hash_numbers_in_range_u64_limited(
|
|
6489
|
+
integerString(range.start1),
|
|
6490
|
+
integerString(range.end1),
|
|
6491
|
+
integerString(range.start2),
|
|
6492
|
+
integerString(range.end2),
|
|
6493
|
+
range.limit,
|
|
6494
|
+
);
|
|
6495
|
+
}
|
|
6496
|
+
|
|
6367
6497
|
countEntryCoordinatesInRanges(
|
|
6368
6498
|
ranges: Iterable<{
|
|
6369
6499
|
start1: bigint | number | string;
|
|
@@ -8586,6 +8716,23 @@ export class NativeBackboneMemoryCoordinatePersistenceStore
|
|
|
8586
8716
|
return file ? copyBytes(file) : undefined;
|
|
8587
8717
|
}
|
|
8588
8718
|
|
|
8719
|
+
async readLimited(
|
|
8720
|
+
name: string,
|
|
8721
|
+
maxBytes: number,
|
|
8722
|
+
): Promise<Uint8Array | undefined> {
|
|
8723
|
+
const validName = validateCoordinatePersistenceName(name);
|
|
8724
|
+
const limit = validateCoordinatePersistenceReadMaxBytes(maxBytes);
|
|
8725
|
+
const file = this.files.get(validName);
|
|
8726
|
+
if (file) {
|
|
8727
|
+
assertCoordinatePersistenceReadWithinLimit(
|
|
8728
|
+
validName,
|
|
8729
|
+
limit,
|
|
8730
|
+
file.byteLength,
|
|
8731
|
+
);
|
|
8732
|
+
}
|
|
8733
|
+
return file ? copyBytes(file) : undefined;
|
|
8734
|
+
}
|
|
8735
|
+
|
|
8589
8736
|
async write(name: string, bytes: Uint8Array): Promise<void> {
|
|
8590
8737
|
this.files.set(validateCoordinatePersistenceName(name), copyBytes(bytes));
|
|
8591
8738
|
}
|
|
@@ -8616,6 +8763,10 @@ export class NativeBackboneNodeCoordinatePersistenceStore
|
|
|
8616
8763
|
private readonly filePaths = new Map<string, string>();
|
|
8617
8764
|
private directoryEnsured = false;
|
|
8618
8765
|
private appendFailure: unknown;
|
|
8766
|
+
readonly readLimited?: (
|
|
8767
|
+
name: string,
|
|
8768
|
+
maxBytes: number,
|
|
8769
|
+
) => Promise<Uint8Array | undefined>;
|
|
8619
8770
|
readonly durableBarrier?: (name?: string) => Promise<void>;
|
|
8620
8771
|
|
|
8621
8772
|
constructor(
|
|
@@ -8628,6 +8779,10 @@ export class NativeBackboneNodeCoordinatePersistenceStore
|
|
|
8628
8779
|
if (!fs || typeof fs.open === "function") {
|
|
8629
8780
|
this.durableBarrier = (name) => this.syncDurably(name);
|
|
8630
8781
|
}
|
|
8782
|
+
if (!fs || typeof fs.openBoundedRead === "function") {
|
|
8783
|
+
this.readLimited = (name, maxBytes) =>
|
|
8784
|
+
this.readWithinLimit(name, maxBytes);
|
|
8785
|
+
}
|
|
8631
8786
|
}
|
|
8632
8787
|
|
|
8633
8788
|
private async nodeFs(): Promise<NativeBackboneNodeFs> {
|
|
@@ -8689,6 +8844,120 @@ export class NativeBackboneNodeCoordinatePersistenceStore
|
|
|
8689
8844
|
}
|
|
8690
8845
|
}
|
|
8691
8846
|
|
|
8847
|
+
private async readWithinLimit(
|
|
8848
|
+
name: string,
|
|
8849
|
+
maxBytes: number,
|
|
8850
|
+
): Promise<Uint8Array | undefined> {
|
|
8851
|
+
const validName = validateCoordinatePersistenceName(name);
|
|
8852
|
+
const limit = validateCoordinatePersistenceReadMaxBytes(maxBytes);
|
|
8853
|
+
const fs = await this.nodeFs();
|
|
8854
|
+
const path = await this.filePath(validName);
|
|
8855
|
+
let handle: NativeBackboneNodeBoundedReadFileHandle | undefined;
|
|
8856
|
+
try {
|
|
8857
|
+
if (this.fs) {
|
|
8858
|
+
handle = await this.fs.openBoundedRead!(path);
|
|
8859
|
+
} else {
|
|
8860
|
+
if (!fs.open) {
|
|
8861
|
+
throw new Error(
|
|
8862
|
+
"Default Node coordinate persistence does not expose FileHandle.open",
|
|
8863
|
+
);
|
|
8864
|
+
}
|
|
8865
|
+
const opened = await fs.open(path, "r");
|
|
8866
|
+
if (!opened.stat || !opened.read) {
|
|
8867
|
+
await opened.close();
|
|
8868
|
+
throw new Error(
|
|
8869
|
+
"Default Node coordinate persistence bounded reads require FileHandle.stat and FileHandle.read",
|
|
8870
|
+
);
|
|
8871
|
+
}
|
|
8872
|
+
handle = opened as NativeBackboneNodeBoundedReadFileHandle;
|
|
8873
|
+
}
|
|
8874
|
+
} catch (error) {
|
|
8875
|
+
if (isNotFoundError(error)) {
|
|
8876
|
+
return undefined;
|
|
8877
|
+
}
|
|
8878
|
+
throw error;
|
|
8879
|
+
}
|
|
8880
|
+
try {
|
|
8881
|
+
const initial = await handle.stat({ bigint: true });
|
|
8882
|
+
if (typeof initial.size !== "bigint" || initial.size < 0n) {
|
|
8883
|
+
throw new Error(
|
|
8884
|
+
"Node coordinate persistence returned an invalid bigint file size",
|
|
8885
|
+
);
|
|
8886
|
+
}
|
|
8887
|
+
assertCoordinatePersistenceReadWithinLimit(
|
|
8888
|
+
validName,
|
|
8889
|
+
limit,
|
|
8890
|
+
initial.size,
|
|
8891
|
+
);
|
|
8892
|
+
if (initial.size > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
8893
|
+
throw new RangeError(
|
|
8894
|
+
"Node coordinate persistence file is too large to materialize safely",
|
|
8895
|
+
);
|
|
8896
|
+
}
|
|
8897
|
+
const byteLength = Number(initial.size);
|
|
8898
|
+
const bytes = new Uint8Array(byteLength);
|
|
8899
|
+
let offset = 0;
|
|
8900
|
+
while (offset < byteLength) {
|
|
8901
|
+
const { bytesRead } = await handle.read(
|
|
8902
|
+
bytes,
|
|
8903
|
+
offset,
|
|
8904
|
+
byteLength - offset,
|
|
8905
|
+
offset,
|
|
8906
|
+
);
|
|
8907
|
+
if (
|
|
8908
|
+
!Number.isSafeInteger(bytesRead) ||
|
|
8909
|
+
bytesRead <= 0 ||
|
|
8910
|
+
bytesRead > byteLength - offset
|
|
8911
|
+
) {
|
|
8912
|
+
throw new Error(
|
|
8913
|
+
"Node coordinate persistence file changed during a bounded read",
|
|
8914
|
+
);
|
|
8915
|
+
}
|
|
8916
|
+
offset += bytesRead;
|
|
8917
|
+
}
|
|
8918
|
+
const growthProbe = new Uint8Array(1);
|
|
8919
|
+
const { bytesRead: growthBytes } = await handle.read(
|
|
8920
|
+
growthProbe,
|
|
8921
|
+
0,
|
|
8922
|
+
1,
|
|
8923
|
+
byteLength,
|
|
8924
|
+
);
|
|
8925
|
+
if (
|
|
8926
|
+
!Number.isSafeInteger(growthBytes) ||
|
|
8927
|
+
growthBytes < 0 ||
|
|
8928
|
+
growthBytes > 1
|
|
8929
|
+
) {
|
|
8930
|
+
throw new Error(
|
|
8931
|
+
"Node coordinate persistence returned invalid bounded read progress",
|
|
8932
|
+
);
|
|
8933
|
+
}
|
|
8934
|
+
const final = await handle.stat({ bigint: true });
|
|
8935
|
+
if (typeof final.size !== "bigint" || final.size < 0n) {
|
|
8936
|
+
throw new Error(
|
|
8937
|
+
"Node coordinate persistence returned an invalid bigint file size",
|
|
8938
|
+
);
|
|
8939
|
+
}
|
|
8940
|
+
if (growthBytes !== 0 || final.size > initial.size) {
|
|
8941
|
+
assertCoordinatePersistenceReadWithinLimit(
|
|
8942
|
+
validName,
|
|
8943
|
+
limit,
|
|
8944
|
+
final.size > initial.size ? final.size : initial.size + 1n,
|
|
8945
|
+
);
|
|
8946
|
+
throw new Error(
|
|
8947
|
+
"Node coordinate persistence file changed during a bounded read",
|
|
8948
|
+
);
|
|
8949
|
+
}
|
|
8950
|
+
if (final.size !== initial.size) {
|
|
8951
|
+
throw new Error(
|
|
8952
|
+
"Node coordinate persistence file changed during a bounded read",
|
|
8953
|
+
);
|
|
8954
|
+
}
|
|
8955
|
+
return bytes;
|
|
8956
|
+
} finally {
|
|
8957
|
+
await handle.close();
|
|
8958
|
+
}
|
|
8959
|
+
}
|
|
8960
|
+
|
|
8692
8961
|
async write(name: string, bytes: Uint8Array): Promise<void> {
|
|
8693
8962
|
const fs = await this.ensureDirectory();
|
|
8694
8963
|
const path = await this.filePath(name);
|
|
@@ -8889,6 +9158,38 @@ export class NativeBackboneOPFSCoordinatePersistenceStore
|
|
|
8889
9158
|
}
|
|
8890
9159
|
}
|
|
8891
9160
|
|
|
9161
|
+
async readLimited(
|
|
9162
|
+
name: string,
|
|
9163
|
+
maxBytes: number,
|
|
9164
|
+
): Promise<Uint8Array | undefined> {
|
|
9165
|
+
const validName = validateCoordinatePersistenceName(name);
|
|
9166
|
+
const limit = validateCoordinatePersistenceReadMaxBytes(maxBytes);
|
|
9167
|
+
try {
|
|
9168
|
+
const handle = await this.directory.getFileHandle(validName, {
|
|
9169
|
+
create: false,
|
|
9170
|
+
});
|
|
9171
|
+
const file = await handle.getFile();
|
|
9172
|
+
if (!Number.isSafeInteger(file.size) || file.size < 0) {
|
|
9173
|
+
throw new Error(
|
|
9174
|
+
"OPFS coordinate persistence returned an invalid file size",
|
|
9175
|
+
);
|
|
9176
|
+
}
|
|
9177
|
+
assertCoordinatePersistenceReadWithinLimit(validName, limit, file.size);
|
|
9178
|
+
const buffer = await file.arrayBuffer();
|
|
9179
|
+
if (buffer.byteLength !== file.size) {
|
|
9180
|
+
throw new Error(
|
|
9181
|
+
"OPFS coordinate persistence file changed during a bounded read",
|
|
9182
|
+
);
|
|
9183
|
+
}
|
|
9184
|
+
return new Uint8Array(buffer);
|
|
9185
|
+
} catch (error) {
|
|
9186
|
+
if (isNotFoundError(error)) {
|
|
9187
|
+
return undefined;
|
|
9188
|
+
}
|
|
9189
|
+
throw error;
|
|
9190
|
+
}
|
|
9191
|
+
}
|
|
9192
|
+
|
|
8892
9193
|
async write(name: string, bytes: Uint8Array): Promise<void> {
|
|
8893
9194
|
const handle = await this.directory.getFileHandle(
|
|
8894
9195
|
validateCoordinatePersistenceName(name),
|
|
@@ -9010,6 +9311,10 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
|
|
|
9010
9311
|
{
|
|
9011
9312
|
private readonly buffers = new Map<string, Uint8Array[]>();
|
|
9012
9313
|
private bufferedBytes = 0;
|
|
9314
|
+
readonly readLimited?: (
|
|
9315
|
+
name: string,
|
|
9316
|
+
maxBytes: number,
|
|
9317
|
+
) => Promise<Uint8Array | undefined>;
|
|
9013
9318
|
readonly supportsRemoval: boolean;
|
|
9014
9319
|
readonly durableBarrier?: (name?: string) => Promise<void>;
|
|
9015
9320
|
|
|
@@ -9019,6 +9324,11 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
|
|
|
9019
9324
|
) {
|
|
9020
9325
|
this.supportsRemoval =
|
|
9021
9326
|
inner.supportsRemoval ?? typeof inner.remove === "function";
|
|
9327
|
+
if (typeof inner.readLimited === "function") {
|
|
9328
|
+
const innerReadLimited = inner.readLimited.bind(inner);
|
|
9329
|
+
this.readLimited = (name, maxBytes) =>
|
|
9330
|
+
this.readWithinLimit(name, maxBytes, innerReadLimited);
|
|
9331
|
+
}
|
|
9022
9332
|
if (typeof inner.durableBarrier === "function") {
|
|
9023
9333
|
this.durableBarrier = async (name) => {
|
|
9024
9334
|
await this.flush(name);
|
|
@@ -9042,6 +9352,63 @@ export class NativeBackboneBufferedCoordinatePersistenceStore
|
|
|
9042
9352
|
return this.inner.read(name);
|
|
9043
9353
|
}
|
|
9044
9354
|
|
|
9355
|
+
private async readWithinLimit(
|
|
9356
|
+
name: string,
|
|
9357
|
+
maxBytes: number,
|
|
9358
|
+
innerReadLimited: (
|
|
9359
|
+
name: string,
|
|
9360
|
+
maxBytes: number,
|
|
9361
|
+
) => Promise<Uint8Array | undefined>,
|
|
9362
|
+
): Promise<Uint8Array | undefined> {
|
|
9363
|
+
const validName = validateCoordinatePersistenceName(name);
|
|
9364
|
+
const limit = validateCoordinatePersistenceReadMaxBytes(maxBytes);
|
|
9365
|
+
const pending = this.buffers.get(validName);
|
|
9366
|
+
if (!pending || pending.length === 0) {
|
|
9367
|
+
return innerReadLimited(validName, limit);
|
|
9368
|
+
}
|
|
9369
|
+
const pendingLength = pending.length;
|
|
9370
|
+
let pendingBytes = 0n;
|
|
9371
|
+
for (const chunk of pending) {
|
|
9372
|
+
pendingBytes += BigInt(chunk.byteLength);
|
|
9373
|
+
}
|
|
9374
|
+
assertCoordinatePersistenceReadWithinLimit(validName, limit, pendingBytes);
|
|
9375
|
+
const remaining = limit - Number(pendingBytes);
|
|
9376
|
+
let existingBytes: number | undefined;
|
|
9377
|
+
try {
|
|
9378
|
+
existingBytes = (await innerReadLimited(validName, remaining))
|
|
9379
|
+
?.byteLength;
|
|
9380
|
+
} catch (error) {
|
|
9381
|
+
if (error instanceof NativeBackboneCoordinatePersistenceReadLimitError) {
|
|
9382
|
+
throw new NativeBackboneCoordinatePersistenceReadLimitError(
|
|
9383
|
+
validName,
|
|
9384
|
+
limit,
|
|
9385
|
+
pendingBytes + error.observedBytes,
|
|
9386
|
+
);
|
|
9387
|
+
}
|
|
9388
|
+
throw error;
|
|
9389
|
+
}
|
|
9390
|
+
let confirmedPendingBytes = 0n;
|
|
9391
|
+
for (const chunk of pending) {
|
|
9392
|
+
confirmedPendingBytes += BigInt(chunk.byteLength);
|
|
9393
|
+
}
|
|
9394
|
+
if (
|
|
9395
|
+
this.buffers.get(validName) !== pending ||
|
|
9396
|
+
pending.length !== pendingLength ||
|
|
9397
|
+
confirmedPendingBytes !== pendingBytes
|
|
9398
|
+
) {
|
|
9399
|
+
throw new Error(
|
|
9400
|
+
"Native backbone coordinate persistence pending bytes changed during a bounded read",
|
|
9401
|
+
);
|
|
9402
|
+
}
|
|
9403
|
+
assertCoordinatePersistenceReadWithinLimit(
|
|
9404
|
+
validName,
|
|
9405
|
+
limit,
|
|
9406
|
+
pendingBytes + BigInt(existingBytes ?? 0),
|
|
9407
|
+
);
|
|
9408
|
+
await this.flush(validName);
|
|
9409
|
+
return innerReadLimited(validName, limit);
|
|
9410
|
+
}
|
|
9411
|
+
|
|
9045
9412
|
async write(name: string, bytes: Uint8Array): Promise<void> {
|
|
9046
9413
|
await this.flush(name);
|
|
9047
9414
|
await this.inner.write(name, bytes);
|
package/src/shared_log_plan.rs
CHANGED
|
@@ -326,6 +326,30 @@ impl NativePeerbitBackbone {
|
|
|
326
326
|
.entry_hash_numbers_in_range_u64(start1, end1, start2, end2)
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
+
pub fn entry_hash_numbers_in_range_limited(
|
|
330
|
+
&self,
|
|
331
|
+
start1: String,
|
|
332
|
+
end1: String,
|
|
333
|
+
start2: String,
|
|
334
|
+
end2: String,
|
|
335
|
+
limit: u32,
|
|
336
|
+
) -> Result<Array, JsValue> {
|
|
337
|
+
self.shared_log
|
|
338
|
+
.entry_hash_numbers_in_range_limited(start1, end1, start2, end2, limit)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
pub fn entry_hash_numbers_in_range_u64_limited(
|
|
342
|
+
&self,
|
|
343
|
+
start1: String,
|
|
344
|
+
end1: String,
|
|
345
|
+
start2: String,
|
|
346
|
+
end2: String,
|
|
347
|
+
limit: u32,
|
|
348
|
+
) -> Result<BigUint64Array, JsValue> {
|
|
349
|
+
self.shared_log
|
|
350
|
+
.entry_hash_numbers_in_range_u64_limited(start1, end1, start2, end2, limit)
|
|
351
|
+
}
|
|
352
|
+
|
|
329
353
|
pub fn count_entry_coordinates_in_ranges(
|
|
330
354
|
&self,
|
|
331
355
|
start1: Array,
|