amoradbx 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/amora.js ADDED
@@ -0,0 +1,1864 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+
5
+ const path = require('path');
6
+
7
+ const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
8
+
9
+ const DEC = new TextDecoder();
10
+
11
+ const ENC = new TextEncoder();
12
+
13
+ const CMD_BUF_SIZE = 1 << 19;
14
+
15
+ const AUTO_FLUSH_SIZE = (CMD_BUF_SIZE * 9) / 10 | 0;
16
+
17
+ const MAX_THREADS = 8;
18
+
19
+ const WORKER_TIMEOUT_MS = 60_000;
20
+
21
+ const WAL_PERSIST_EVERY = 128;
22
+
23
+ let _MAX_KEY_SIZE = 4096;
24
+
25
+ let _MAX_VALUE_SIZE = 1 << 20;
26
+
27
+ const SC_SIZE = 16384;
28
+
29
+ const SC_MASK = SC_SIZE - 1;
30
+
31
+ const _scKey = new Array(SC_SIZE).fill(null);
32
+
33
+ const _scEnc = new Array(SC_SIZE).fill(null);
34
+
35
+ const _scAge = new Uint32Array(SC_SIZE);
36
+
37
+ let _scTick = 0;
38
+
39
+ let _lastKey = null, _lastBytes = null;
40
+
41
+ function fnv1a(s) {
42
+
43
+ let h = 0x811c9dc5;
44
+
45
+ for (let i = 0, len = s.length; i < len; i++) {
46
+
47
+ h ^= s.charCodeAt(i);
48
+
49
+ h = Math.imul(h, 0x01000193);
50
+
51
+ }
52
+
53
+ return h >>> 0;
54
+
55
+ }
56
+
57
+ function enc(s) {
58
+
59
+ if (s === _lastKey) return _lastBytes;
60
+
61
+ const slot = fnv1a(s) & SC_MASK;
62
+
63
+ if (_scKey[slot] === s) {
64
+
65
+ _lastKey = s; _lastBytes = _scEnc[slot];
66
+
67
+ _scAge[slot] = ++_scTick;
68
+
69
+ return _lastBytes;
70
+
71
+ }
72
+
73
+ const b = ENC.encode(s);
74
+
75
+ _scKey[slot] = s; _scEnc[slot] = b;
76
+
77
+ _scAge[slot] = ++_scTick;
78
+
79
+ _lastKey = s; _lastBytes = b;
80
+
81
+ return b;
82
+
83
+ }
84
+
85
+ const _encBuf = new Uint8Array(MAX_THREADS > 0 ? 65536 : 4096);
86
+
87
+ function writeStr(dst, off, s) {
88
+
89
+ const len = s.length;
90
+
91
+ let isAscii = true;
92
+
93
+ for (let i = 0; i < len; i++) {
94
+
95
+ const c = s.charCodeAt(i);
96
+
97
+ if (c >= 128) { isAscii = false; break; }
98
+
99
+ dst[off++] = c;
100
+
101
+ }
102
+
103
+ if (isAscii) return off;
104
+
105
+ off -= len;
106
+
107
+ const result = ENC.encodeInto(s, dst.subarray(off));
108
+
109
+ return off + result.written;
110
+
111
+ }
112
+
113
+ function strByteLen(s) {
114
+
115
+ let bytes = 0;
116
+
117
+ for (let i = 0, len = s.length; i < len; i++) {
118
+
119
+ const c = s.charCodeAt(i);
120
+
121
+ if (c < 0x80) bytes += 1;
122
+
123
+ else if (c < 0x800) bytes += 2;
124
+
125
+ else if (c >= 0xD800 && c <= 0xDBFF) { bytes += 4; i++; }
126
+
127
+ else bytes += 3;
128
+
129
+ }
130
+
131
+ return bytes;
132
+
133
+ }
134
+
135
+ function isBytes(x) {
136
+
137
+ return x != null && (Buffer.isBuffer(x) || x instanceof Uint8Array);
138
+
139
+ }
140
+
141
+ function validateKey(kb) {
142
+
143
+ if (!kb || kb.length === 0) throw new RangeError('AmoraDB: chave vazia');
144
+
145
+ if (kb.length > _MAX_KEY_SIZE) throw new RangeError(`AmoraDB: chave muito longa (${kb.length} > ${_MAX_KEY_SIZE})`);
146
+
147
+ }
148
+
149
+ function validateValue(vb) {
150
+
151
+ if (vb && vb.length > _MAX_VALUE_SIZE) throw new RangeError(`AmoraDB: valor muito longo (${vb.length} > ${_MAX_VALUE_SIZE})`);
152
+
153
+ }
154
+
155
+ function writeSet(dst, off, key, val) {
156
+
157
+ const kl = strByteLen(key), vl = strByteLen(val);
158
+
159
+ dst[off] = 1;
160
+
161
+ dst[off + 1] = kl & 0xFF; dst[off + 2] = (kl >> 8) & 0xFF;
162
+
163
+ dst[off + 3] = vl & 0xFF; dst[off + 4] = (vl >> 8) & 0xFF;
164
+
165
+ off += 5;
166
+
167
+ off = writeStr(dst, off, key);
168
+
169
+ off = writeStr(dst, off, val);
170
+
171
+ return off;
172
+
173
+ }
174
+
175
+ function writeDel(dst, off, key) {
176
+
177
+ const kl = strByteLen(key);
178
+
179
+ dst[off] = 2;
180
+
181
+ dst[off + 1] = kl & 0xFF; dst[off + 2] = (kl >> 8) & 0xFF;
182
+
183
+ dst[off + 3] = 0; dst[off + 4] = 0;
184
+
185
+ off += 5;
186
+
187
+ off = writeStr(dst, off, key);
188
+
189
+ return off;
190
+
191
+ }
192
+
193
+ function writeKeyOnly(dst, off, key) {
194
+
195
+ const kl = strByteLen(key);
196
+
197
+ dst[off] = kl & 0xFF; dst[off + 1] = (kl >> 8) & 0xFF;
198
+
199
+ off += 2;
200
+
201
+ off = writeStr(dst, off, key);
202
+
203
+ return off;
204
+
205
+ }
206
+
207
+ function writeSetBytes(dst, off, kb, vb) {
208
+
209
+ const kl = kb.length >>> 0, vl = vb.length >>> 0;
210
+
211
+ dst[off] = 1;
212
+
213
+ dst[off + 1] = kl & 0xFF; dst[off + 2] = (kl >> 8) & 0xFF;
214
+
215
+ dst[off + 3] = vl & 0xFF; dst[off + 4] = (vl >> 8) & 0xFF;
216
+
217
+ off += 5;
218
+
219
+ dst.set(kb, off); off += kl;
220
+
221
+ dst.set(vb, off); off += vl;
222
+
223
+ return off;
224
+
225
+ }
226
+
227
+ function writeDelBytes(dst, off, kb) {
228
+
229
+ const kl = kb.length >>> 0;
230
+
231
+ dst[off] = 2;
232
+
233
+ dst[off + 1] = kl & 0xFF; dst[off + 2] = (kl >> 8) & 0xFF;
234
+
235
+ dst[off + 3] = 0; dst[off + 4] = 0;
236
+
237
+ off += 5;
238
+
239
+ dst.set(kb, off); off += kl;
240
+
241
+ return off;
242
+
243
+ }
244
+
245
+ function writeKeyOnlyBytes(dst, off, kb) {
246
+
247
+ const kl = kb.length >>> 0;
248
+
249
+ dst[off] = kl & 0xFF; dst[off + 1] = (kl >> 8) & 0xFF;
250
+
251
+ off += 2;
252
+
253
+ dst.set(kb, off); off += kl;
254
+
255
+ return off;
256
+
257
+ }
258
+
259
+ let _hrtimeBase = null;
260
+
261
+ function makeNowFn() {
262
+
263
+ if (typeof process !== 'undefined' && process.hrtime && process.hrtime.bigint) {
264
+
265
+ _hrtimeBase = process.hrtime.bigint();
266
+
267
+ return function jsNow() {
268
+
269
+ return Number(process.hrtime.bigint() - _hrtimeBase) / 1_000_000;
270
+
271
+ };
272
+
273
+ }
274
+
275
+ try {
276
+
277
+ const { performance: _perf } = require('perf_hooks');
278
+
279
+ return function jsNow() { return _perf.now(); };
280
+
281
+ } catch (_) {
282
+
283
+ return function jsNow() { return Date.now(); };
284
+
285
+ }
286
+
287
+ }
288
+
289
+ function makeWalHandlers(walPath, walSync) {
290
+
291
+ if (!walPath) {
292
+
293
+ return { flush: () => {}, load: () => 0 };
294
+
295
+ }
296
+
297
+ let _walFd = null;
298
+
299
+ return {
300
+
301
+ flush(ptr, len, memBuffer) {
302
+ const buf = Buffer.from(new Uint8Array(memBuffer, ptr, len));
303
+ let fd = null;
304
+ try {
305
+ fd = fs.openSync(walPath, 'w');
306
+ fs.writeSync(fd, buf);
307
+ if (walSync !== false) fs.fsyncSync(fd);
308
+ fs.closeSync(fd); fd = null;
309
+ } catch (err) {
310
+ if (fd != null) { try { fs.closeSync(fd); } catch (_) {} }
311
+ throw err;
312
+ }
313
+ },
314
+
315
+ load(ptr, maxLen, memBuffer) {
316
+
317
+ if (!fs.existsSync(walPath)) return 0;
318
+
319
+ let data;
320
+
321
+ try { data = fs.readFileSync(walPath); }
322
+
323
+ catch (_) { return 0; }
324
+
325
+ const n = Math.min(data.length, maxLen);
326
+
327
+ new Uint8Array(memBuffer, ptr, n).set(data.subarray(0, n));
328
+
329
+ return n;
330
+
331
+ },
332
+
333
+ };
334
+
335
+ }
336
+
337
+ if (!isMainThread && workerData && workerData.__amoraWorker) {
338
+
339
+ const { wasmBytes, sharedMem, cmdBufOffset, scratchOffset, tid } = workerData;
340
+
341
+ const now = makeNowFn();
342
+
343
+ const sharedMemory = new WebAssembly.Memory({
344
+
345
+ initial: sharedMem.byteLength >> 16,
346
+
347
+ maximum: 65536,
348
+
349
+ shared: true,
350
+
351
+ });
352
+
353
+ const mod = new WebAssembly.Module(wasmBytes);
354
+
355
+ const inst = new WebAssembly.Instance(mod, {
356
+
357
+ env: {
358
+
359
+ memory: sharedMemory,
360
+
361
+ js_now: now,
362
+
363
+ js_wal_flush: () => {},
364
+
365
+ js_wal_load: () => 0,
366
+
367
+ }
368
+
369
+ });
370
+
371
+ const e = inst.exports;
372
+
373
+ if (e.db_set_worker_mode) e.db_set_worker_mode();
374
+
375
+ const cmdView = new Uint8Array(sharedMem, cmdBufOffset, CMD_BUF_SIZE);
376
+
377
+ parentPort.on('message', (msg) => {
378
+
379
+ try {
380
+
381
+ if (msg.type === 'exec') {
382
+
383
+ const wasmU8 = new Uint8Array(sharedMemory.buffer);
384
+
385
+ wasmU8.set(new Uint8Array(sharedMem, cmdBufOffset, msg.cmdOff), cmdBufOffset);
386
+
387
+ const n = e.db_exec_cmdbuf_thread(cmdBufOffset, msg.cmdOff, msg.scratchOff);
388
+
389
+ parentPort.postMessage({ type: 'done', n });
390
+
391
+ } else if (msg.type === 'mget') {
392
+
393
+ const wasmU8 = new Uint8Array(sharedMemory.buffer);
394
+
395
+ wasmU8.set(new Uint8Array(sharedMem, cmdBufOffset, msg.cmdOff), cmdBufOffset);
396
+
397
+ const n = e.db_mget_cmdbuf(cmdBufOffset, msg.cmdOff, 8192);
398
+
399
+ const mgetOff = e.db_mget_buf_off ? e.db_mget_buf_off() : 0;
400
+
401
+ if (mgetOff) {
402
+
403
+ const resultSize = Math.min(n * 8 + 4, 65536);
404
+
405
+ new Uint8Array(sharedMem, mgetOff, resultSize).set(
406
+
407
+ new Uint8Array(sharedMemory.buffer, mgetOff, resultSize)
408
+
409
+ );
410
+
411
+ }
412
+
413
+ parentPort.postMessage({ type: 'done', n });
414
+
415
+ } else {
416
+
417
+ parentPort.postMessage({ type: 'done', n: 0 });
418
+
419
+ }
420
+
421
+ } catch (err) {
422
+
423
+ parentPort.postMessage({ type: 'error', message: err.message });
424
+
425
+ }
426
+
427
+ });
428
+
429
+ parentPort.postMessage({ type: 'ready' });
430
+
431
+ }
432
+
433
+ class WorkerPool {
434
+
435
+ constructor(wasmBytes, sharedMem, n) {
436
+
437
+ this._workers = [];
438
+
439
+ this._ready = [];
440
+
441
+ this._queue = [];
442
+
443
+ this._n = n;
444
+
445
+ this._robin = 0;
446
+
447
+ for (let i = 0; i < n; i++) {
448
+
449
+ const cmdBufOffset = sharedMem.byteLength - CMD_BUF_SIZE * (i + 1);
450
+
451
+ const scratchOff = 8192 * 16 + 64 + i * 8192;
452
+
453
+ const w = new Worker(__filename, {
454
+
455
+ workerData: {
456
+
457
+ __amoraWorker: true,
458
+
459
+ wasmBytes, sharedMem,
460
+
461
+ tid: i, cmdBufOffset,
462
+
463
+ scratchOffset: scratchOff,
464
+
465
+ }
466
+
467
+ });
468
+
469
+ w._tid = i;
470
+
471
+ w._cmdBufOff = cmdBufOffset;
472
+
473
+ w._scratchOff = scratchOff;
474
+
475
+ w._busy = false;
476
+
477
+ w._cmdBuf = new Uint8Array(sharedMem, cmdBufOffset, CMD_BUF_SIZE);
478
+
479
+ w._timeoutId = null;
480
+
481
+ w._pending = null;
482
+
483
+ w.on('message', (msg) => {
484
+
485
+ if (w._timeoutId) { clearTimeout(w._timeoutId); w._timeoutId = null; }
486
+
487
+ if (msg.type === 'ready') {
488
+
489
+ this._ready.push(w);
490
+
491
+ this._drain();
492
+
493
+ } else if (msg.type === 'done') {
494
+
495
+ w._busy = false;
496
+
497
+ if (w._pending) {
498
+
499
+ const { resolve } = w._pending;
500
+
501
+ w._pending = null;
502
+
503
+ this._ready.push(w);
504
+
505
+ this._drain();
506
+
507
+ resolve(msg.n);
508
+
509
+ }
510
+
511
+ } else if (msg.type === 'error') {
512
+
513
+ w._busy = false;
514
+
515
+ if (w._pending) {
516
+
517
+ const { reject } = w._pending;
518
+
519
+ w._pending = null;
520
+
521
+ this._ready.push(w);
522
+
523
+ this._drain();
524
+
525
+ reject(new Error('Worker: ' + msg.message));
526
+
527
+ }
528
+
529
+ }
530
+
531
+ });
532
+
533
+ w.on('error', (err) => {
534
+
535
+ if (w._timeoutId) { clearTimeout(w._timeoutId); w._timeoutId = null; }
536
+
537
+ if (w._pending) { w._pending.reject(err); w._pending = null; }
538
+
539
+ w._busy = false;
540
+
541
+ });
542
+
543
+ this._workers.push(w);
544
+
545
+ }
546
+
547
+ }
548
+
549
+ _drain() {
550
+
551
+ while (this._ready.length > 0 && this._queue.length > 0) {
552
+
553
+ const w = this._ready.shift(), task = this._queue.shift();
554
+
555
+ this._dispatch_to(w, task);
556
+
557
+ }
558
+
559
+ }
560
+
561
+ _dispatch_to(w, task) {
562
+
563
+ w._busy = true;
564
+
565
+ w._pending = task;
566
+
567
+ w._timeoutId = setTimeout(() => {
568
+
569
+ if (w._pending) {
570
+
571
+ const { reject } = w._pending;
572
+
573
+ w._pending = null;
574
+
575
+ w._busy = false;
576
+
577
+ this._ready.push(w);
578
+
579
+ this._drain();
580
+
581
+ reject(new Error('AmoraDB: worker timeout'));
582
+
583
+ }
584
+
585
+ }, WORKER_TIMEOUT_MS);
586
+
587
+ w.postMessage(task.msg);
588
+
589
+ }
590
+
591
+ dispatch(worker, msg) {
592
+
593
+ return new Promise((resolve, reject) => {
594
+
595
+ const task = { msg, resolve, reject };
596
+
597
+ const idx = this._ready.indexOf(worker);
598
+
599
+ if (!worker._busy && idx !== -1) {
600
+
601
+ this._ready.splice(idx, 1);
602
+
603
+ this._dispatch_to(worker, task);
604
+
605
+ } else {
606
+
607
+ this._queue.push(task);
608
+
609
+ }
610
+
611
+ });
612
+
613
+ }
614
+
615
+ getNextWorker() {
616
+
617
+ const w = this._workers[this._robin % this._n];
618
+
619
+ this._robin = (this._robin + 1) % this._n;
620
+
621
+ return w;
622
+
623
+ }
624
+
625
+ getWorker(idx) { return this._workers[idx % this._n]; }
626
+
627
+ async terminate() {
628
+
629
+ await Promise.all(this._workers.map(w => {
630
+
631
+ if (w._timeoutId) clearTimeout(w._timeoutId);
632
+
633
+ return w.terminate();
634
+
635
+ }));
636
+
637
+ }
638
+
639
+ }
640
+
641
+ class AmoraDB {
642
+
643
+ constructor(inst, mem, walHandlers, opts) {
644
+
645
+ this._e = inst.exports;
646
+
647
+ this._mem = mem;
648
+
649
+ this._walHandlers = walHandlers;
650
+
651
+ this._walPath = (opts && opts.walPath) || null;
652
+
653
+ this._walSync = opts && opts.walSync !== false;
654
+
655
+ this._inBatch = 0;
656
+
657
+ this._autoFlush = true;
658
+
659
+ this._viewsDirty = false;
660
+
661
+ this._buf = null;
662
+
663
+ this._scratchPtr = 0;
664
+
665
+ this._mgetBufPtr = 0;
666
+
667
+ this._kbufPtr = 0;
668
+
669
+ this._vbufPtr = 0;
670
+
671
+ this._cmdBufPtr = 0;
672
+
673
+ this._scratchVlenOff = 0;
674
+
675
+ this._scratchVoffOff = 4;
676
+
677
+ this._dv = null;
678
+
679
+ this._u8raw = null;
680
+
681
+ this._u8kbuf = null;
682
+
683
+ this._u8vbuf = null;
684
+
685
+ this._u8cmd = null;
686
+
687
+ this._cmdOff = 0;
688
+
689
+ this._walPendingOps = 0;
690
+
691
+ this._pool = null;
692
+
693
+ this._wasmBytes = null;
694
+
695
+ this._nThreads = 0;
696
+
697
+ this._tempAllocs = [];
698
+
699
+ }
700
+
701
+ static open(wasmPath, opts = {}) {
702
+
703
+ let bytes;
704
+
705
+ if (isBytes(wasmPath)) {
706
+
707
+ bytes = wasmPath;
708
+
709
+ } else {
710
+
711
+ let p = wasmPath || opts.wasmPath || null;
712
+
713
+ if (!p) {
714
+
715
+ const dir = __dirname;
716
+
717
+ const cands = [
718
+
719
+ path.join(dir, 'amora_core_mt_simd.wasm'),
720
+
721
+ path.join(dir, 'amora_core_simd.wasm'),
722
+
723
+ path.join(dir, 'amora_core_mt.wasm'),
724
+
725
+ path.join(dir, 'amora_core.wasm'),
726
+
727
+ ];
728
+
729
+ for (const c of cands) { if (fs.existsSync(c)) { p = c; break; } }
730
+
731
+ if (!p) throw new Error('AmoraDB: nenhum arquivo .wasm encontrado');
732
+
733
+ }
734
+
735
+ bytes = fs.readFileSync(p);
736
+
737
+ }
738
+
739
+ const nThreads = Math.min(opts.threads || 1, MAX_THREADS);
740
+
741
+ const useShared = nThreads > 1;
742
+
743
+ const extraPages = useShared ? nThreads * 8 : 0;
744
+
745
+ const initPages = (opts.initialPages || 4096) + extraPages;
746
+
747
+ const maxPages = opts.maxPages || 65536;
748
+
749
+ let mem;
750
+
751
+ try {
752
+
753
+ mem = new WebAssembly.Memory({ initial: initPages, maximum: maxPages, shared: true });
754
+
755
+ } catch (_) {
756
+
757
+ mem = new WebAssembly.Memory({ initial: initPages, maximum: maxPages });
758
+
759
+ }
760
+
761
+ const now = makeNowFn();
762
+
763
+ const walPath = opts.walPath || null;
764
+
765
+ const walSync = opts.walSync !== false;
766
+
767
+ const handlers = makeWalHandlers(walPath, walSync);
768
+
769
+ const mod = new WebAssembly.Module(bytes);
770
+
771
+ const inst = new WebAssembly.Instance(mod, {
772
+
773
+ env: {
774
+
775
+ memory: mem,
776
+
777
+ js_now: now,
778
+
779
+ js_wal_flush: (ptr, len) => {
780
+
781
+ handlers.flush(ptr, len, mem.buffer);
782
+
783
+ },
784
+
785
+ js_wal_load: (ptr, maxLen) => {
786
+
787
+ return handlers.load(ptr, maxLen, mem.buffer);
788
+
789
+ },
790
+
791
+ }
792
+
793
+ });
794
+
795
+ const db = new AmoraDB(inst, mem, handlers, opts);
796
+
797
+ db._autoFlush = opts.autoFlush !== false;
798
+
799
+ db._wasmBytes = bytes;
800
+
801
+ db._nThreads = nThreads;
802
+
803
+ if (!db._e.db_init(opts.cap || 65536))
804
+
805
+ throw new Error('AmoraDB: db_init falhou — memória insuficiente');
806
+
807
+ db._setup();
808
+
809
+ if (opts.maxMemoryBytes && db._e.db_set_memory_limit) {
810
+
811
+ db._e.db_set_memory_limit(opts.maxMemoryBytes >>> 0);
812
+
813
+ }
814
+
815
+ if (useShared && mem.buffer instanceof SharedArrayBuffer)
816
+
817
+ db._pool = new WorkerPool(bytes, mem.buffer, nThreads);
818
+
819
+ if (walPath && fs.existsSync(walPath)) {
820
+
821
+ const replayed = db._e.db_restore();
822
+
823
+ if (typeof replayed === 'number' && replayed < 0) {
824
+
825
+ console.warn(`AmoraDB: replay WAL completou com ${-replayed} registros corrompidos ignorados`);
826
+
827
+ }
828
+
829
+ try { fs.truncateSync(walPath, 0); } catch (_) {}
830
+
831
+ }
832
+
833
+ return db;
834
+
835
+ }
836
+
837
+ _setup() {
838
+
839
+ const e = this._e;
840
+
841
+ if (e.db_max_key_size) _MAX_KEY_SIZE = e.db_max_key_size() >>> 0;
842
+
843
+ if (e.db_max_value_size) _MAX_VALUE_SIZE = e.db_max_value_size() >>> 0;
844
+
845
+ this._scratchPtr = e.db_scratch_off() >>> 0;
846
+
847
+ this._kbufPtr = e.db_kbuf() >>> 0;
848
+
849
+ this._vbufPtr = e.db_vbuf() >>> 0;
850
+
851
+ this._mgetBufPtr = e.db_mget_buf_off ? (e.db_mget_buf_off() >>> 0) : this._scratchPtr + 4;
852
+
853
+ this._cmdBufPtr = e.mem_alloc(CMD_BUF_SIZE) >>> 0;
854
+
855
+ if (!this._cmdBufPtr) throw new Error('AmoraDB: falha ao alocar CmdBuf');
856
+
857
+ if (e.db_scratch_vlen_off) this._scratchVlenOff = e.db_scratch_vlen_off() >>> 0;
858
+
859
+ if (e.db_scratch_voff_off) this._scratchVoffOff = e.db_scratch_voff_off() >>> 0;
860
+
861
+ this._rebuildViews();
862
+
863
+ }
864
+
865
+ _rebuildViews() {
866
+
867
+ const buf = this._mem.buffer;
868
+
869
+ this._buf = buf;
870
+
871
+ this._viewsDirty = false;
872
+
873
+ this._dv = new DataView(buf);
874
+
875
+ this._u8raw = new Uint8Array(buf);
876
+
877
+ this._u8kbuf = new Uint8Array(buf, this._kbufPtr, _MAX_KEY_SIZE);
878
+
879
+ this._u8vbuf = new Uint8Array(buf, this._vbufPtr, Math.min(_MAX_VALUE_SIZE + 1, buf.byteLength - this._vbufPtr));
880
+
881
+ this._u8cmd = new Uint8Array(buf, this._cmdBufPtr, CMD_BUF_SIZE);
882
+
883
+ }
884
+
885
+ _checkBuf() {
886
+
887
+ if (this._viewsDirty || this._buf !== this._mem.buffer)
888
+
889
+ this._rebuildViews();
890
+
891
+ }
892
+
893
+ _maybeInvalidate() {
894
+
895
+ if (this._mem.buffer !== this._buf) this._viewsDirty = true;
896
+
897
+ }
898
+
899
+ flush() {
900
+
901
+ const off = this._cmdOff;
902
+
903
+ if (off === 0) {
904
+
905
+ if (this._walPath && !this._inBatch && this._walPendingOps > 0) {
906
+
907
+ this._e.db_persist();
908
+
909
+ this._walPendingOps = 0;
910
+
911
+ }
912
+
913
+ return;
914
+
915
+ }
916
+
917
+ this._checkBuf();
918
+
919
+ this._e.db_exec_cmdbuf(this._cmdBufPtr, off);
920
+
921
+ this._maybeInvalidate();
922
+
923
+ this._checkBuf();
924
+
925
+ this._cmdOff = 0;
926
+
927
+ if (this._walPath && !this._inBatch) {
928
+
929
+ this._e.db_persist();
930
+
931
+ this._walPendingOps = 0;
932
+
933
+ }
934
+
935
+ }
936
+
937
+ set(key, value) {
938
+
939
+ const val = typeof value === 'string' ? value : String(value);
940
+
941
+ if (this._cmdOff > 0) this.flush();
942
+
943
+ const kb = enc(key), vb = enc(val);
944
+
945
+ validateKey(kb); validateValue(vb);
946
+
947
+ this._checkBuf();
948
+
949
+ this._u8kbuf.set(kb);
950
+
951
+ this._u8vbuf.set(vb);
952
+
953
+ const ok = this._e.db_set_inplace(kb.length, vb.length) === 1;
954
+
955
+ this._maybeInvalidate();
956
+
957
+ this._checkBuf();
958
+
959
+ if (ok && this._walPath && !this._inBatch) {
960
+
961
+ if (++this._walPendingOps >= WAL_PERSIST_EVERY) {
962
+
963
+ this._e.db_persist();
964
+
965
+ this._walPendingOps = 0;
966
+
967
+ }
968
+
969
+ }
970
+
971
+ return ok;
972
+
973
+ }
974
+
975
+ setBuffered(key, value) {
976
+
977
+ const val = typeof value === 'string' ? value : String(value);
978
+
979
+ const kl = strByteLen(key), vl = strByteLen(val);
980
+
981
+ if (kl > _MAX_KEY_SIZE) throw new RangeError('AmoraDB: chave muito longa');
982
+
983
+ if (vl > _MAX_VALUE_SIZE) throw new RangeError('AmoraDB: valor muito longo');
984
+
985
+ this._checkBuf();
986
+
987
+ if (this._cmdOff + 5 + kl + vl > AUTO_FLUSH_SIZE) {
988
+
989
+ this._e.db_exec_cmdbuf(this._cmdBufPtr, this._cmdOff);
990
+
991
+ this._maybeInvalidate();
992
+
993
+ this._checkBuf();
994
+
995
+ this._cmdOff = 0;
996
+
997
+ if (this._walPath && !this._inBatch) this._e.db_persist();
998
+
999
+ }
1000
+
1001
+ this._cmdOff = writeSet(this._u8cmd, this._cmdOff, key, val);
1002
+
1003
+ }
1004
+
1005
+ setBytes(keyBytes, valueBytes) {
1006
+
1007
+ if (!isBytes(keyBytes) || !isBytes(valueBytes))
1008
+
1009
+ throw new TypeError('setBytes: esperado Uint8Array/Buffer');
1010
+
1011
+ validateKey(keyBytes); validateValue(valueBytes);
1012
+
1013
+ if (this._cmdOff > 0) this.flush();
1014
+
1015
+ this._checkBuf();
1016
+
1017
+ this._u8kbuf.set(keyBytes);
1018
+
1019
+ this._u8vbuf.set(valueBytes);
1020
+
1021
+ const ok = this._e.db_set_inplace(keyBytes.length >>> 0, valueBytes.length >>> 0) === 1;
1022
+
1023
+ this._maybeInvalidate();
1024
+
1025
+ this._checkBuf();
1026
+
1027
+ if (ok && this._walPath && !this._inBatch) {
1028
+
1029
+ if (++this._walPendingOps >= WAL_PERSIST_EVERY) {
1030
+
1031
+ this._e.db_persist();
1032
+
1033
+ this._walPendingOps = 0;
1034
+
1035
+ }
1036
+
1037
+ }
1038
+
1039
+ return ok;
1040
+
1041
+ }
1042
+
1043
+ setSync(key, value) { return this.set(key, value); }
1044
+
1045
+ get(key) {
1046
+
1047
+ if (this._cmdOff > 0) this.flush();
1048
+
1049
+ const kb = enc(key);
1050
+
1051
+ validateKey(kb);
1052
+
1053
+ this._checkBuf();
1054
+
1055
+ this._u8kbuf.set(kb);
1056
+
1057
+ const found = this._e.db_get_inplace(kb.length);
1058
+
1059
+ if (!found) return null;
1060
+
1061
+ const sp = this._scratchPtr;
1062
+
1063
+ const vlen = this._dv.getUint32(sp + this._scratchVlenOff, true);
1064
+
1065
+ const voff = this._dv.getUint32(sp + this._scratchVoffOff, true);
1066
+
1067
+ if (!voff || !vlen) return null;
1068
+
1069
+ return DEC.decode(this._u8raw.subarray(voff, voff + vlen));
1070
+
1071
+ }
1072
+
1073
+ getBytes(keyBytes) {
1074
+
1075
+ if (!isBytes(keyBytes)) throw new TypeError('getBytes: esperado Uint8Array/Buffer');
1076
+
1077
+ validateKey(keyBytes);
1078
+
1079
+ if (this._cmdOff > 0) this.flush();
1080
+
1081
+ this._checkBuf();
1082
+
1083
+ this._u8kbuf.set(keyBytes);
1084
+
1085
+ const found = this._e.db_get_inplace(keyBytes.length >>> 0);
1086
+
1087
+ if (!found) return null;
1088
+
1089
+ const sp = this._scratchPtr;
1090
+
1091
+ const vlen = this._dv.getUint32(sp + this._scratchVlenOff, true);
1092
+
1093
+ const voff = this._dv.getUint32(sp + this._scratchVoffOff, true);
1094
+
1095
+ if (!voff || !vlen) return null;
1096
+
1097
+ return Buffer.from(this._u8raw.slice(voff, voff + vlen));
1098
+
1099
+ }
1100
+
1101
+ has(key) {
1102
+
1103
+ if (this._cmdOff > 0) this.flush();
1104
+
1105
+ const kb = enc(key);
1106
+
1107
+ validateKey(kb);
1108
+
1109
+ this._checkBuf();
1110
+
1111
+ this._u8kbuf.set(kb);
1112
+
1113
+ return this._e.db_has_inplace(kb.length) === 1;
1114
+
1115
+ }
1116
+
1117
+ hasBytes(keyBytes) {
1118
+
1119
+ if (!isBytes(keyBytes)) throw new TypeError('hasBytes: esperado Uint8Array/Buffer');
1120
+
1121
+ validateKey(keyBytes);
1122
+
1123
+ if (this._cmdOff > 0) this.flush();
1124
+
1125
+ this._checkBuf();
1126
+
1127
+ this._u8kbuf.set(keyBytes);
1128
+
1129
+ return this._e.db_has_inplace(keyBytes.length >>> 0) === 1;
1130
+
1131
+ }
1132
+
1133
+ hasPrefix(prefix) {
1134
+
1135
+ if (this._cmdOff > 0) this.flush();
1136
+
1137
+ const pb = enc(prefix);
1138
+
1139
+ validateKey(pb);
1140
+
1141
+ this._checkBuf();
1142
+
1143
+ this._u8kbuf.set(pb);
1144
+
1145
+ return this._e.db_has_prefix(this._kbufPtr, pb.length) === 1;
1146
+
1147
+ }
1148
+
1149
+ countPrefix(prefix) {
1150
+
1151
+ if (this._cmdOff > 0) this.flush();
1152
+
1153
+ const pb = enc(prefix);
1154
+
1155
+ validateKey(pb);
1156
+
1157
+ this._checkBuf();
1158
+
1159
+ this._u8kbuf.set(pb);
1160
+
1161
+ return this._e.db_count_prefix(this._kbufPtr, pb.length) >>> 0;
1162
+
1163
+ }
1164
+
1165
+ delete(key) {
1166
+
1167
+ if (this._cmdOff > 0) this.flush();
1168
+
1169
+ const kb = enc(key);
1170
+
1171
+ validateKey(kb);
1172
+
1173
+ this._checkBuf();
1174
+
1175
+ this._u8kbuf.set(kb);
1176
+
1177
+ const ok = this._e.db_delete_inplace(kb.length) === 1;
1178
+
1179
+ this._maybeInvalidate();
1180
+
1181
+ this._checkBuf();
1182
+
1183
+ if (ok && this._walPath && !this._inBatch) {
1184
+
1185
+ if (++this._walPendingOps >= WAL_PERSIST_EVERY) {
1186
+
1187
+ this._e.db_persist();
1188
+
1189
+ this._walPendingOps = 0;
1190
+
1191
+ }
1192
+
1193
+ }
1194
+
1195
+ return ok;
1196
+
1197
+ }
1198
+
1199
+ deleteBytes(keyBytes) {
1200
+
1201
+ if (!isBytes(keyBytes)) throw new TypeError('deleteBytes: esperado Uint8Array/Buffer');
1202
+
1203
+ validateKey(keyBytes);
1204
+
1205
+ if (this._cmdOff > 0) this.flush();
1206
+
1207
+ this._checkBuf();
1208
+
1209
+ this._u8kbuf.set(keyBytes);
1210
+
1211
+ const ok = this._e.db_delete_inplace(keyBytes.length >>> 0) === 1;
1212
+
1213
+ this._maybeInvalidate();
1214
+
1215
+ this._checkBuf();
1216
+
1217
+ if (ok && this._walPath && !this._inBatch) {
1218
+
1219
+ if (++this._walPendingOps >= WAL_PERSIST_EVERY) {
1220
+
1221
+ this._e.db_persist();
1222
+
1223
+ this._walPendingOps = 0;
1224
+
1225
+ }
1226
+
1227
+ }
1228
+
1229
+ return ok;
1230
+
1231
+ }
1232
+
1233
+ deleteSync(key) { return this.delete(key); }
1234
+
1235
+ mget(keys) {
1236
+
1237
+ if (this._cmdOff > 0) this.flush();
1238
+
1239
+ const e = this._e, cmd = this._u8cmd;
1240
+
1241
+ let off = 0;
1242
+
1243
+ this._checkBuf();
1244
+
1245
+ for (let i = 0; i < keys.length; i++) {
1246
+
1247
+ const kl = strByteLen(keys[i]);
1248
+
1249
+ if (kl > _MAX_KEY_SIZE) throw new RangeError('mget: chave muito longa');
1250
+
1251
+ if (off + 2 + kl > CMD_BUF_SIZE) break;
1252
+
1253
+ off = writeKeyOnly(cmd, off, keys[i]);
1254
+
1255
+ }
1256
+
1257
+ const n = e.db_mget_cmdbuf(this._cmdBufPtr, off, keys.length);
1258
+
1259
+ this._maybeInvalidate();
1260
+
1261
+ this._checkBuf();
1262
+
1263
+ const out = new Array(n);
1264
+
1265
+ const dv = this._dv, mp = this._mgetBufPtr + 4, raw = this._u8raw;
1266
+
1267
+ for (let i = 0; i < n; i++) {
1268
+
1269
+ const base = mp + i * 8;
1270
+
1271
+ const vptr = dv.getUint32(base, true);
1272
+
1273
+ const vlen = dv.getUint32(base + 4, true);
1274
+
1275
+ out[i] = vptr ? DEC.decode(raw.subarray(vptr, vptr + vlen)) : null;
1276
+
1277
+ }
1278
+
1279
+ return out;
1280
+
1281
+ }
1282
+
1283
+ mgetBytes(keysBytes) {
1284
+
1285
+ if (this._cmdOff > 0) this.flush();
1286
+
1287
+ const e = this._e, cmd = this._u8cmd;
1288
+
1289
+ let off = 0;
1290
+
1291
+ this._checkBuf();
1292
+
1293
+ for (let i = 0; i < keysBytes.length; i++) {
1294
+
1295
+ const kb = keysBytes[i];
1296
+
1297
+ if (!isBytes(kb)) throw new TypeError('mgetBytes: esperado array de Uint8Array/Buffer');
1298
+
1299
+ validateKey(kb);
1300
+
1301
+ const kl = kb.length >>> 0;
1302
+
1303
+ if (off + 2 + kl > CMD_BUF_SIZE) break;
1304
+
1305
+ off = writeKeyOnlyBytes(cmd, off, kb);
1306
+
1307
+ }
1308
+
1309
+ const n = e.db_mget_cmdbuf(this._cmdBufPtr, off, keysBytes.length);
1310
+
1311
+ this._maybeInvalidate();
1312
+
1313
+ this._checkBuf();
1314
+
1315
+ const out = new Array(n), dv = this._dv, mp = this._mgetBufPtr + 4, raw = this._u8raw;
1316
+
1317
+ for (let i = 0; i < n; i++) {
1318
+
1319
+ const base = mp + i * 8;
1320
+
1321
+ const vptr = dv.getUint32(base, true);
1322
+
1323
+ const vlen = dv.getUint32(base + 4, true);
1324
+
1325
+ out[i] = vptr ? Buffer.from(raw.slice(vptr, vptr + vlen)) : null;
1326
+
1327
+ }
1328
+
1329
+ return out;
1330
+
1331
+ }
1332
+
1333
+ async mgetAsync(keys) {
1334
+
1335
+ if (!this._pool) return this.mget(keys);
1336
+
1337
+ if (this._cmdOff > 0) this.flush();
1338
+
1339
+ const w = this._pool.getNextWorker(), cmd = w._cmdBuf;
1340
+
1341
+ let off = 0;
1342
+
1343
+ for (let i = 0; i < keys.length; i++) {
1344
+
1345
+ const kl = strByteLen(keys[i]);
1346
+
1347
+ if (kl > _MAX_KEY_SIZE) throw new RangeError('mgetAsync: chave muito longa');
1348
+
1349
+ if (off + 2 + kl > CMD_BUF_SIZE) break;
1350
+
1351
+ off = writeKeyOnly(cmd, off, keys[i]);
1352
+
1353
+ }
1354
+
1355
+ await this._pool.dispatch(w, { type: 'mget', cmdOff: off });
1356
+
1357
+ this._checkBuf();
1358
+
1359
+ const dv = this._dv, mp = this._mgetBufPtr + 4;
1360
+
1361
+ const raw = this._u8raw;
1362
+
1363
+ const n = dv.getUint32(this._mgetBufPtr, true), out = new Array(n);
1364
+
1365
+ for (let i = 0; i < n; i++) {
1366
+
1367
+ const base = mp + i * 8;
1368
+
1369
+ const vptr = dv.getUint32(base, true);
1370
+
1371
+ const vlen = dv.getUint32(base + 4, true);
1372
+
1373
+ out[i] = vptr ? DEC.decode(raw.subarray(vptr, vptr + vlen)) : null;
1374
+
1375
+ }
1376
+
1377
+ return out;
1378
+
1379
+ }
1380
+
1381
+ async setParallel(entries) {
1382
+
1383
+ if (!this._pool || entries.length < 100) {
1384
+
1385
+ for (const [k, v] of entries) this.set(k, v);
1386
+
1387
+ return;
1388
+
1389
+ }
1390
+
1391
+ if (this._cmdOff > 0) this.flush();
1392
+
1393
+ const n = this._pool._n, sz = Math.ceil(entries.length / n), ops = [];
1394
+
1395
+ for (let t = 0; t < n; t++) {
1396
+
1397
+ const slice = entries.slice(t * sz, (t + 1) * sz);
1398
+
1399
+ if (slice.length === 0) break;
1400
+
1401
+ const w = this._pool.getWorker(t), cmd = w._cmdBuf;
1402
+
1403
+ let off = 0;
1404
+
1405
+ for (const [k, v] of slice) {
1406
+
1407
+ const val = typeof v === 'string' ? v : String(v);
1408
+
1409
+ const kl = strByteLen(k), vl = strByteLen(val);
1410
+
1411
+ if (kl > _MAX_KEY_SIZE || vl > _MAX_VALUE_SIZE) continue;
1412
+
1413
+ if (off + 5 + kl + vl > AUTO_FLUSH_SIZE) break;
1414
+
1415
+ off = writeSet(cmd, off, k, val);
1416
+
1417
+ }
1418
+
1419
+ ops.push(this._pool.dispatch(w, { type: 'exec', cmdOff: off, scratchOff: w._scratchOff }));
1420
+
1421
+ }
1422
+
1423
+ await Promise.all(ops);
1424
+
1425
+ this._maybeInvalidate();
1426
+
1427
+ this._checkBuf();
1428
+
1429
+ }
1430
+
1431
+ batch(ops) {
1432
+
1433
+ if (this._cmdOff > 0) this.flush();
1434
+
1435
+ const e = this._e, cmd = this._u8cmd;
1436
+
1437
+ e.db_batch_begin();
1438
+
1439
+ this._inBatch = 1;
1440
+
1441
+ try {
1442
+
1443
+ let off = 0;
1444
+
1445
+ for (const op of ops) {
1446
+
1447
+ const val = op.op === 'set'
1448
+
1449
+ ? (typeof op.value === 'string' ? op.value : String(op.value))
1450
+
1451
+ : null;
1452
+
1453
+ const kl = strByteLen(op.key);
1454
+
1455
+ const vl = val ? strByteLen(val) : 0;
1456
+
1457
+ if (kl > _MAX_KEY_SIZE) throw new RangeError(`batch: chave muito longa: ${op.key}`);
1458
+
1459
+ if (vl > _MAX_VALUE_SIZE) throw new RangeError('batch: valor muito longo');
1460
+
1461
+ const need = 5 + kl + vl;
1462
+
1463
+ if (off + need > AUTO_FLUSH_SIZE) {
1464
+
1465
+ e.db_batch_exec_cmdbuf(this._cmdBufPtr, off);
1466
+
1467
+ this._maybeInvalidate();
1468
+
1469
+ this._checkBuf();
1470
+
1471
+ off = 0;
1472
+
1473
+ }
1474
+
1475
+ off = op.op === 'set'
1476
+
1477
+ ? writeSet(cmd, off, op.key, val)
1478
+
1479
+ : writeDel(cmd, off, op.key);
1480
+
1481
+ }
1482
+
1483
+ if (off > 0) {
1484
+
1485
+ e.db_batch_exec_cmdbuf(this._cmdBufPtr, off);
1486
+
1487
+ this._maybeInvalidate();
1488
+
1489
+ this._checkBuf();
1490
+
1491
+ }
1492
+
1493
+ e.db_batch_commit();
1494
+
1495
+ this._inBatch = 0;
1496
+
1497
+ if (this._walPath) e.db_persist();
1498
+
1499
+ } catch (err) {
1500
+
1501
+ this._inBatch = 0;
1502
+
1503
+ e.db_batch_rollback();
1504
+
1505
+ this._maybeInvalidate();
1506
+
1507
+ this._checkBuf();
1508
+
1509
+ throw err;
1510
+
1511
+ }
1512
+
1513
+ }
1514
+
1515
+ scan(prefix) {
1516
+
1517
+ if (this._cmdOff > 0) this.flush();
1518
+
1519
+ const pb = enc(prefix);
1520
+
1521
+ validateKey(pb);
1522
+
1523
+ this._checkBuf();
1524
+
1525
+ this._u8kbuf.set(pb);
1526
+
1527
+ return this._readScan(this._e.db_scan_prefix(this._kbufPtr, pb.length));
1528
+
1529
+ }
1530
+
1531
+ range(from, to) {
1532
+
1533
+ if (this._cmdOff > 0) this.flush();
1534
+
1535
+ const fb = enc(from), tb = enc(to);
1536
+
1537
+ validateKey(fb); validateKey(tb);
1538
+
1539
+ this._checkBuf();
1540
+
1541
+ const raw = this._u8raw;
1542
+
1543
+ const fp = this._e.mem_alloc(fb.length) >>> 0;
1544
+
1545
+ const tp = this._e.mem_alloc(tb.length) >>> 0;
1546
+
1547
+ if (!fp || !tp) throw new Error('AmoraDB: range: falha ao alocar buffers');
1548
+
1549
+ raw.set(fb, fp); raw.set(tb, tp);
1550
+
1551
+ const result = this._readScan(this._e.db_scan_range(fp, fb.length, tp, tb.length));
1552
+
1553
+ return result;
1554
+
1555
+ }
1556
+
1557
+ _readScan(cnt) {
1558
+
1559
+ const dv = this._dv, sp = this._scratchPtr, raw = this._u8raw;
1560
+
1561
+ const RESULTS_OFF = 16;
1562
+
1563
+ const out = new Array(cnt);
1564
+
1565
+ for (let i = 0; i < cnt; i++) {
1566
+
1567
+ const base = sp + RESULTS_OFF + i * 16;
1568
+
1569
+ const ko = dv.getUint32(base, true);
1570
+
1571
+ const kl = dv.getUint32(base + 4, true);
1572
+
1573
+ const vo = dv.getUint32(base + 8, true);
1574
+
1575
+ const vl = dv.getUint32(base + 12, true);
1576
+
1577
+ out[i] = {
1578
+
1579
+ key: ko ? DEC.decode(raw.subarray(ko, ko + kl)) : '',
1580
+
1581
+ value: vo ? DEC.decode(raw.subarray(vo, vo + vl)) : '',
1582
+
1583
+ };
1584
+
1585
+ }
1586
+
1587
+ return out;
1588
+
1589
+ }
1590
+
1591
+ export(maxBytes) {
1592
+
1593
+ if (this._cmdOff > 0) this.flush();
1594
+
1595
+ maxBytes = maxBytes || 128 * 1024 * 1024;
1596
+
1597
+ this._checkBuf();
1598
+
1599
+ const snapPtr = this._e.mem_alloc(maxBytes) >>> 0;
1600
+
1601
+ if (!snapPtr) throw new Error('AmoraDB: export: sem memória');
1602
+
1603
+ const written = this._e.db_export_snapshot(snapPtr, maxBytes) >>> 0;
1604
+
1605
+ if (!written) throw new Error('AmoraDB: export falhou');
1606
+
1607
+ this._maybeInvalidate();
1608
+
1609
+ this._checkBuf();
1610
+
1611
+ return Buffer.from(this._u8raw.slice(snapPtr, snapPtr + written));
1612
+
1613
+ }
1614
+
1615
+ import(buf) {
1616
+
1617
+ if (!isBytes(buf)) throw new TypeError('import: esperado Buffer/Uint8Array');
1618
+
1619
+ if (this._cmdOff > 0) this.flush();
1620
+
1621
+ this._checkBuf();
1622
+
1623
+ const snapPtr = this._e.mem_alloc(buf.length) >>> 0;
1624
+
1625
+ if (!snapPtr) throw new Error('AmoraDB: import: sem memória');
1626
+
1627
+ this._u8raw.set(buf, snapPtr);
1628
+
1629
+ const imported = this._e.db_import_snapshot(snapPtr, buf.length) >>> 0;
1630
+
1631
+ this._maybeInvalidate();
1632
+
1633
+ this._checkBuf();
1634
+
1635
+ return imported;
1636
+
1637
+ }
1638
+
1639
+ gc() {
1640
+
1641
+ if (this._cmdOff > 0) this.flush();
1642
+
1643
+ return this._e.db_gc();
1644
+
1645
+ }
1646
+
1647
+ autoCompact() {
1648
+
1649
+ if (this.fragmentation() > 25) return this.gc();
1650
+
1651
+ return 0;
1652
+
1653
+ }
1654
+
1655
+ fragmentation() {
1656
+
1657
+ return this._e.db_fragmentation_pct ? this._e.db_fragmentation_pct() >>> 0 : 0;
1658
+
1659
+ }
1660
+
1661
+ heartbeat() {
1662
+
1663
+ return this._e.db_heartbeat ? this._e.db_heartbeat() === 1 : true;
1664
+
1665
+ }
1666
+
1667
+ stats() {
1668
+
1669
+ if (this._cmdOff > 0) this.flush();
1670
+
1671
+ const e = this._e;
1672
+
1673
+ const count = e.db_count();
1674
+
1675
+ const cap = e.db_capacity();
1676
+
1677
+ const hits = Number(e.db_hits());
1678
+
1679
+ const misses = Number(e.db_misses());
1680
+
1681
+ const ops = Number(e.db_ops ? e.db_ops() : 0);
1682
+
1683
+ const deleted = e.db_deleted_count ? e.db_deleted_count() : 0;
1684
+
1685
+ const write_errors = e.db_write_errors ? Number(e.db_write_errors()) : 0;
1686
+
1687
+ const wal_errors = e.db_wal_errors ? Number(e.db_wal_errors()) : 0;
1688
+
1689
+ const compactions = e.db_compactions ? Number(e.db_compactions()) : 0;
1690
+
1691
+ const frag_pct = e.db_fragmentation_pct ? e.db_fragmentation_pct() : 0;
1692
+
1693
+ return {
1694
+
1695
+ count,
1696
+
1697
+ capacity: cap,
1698
+
1699
+ deleted,
1700
+
1701
+ shards: e.db_shard_count ? e.db_shard_count() : 64,
1702
+
1703
+ threads: this._nThreads,
1704
+
1705
+ inline_key_max: e.db_inline_key_max ? e.db_inline_key_max() : 22,
1706
+
1707
+ max_key_size: _MAX_KEY_SIZE,
1708
+
1709
+ max_value_size: _MAX_VALUE_SIZE,
1710
+
1711
+ load: ((count / Math.max(cap, 1)) * 100).toFixed(1) + '%',
1712
+
1713
+ fragmentation: frag_pct + '%',
1714
+
1715
+ hit_rate: (hits + misses) > 0
1716
+
1717
+ ? ((hits / (hits + misses)) * 100).toFixed(1) + '%'
1718
+
1719
+ : '0.0%',
1720
+
1721
+ total_ops: ops,
1722
+
1723
+ write_errors,
1724
+
1725
+ wal_errors,
1726
+
1727
+ compactions,
1728
+
1729
+ arena_kb: (e.db_arena_used() / 1024).toFixed(1),
1730
+
1731
+ wal_kb: (e.db_wal_size() / 1024).toFixed(1),
1732
+
1733
+ wasm_mb: (this._buf.byteLength / 1024 / 1024).toFixed(1),
1734
+
1735
+ mem_shared: this._buf instanceof SharedArrayBuffer,
1736
+
1737
+ in_batch: !!(e.db_wact && e.db_wact()),
1738
+
1739
+ pending: this._cmdOff,
1740
+
1741
+ cmd_buf_kb: (CMD_BUF_SIZE / 1024).toFixed(0),
1742
+
1743
+ cache_slots: SC_SIZE,
1744
+
1745
+ wal_sync: this._walSync,
1746
+
1747
+ };
1748
+
1749
+ }
1750
+
1751
+ persist() { this.flush(); this._e.db_persist(); }
1752
+
1753
+ restore() { return this._e.db_restore(); }
1754
+
1755
+ reset(cap) { this._e.db_init(cap || 65536); this._setup(); }
1756
+
1757
+ async close() {
1758
+
1759
+ this.flush();
1760
+
1761
+ if (this._walPath) this._e.db_persist();
1762
+
1763
+ if (this._pool) await this._pool.terminate();
1764
+
1765
+ }
1766
+
1767
+ bench(n) {
1768
+
1769
+ if (this._cmdOff > 0) this.flush();
1770
+
1771
+ n = n || 1_000_000;
1772
+
1773
+ const ok = this._e.db_bench(n);
1774
+
1775
+ this._maybeInvalidate();
1776
+
1777
+ this._checkBuf();
1778
+
1779
+ if (!ok) {
1780
+
1781
+ return {
1782
+
1783
+ ops: n, error: 'shard_init_failed',
1784
+
1785
+ write_ms: 'N/A', read_ms: 'N/A', delete_ms: 'N/A', scan_ms: 'N/A',
1786
+
1787
+ write_ops_s: 'N/A', read_ops_s: 'N/A', delete_ops_s: 'N/A',
1788
+
1789
+ };
1790
+
1791
+ }
1792
+
1793
+ const ptr = this._e.db_bench_ptr ? (this._e.db_bench_ptr() >>> 0) : 0;
1794
+
1795
+ if (!ptr) return { ops: n, error: 'no_bench_ptr' };
1796
+
1797
+ const dv = this._dv;
1798
+
1799
+ const wms = dv.getFloat64(ptr, true);
1800
+
1801
+ const rms = dv.getFloat64(ptr + 8, true);
1802
+
1803
+ const dms = dv.getFloat64(ptr + 16, true);
1804
+
1805
+ const sms = dv.getFloat64(ptr + 24, true);
1806
+
1807
+ if (wms < 0) {
1808
+
1809
+ return {
1810
+
1811
+ ops: n, error: 'shard_init_failed',
1812
+
1813
+ write_ms: 'N/A', read_ms: 'N/A', delete_ms: 'N/A', scan_ms: 'N/A',
1814
+
1815
+ write_ops_s: 'N/A', read_ops_s: 'N/A', delete_ops_s: 'N/A',
1816
+
1817
+ };
1818
+
1819
+ }
1820
+
1821
+ const fmt = x => {
1822
+
1823
+ if (!isFinite(x) || x <= 0) return '< 1K';
1824
+
1825
+ const m = x / 1e6;
1826
+
1827
+ return m >= 1 ? m.toFixed(2) + 'M' : (x / 1e3).toFixed(1) + 'K';
1828
+
1829
+ };
1830
+
1831
+ const safeOps = (ops, ms) => {
1832
+
1833
+ if (!isFinite(ms) || ms <= 0) return '> 1B';
1834
+
1835
+ return fmt(ops / (ms / 1000));
1836
+
1837
+ };
1838
+
1839
+ return {
1840
+
1841
+ ops: n,
1842
+
1843
+ write_ms: wms < 1 ? (wms * 1000).toFixed(0) + 'µs' : wms.toFixed(1) + 'ms',
1844
+
1845
+ read_ms: rms < 1 ? (rms * 1000).toFixed(0) + 'µs' : rms.toFixed(1) + 'ms',
1846
+
1847
+ delete_ms: dms < 1 ? (dms * 1000).toFixed(0) + 'µs' : dms.toFixed(1) + 'ms',
1848
+
1849
+ scan_ms: sms.toFixed(2) + 'ms',
1850
+
1851
+ write_ops_s: safeOps(n, wms),
1852
+
1853
+ read_ops_s: safeOps(n, rms),
1854
+
1855
+ delete_ops_s: safeOps(n / 2, dms),
1856
+
1857
+ };
1858
+
1859
+ }
1860
+
1861
+ }
1862
+
1863
+ module.exports = AmoraDB;
1864
+