bun-shared-memory 0.1.7 → 0.1.8
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/package.json +1 -1
- package/src/growable-buffer.ts +19 -4
- package/src/memory.ts +33 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bun-shared-memory",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Share data between Bun workers/threads using SharedArrayBuffer (zero-copy, 4-buffer architecture, Atomics-based synchronization).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
package/src/growable-buffer.ts
CHANGED
|
@@ -102,7 +102,13 @@ export class GrowableBuffer {
|
|
|
102
102
|
/** log2(chunkSize), used for O(1) offset resolution via bit shifts. */
|
|
103
103
|
private readonly chunkShift: number;
|
|
104
104
|
private readonly budget?: SharedBudget;
|
|
105
|
-
|
|
105
|
+
/**
|
|
106
|
+
* Shared append cursor (used length). Stored in a SharedArrayBuffer so all
|
|
107
|
+
* workers that reconstruct this buffer from `fromBuffers()` see the same
|
|
108
|
+
* used length and append at the correct offset instead of overwriting
|
|
109
|
+
* existing data at offset 0.
|
|
110
|
+
*/
|
|
111
|
+
private readonly cursor: BigInt64Array;
|
|
106
112
|
/** Smallest chunk index that is not yet active (see `activate`). */
|
|
107
113
|
private nextChunkToActivate = 0;
|
|
108
114
|
|
|
@@ -113,9 +119,13 @@ export class GrowableBuffer {
|
|
|
113
119
|
chunkSize = 32 * 1024 * 1024, // 32 MiB per chunk
|
|
114
120
|
singleBuffer = false,
|
|
115
121
|
chargeInitial = true,
|
|
122
|
+
cursorBuffer?: SharedArrayBuffer,
|
|
116
123
|
) {
|
|
117
124
|
this.singleBuffer = singleBuffer;
|
|
118
125
|
this.budget = budget;
|
|
126
|
+
this.cursor = new BigInt64Array(
|
|
127
|
+
cursorBuffer ?? new SharedArrayBuffer(BigInt64Array.BYTES_PER_ELEMENT),
|
|
128
|
+
);
|
|
119
129
|
if (singleBuffer && typeof initialSizeOrBuffer !== "number") {
|
|
120
130
|
const buffer = Array.isArray(initialSizeOrBuffer)
|
|
121
131
|
? initialSizeOrBuffer[0]
|
|
@@ -267,7 +277,12 @@ export class GrowableBuffer {
|
|
|
267
277
|
|
|
268
278
|
/** Number of bytes written so far (used length, not buffer capacity). */
|
|
269
279
|
get byteLength(): number {
|
|
270
|
-
return this.
|
|
280
|
+
return Number(Atomics.load(this.cursor, 0));
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** The shared cursor buffer (for export to workers). */
|
|
284
|
+
get cursorBuffer(): SharedArrayBuffer {
|
|
285
|
+
return this.cursor.buffer as SharedArrayBuffer;
|
|
271
286
|
}
|
|
272
287
|
|
|
273
288
|
/** Total logical capacity across all chunks (active or not). */
|
|
@@ -373,7 +388,7 @@ export class GrowableBuffer {
|
|
|
373
388
|
|
|
374
389
|
/** Mark `n` bytes as used, after writing them at the current offset. */
|
|
375
390
|
advance(n: number): void {
|
|
376
|
-
this.
|
|
391
|
+
Atomics.add(this.cursor, 0, BigInt(n));
|
|
377
392
|
}
|
|
378
393
|
|
|
379
394
|
/**
|
|
@@ -383,7 +398,7 @@ export class GrowableBuffer {
|
|
|
383
398
|
* `releaseInactiveChunks()`.
|
|
384
399
|
*/
|
|
385
400
|
reset(n: number): void {
|
|
386
|
-
this.
|
|
401
|
+
Atomics.store(this.cursor, 0, BigInt(n));
|
|
387
402
|
if (this.singleBuffer) return;
|
|
388
403
|
const neededChunks = Math.ceil(n / this.chunkSize);
|
|
389
404
|
for (let i = 0; i < this.chunks.length; i++) {
|
package/src/memory.ts
CHANGED
|
@@ -211,6 +211,12 @@ export interface SharedMemoryOptions {
|
|
|
211
211
|
layoutVersion?: SharedArrayBuffer;
|
|
212
212
|
refCount?: SharedArrayBuffer;
|
|
213
213
|
budget?: SharedArrayBuffer;
|
|
214
|
+
cursors?: {
|
|
215
|
+
indexTable?: SharedArrayBuffer;
|
|
216
|
+
dataTable?: SharedArrayBuffer;
|
|
217
|
+
stringTable?: SharedArrayBuffer;
|
|
218
|
+
arrayTable?: SharedArrayBuffer;
|
|
219
|
+
};
|
|
214
220
|
};
|
|
215
221
|
}
|
|
216
222
|
|
|
@@ -223,6 +229,7 @@ function makeBuffer(
|
|
|
223
229
|
chunkSize?: number,
|
|
224
230
|
singleBuffer = false,
|
|
225
231
|
chargeInitial = true,
|
|
232
|
+
cursorBuffer?: SharedArrayBuffer,
|
|
226
233
|
): GrowableBuffer {
|
|
227
234
|
if (buf === undefined) {
|
|
228
235
|
return new GrowableBuffer(
|
|
@@ -232,6 +239,7 @@ function makeBuffer(
|
|
|
232
239
|
chunkSize,
|
|
233
240
|
singleBuffer,
|
|
234
241
|
chargeInitial,
|
|
242
|
+
cursorBuffer,
|
|
235
243
|
);
|
|
236
244
|
}
|
|
237
245
|
return new GrowableBuffer(
|
|
@@ -241,6 +249,7 @@ function makeBuffer(
|
|
|
241
249
|
chunkSize,
|
|
242
250
|
singleBuffer,
|
|
243
251
|
chargeInitial,
|
|
252
|
+
cursorBuffer,
|
|
244
253
|
);
|
|
245
254
|
}
|
|
246
255
|
|
|
@@ -359,6 +368,8 @@ export class SharedMemory {
|
|
|
359
368
|
undefined,
|
|
360
369
|
chunkSize,
|
|
361
370
|
true,
|
|
371
|
+
true,
|
|
372
|
+
buffers?.cursors?.indexTable,
|
|
362
373
|
);
|
|
363
374
|
this.dataTable = makeBuffer(
|
|
364
375
|
buffers?.dataTable,
|
|
@@ -368,6 +379,7 @@ export class SharedMemory {
|
|
|
368
379
|
chunkSize,
|
|
369
380
|
false,
|
|
370
381
|
chargeInitial,
|
|
382
|
+
buffers?.cursors?.dataTable,
|
|
371
383
|
);
|
|
372
384
|
this.stringTable = makeBuffer(
|
|
373
385
|
buffers?.stringTable,
|
|
@@ -377,6 +389,7 @@ export class SharedMemory {
|
|
|
377
389
|
chunkSize,
|
|
378
390
|
false,
|
|
379
391
|
chargeInitial,
|
|
392
|
+
buffers?.cursors?.stringTable,
|
|
380
393
|
);
|
|
381
394
|
this.arrayTable = makeBuffer(
|
|
382
395
|
buffers?.arrayTable,
|
|
@@ -386,6 +399,7 @@ export class SharedMemory {
|
|
|
386
399
|
chunkSize,
|
|
387
400
|
false,
|
|
388
401
|
chargeInitial,
|
|
402
|
+
buffers?.cursors?.arrayTable,
|
|
389
403
|
);
|
|
390
404
|
this.versionView = new Int32Array(this.indexTable.buffers[0]!);
|
|
391
405
|
this.layoutVersion = new Int32Array(
|
|
@@ -453,6 +467,12 @@ export class SharedMemory {
|
|
|
453
467
|
indexTableMaxByteLength: number;
|
|
454
468
|
maxTotalBytes: number | null;
|
|
455
469
|
budget: SharedArrayBuffer | null;
|
|
470
|
+
cursors: {
|
|
471
|
+
indexTable: SharedArrayBuffer;
|
|
472
|
+
dataTable: SharedArrayBuffer;
|
|
473
|
+
stringTable: SharedArrayBuffer;
|
|
474
|
+
arrayTable: SharedArrayBuffer;
|
|
475
|
+
};
|
|
456
476
|
} {
|
|
457
477
|
return {
|
|
458
478
|
indexTable: this.indexTable.buffers,
|
|
@@ -466,6 +486,12 @@ export class SharedMemory {
|
|
|
466
486
|
indexTableMaxByteLength: this.indexTableMaxByteLength,
|
|
467
487
|
maxTotalBytes: this.maxTotalBytes,
|
|
468
488
|
budget: this.budgetBuffer,
|
|
489
|
+
cursors: {
|
|
490
|
+
indexTable: this.indexTable.cursorBuffer,
|
|
491
|
+
dataTable: this.dataTable.cursorBuffer,
|
|
492
|
+
stringTable: this.stringTable.cursorBuffer,
|
|
493
|
+
arrayTable: this.arrayTable.cursorBuffer,
|
|
494
|
+
},
|
|
469
495
|
};
|
|
470
496
|
}
|
|
471
497
|
|
|
@@ -485,6 +511,12 @@ export class SharedMemory {
|
|
|
485
511
|
indexTableMaxByteLength?: number;
|
|
486
512
|
maxTotalBytes?: number | null;
|
|
487
513
|
budget?: SharedArrayBuffer | null;
|
|
514
|
+
cursors?: {
|
|
515
|
+
indexTable?: SharedArrayBuffer;
|
|
516
|
+
dataTable?: SharedArrayBuffer;
|
|
517
|
+
stringTable?: SharedArrayBuffer;
|
|
518
|
+
arrayTable?: SharedArrayBuffer;
|
|
519
|
+
};
|
|
488
520
|
}): SharedMemory {
|
|
489
521
|
const indexBuffer = Array.isArray(buffers.indexTable)
|
|
490
522
|
? buffers.indexTable[0]
|
|
@@ -505,6 +537,7 @@ export class SharedMemory {
|
|
|
505
537
|
layoutVersion: buffers.layoutVersion,
|
|
506
538
|
refCount: buffers.refCount ?? undefined,
|
|
507
539
|
budget: buffers.budget ?? undefined,
|
|
540
|
+
cursors: buffers.cursors,
|
|
508
541
|
},
|
|
509
542
|
lock: new Mutex(buffers.lock),
|
|
510
543
|
});
|