@tinycloud/replica 0.2.4-beta.2 → 0.2.4-beta.3
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/sqlite.cjs +212 -85
- package/dist/sqlite.cjs.map +1 -1
- package/dist/sqlite.js +212 -85
- package/dist/sqlite.js.map +1 -1
- package/package.json +1 -1
package/dist/sqlite.cjs
CHANGED
|
@@ -355,9 +355,44 @@ var pinnedDirectories = new FinalizationRegistry((fd) => {
|
|
|
355
355
|
} catch {
|
|
356
356
|
}
|
|
357
357
|
});
|
|
358
|
+
var writableStores = /* @__PURE__ */ new Map();
|
|
359
|
+
function releaseWritable(shared) {
|
|
360
|
+
if (shared.references === 0 || --shared.references !== 0) return;
|
|
361
|
+
if (writableStores.get(shared.key) === shared) writableStores.delete(shared.key);
|
|
362
|
+
try {
|
|
363
|
+
shared.db.close();
|
|
364
|
+
} finally {
|
|
365
|
+
if (shared.directoryFd !== void 0) (0, import_node_fs.closeSync)(shared.directoryFd);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
var sharedStores = new FinalizationRegistry((shared) => {
|
|
369
|
+
try {
|
|
370
|
+
releaseWritable(shared);
|
|
371
|
+
} catch {
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
async function acquireWritableMutation(shared) {
|
|
375
|
+
const previous = shared.mutationTail;
|
|
376
|
+
let release;
|
|
377
|
+
shared.mutationTail = new Promise((resolve2) => {
|
|
378
|
+
release = resolve2;
|
|
379
|
+
});
|
|
380
|
+
await previous;
|
|
381
|
+
return release;
|
|
382
|
+
}
|
|
358
383
|
var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
359
384
|
dir;
|
|
360
|
-
#
|
|
385
|
+
#database;
|
|
386
|
+
get #db() {
|
|
387
|
+
if (this.#closed) throw new ReplicaError(ReplicaErrorCode.CLOSED, "The replica store is closed.");
|
|
388
|
+
return this.#database;
|
|
389
|
+
}
|
|
390
|
+
#closed = false;
|
|
391
|
+
#closing = false;
|
|
392
|
+
#closePromise;
|
|
393
|
+
#activeMutations = 0;
|
|
394
|
+
#drained;
|
|
395
|
+
#shared;
|
|
361
396
|
#pinnedDir;
|
|
362
397
|
#directoryFd;
|
|
363
398
|
#holder = `${process.pid}-${(0, import_node_crypto.randomBytes)(6).toString("hex")}`;
|
|
@@ -368,12 +403,18 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
368
403
|
#ino;
|
|
369
404
|
#dev;
|
|
370
405
|
#namedAncestors;
|
|
371
|
-
constructor(dir, db, identity, options, directoryFd, namedAncestors = []) {
|
|
406
|
+
constructor(dir, db, identity, options, directoryFd, namedAncestors = [], shared) {
|
|
372
407
|
this.dir = dir;
|
|
373
|
-
this.#pinnedDir = directoryFd !== void 0 && process.platform === "linux" ? `/proc/self/fd/${directoryFd}` : dir;
|
|
408
|
+
this.#pinnedDir = shared?.pinnedDir ?? (directoryFd !== void 0 && process.platform === "linux" ? `/proc/self/fd/${directoryFd}` : dir);
|
|
374
409
|
this.#directoryFd = directoryFd;
|
|
375
|
-
|
|
376
|
-
|
|
410
|
+
this.#shared = shared;
|
|
411
|
+
if (shared) {
|
|
412
|
+
shared.references++;
|
|
413
|
+
sharedStores.register(this, shared, this);
|
|
414
|
+
} else if (directoryFd !== void 0) {
|
|
415
|
+
pinnedDirectories.register(this, directoryFd, this);
|
|
416
|
+
}
|
|
417
|
+
this.#database = db;
|
|
377
418
|
this.#ino = identity.ino;
|
|
378
419
|
this.#dev = identity.dev;
|
|
379
420
|
this.#now = options.now ?? Date.now;
|
|
@@ -443,7 +484,6 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
443
484
|
);
|
|
444
485
|
if (!exists) throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `No regular replica database at ${dir}.`);
|
|
445
486
|
}
|
|
446
|
-
const opener = options.sqlite ?? await loadSqlite();
|
|
447
487
|
const releaseOpen = await acquireSqliteOpen();
|
|
448
488
|
let store;
|
|
449
489
|
let directoryFd;
|
|
@@ -485,63 +525,99 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
485
525
|
if (!identity.isFile() || !named.isFile() || named.dev !== identity.dev || named.ino !== identity.ino) {
|
|
486
526
|
throw new Error("The replica database changed before SQLite opened it.");
|
|
487
527
|
}
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
528
|
+
const key = `${opened.dev}:${opened.ino}`;
|
|
529
|
+
const active = writableStores.get(key);
|
|
530
|
+
if (active && (active.dev !== identity.dev || active.ino !== identity.ino)) {
|
|
531
|
+
throw new Error("The replica database changed while another controller holds it open.");
|
|
532
|
+
}
|
|
533
|
+
if (active && !options.sqlite) {
|
|
534
|
+
const namedDirectory = (0, import_node_fs.lstatSync)(dir, { bigint: true });
|
|
535
|
+
if (!namedDirectory.isDirectory() || namedDirectory.dev !== opened.dev || namedDirectory.ino !== opened.ino) {
|
|
536
|
+
throw new Error("The replica directory changed before its checked SQLite handle could be shared.");
|
|
537
|
+
}
|
|
538
|
+
const pinned = active.directoryFd === void 0 ? (0, import_node_fs.lstatSync)(active.pinnedDir, { bigint: true }) : (0, import_node_fs.fstatSync)(active.directoryFd, { bigint: true });
|
|
539
|
+
const activeLeaf = (0, import_node_fs.lstatSync)((0, import_node_path.join)(active.pinnedDir, "replica.db"));
|
|
540
|
+
if (!pinned.isDirectory() || pinned.dev !== opened.dev || pinned.ino !== opened.ino || !activeLeaf.isFile() || activeLeaf.dev !== identity.dev || activeLeaf.ino !== identity.ino || active.directoryFd === void 0 && active.namedPath !== dir) {
|
|
541
|
+
throw new Error("The live replica changed before its checked SQLite handle could be shared.");
|
|
493
542
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
543
|
+
if (directoryFd !== void 0) {
|
|
544
|
+
(0, import_node_fs.closeSync)(directoryFd);
|
|
545
|
+
directoryFd = void 0;
|
|
546
|
+
}
|
|
547
|
+
store = new _SqliteReplicaStore(dir, active.db, identity, options, active.directoryFd, namedAncestors, active);
|
|
499
548
|
}
|
|
500
|
-
if (
|
|
501
|
-
|
|
502
|
-
const
|
|
549
|
+
if (!store) {
|
|
550
|
+
const opener = options.sqlite ?? await loadSqlite();
|
|
551
|
+
const previousFds = process.platform === "linux" && !options.sqlite ? new Map((0, import_node_fs.readdirSync)("/proc/self/fd").map((fd) => {
|
|
503
552
|
try {
|
|
504
|
-
|
|
505
|
-
return target.endsWith("/replica.db") && previousFds.get(fd) !== target;
|
|
553
|
+
return [fd, (0, import_node_fs.readlinkSync)(`/proc/self/fd/${fd}`)];
|
|
506
554
|
} catch {
|
|
507
|
-
return
|
|
555
|
+
return [fd, ""];
|
|
508
556
|
}
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
557
|
+
})) : null;
|
|
558
|
+
db = opener(dbPath);
|
|
559
|
+
const afterOpen = (0, import_node_fs.lstatSync)(dbPath);
|
|
560
|
+
if (!afterOpen.isFile() || afterOpen.dev !== identity.dev || afterOpen.ino !== identity.ino) {
|
|
561
|
+
throw new Error("The replica database changed while SQLite opened it.");
|
|
562
|
+
}
|
|
563
|
+
if (previousFds) db.get("SELECT count(*) FROM sqlite_master");
|
|
564
|
+
if (previousFds) {
|
|
565
|
+
const databases = (0, import_node_fs.readdirSync)("/proc/self/fd").filter((fd) => {
|
|
566
|
+
try {
|
|
567
|
+
const target = (0, import_node_fs.readlinkSync)(`/proc/self/fd/${fd}`);
|
|
568
|
+
return target.endsWith("/replica.db") && previousFds.get(fd) !== target;
|
|
569
|
+
} catch {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
if (databases.length === 0 || databases.some((fd) => {
|
|
574
|
+
try {
|
|
575
|
+
const actual = (0, import_node_fs.fstatSync)(Number(fd));
|
|
576
|
+
return actual.dev !== identity.dev || actual.ino !== identity.ino;
|
|
577
|
+
} catch {
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
})) {
|
|
581
|
+
throw new Error("SQLite opened a different replica database.");
|
|
516
582
|
}
|
|
517
|
-
})) {
|
|
518
|
-
throw new Error("SQLite opened a different replica database.");
|
|
519
583
|
}
|
|
584
|
+
const after = (0, import_node_fs.lstatSync)(dbPath);
|
|
585
|
+
if (!after.isFile() || after.dev !== identity.dev || after.ino !== identity.ino) {
|
|
586
|
+
throw new Error("The replica database changed while SQLite opened it.");
|
|
587
|
+
}
|
|
588
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
589
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
590
|
+
db.exec("PRAGMA synchronous = FULL");
|
|
591
|
+
db.exec("PRAGMA secure_delete = ON");
|
|
592
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
593
|
+
const version = db.get("PRAGMA user_version")?.user_version ?? 0;
|
|
594
|
+
if (version > SCHEMA_VERSION) {
|
|
595
|
+
throw new ReplicaError(
|
|
596
|
+
ReplicaErrorCode.STORAGE_ERROR,
|
|
597
|
+
`The replica at ${dir} was written by a newer tc (schema ${version}); upgrade tc to read it.`
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
if (version < SCHEMA_VERSION) {
|
|
601
|
+
db.exec("BEGIN IMMEDIATE");
|
|
602
|
+
db.exec(SCHEMA);
|
|
603
|
+
db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
604
|
+
db.exec("COMMIT");
|
|
605
|
+
}
|
|
606
|
+
const shared = options.sqlite ? void 0 : {
|
|
607
|
+
key,
|
|
608
|
+
db,
|
|
609
|
+
directoryFd,
|
|
610
|
+
pinnedDir,
|
|
611
|
+
namedPath: dir,
|
|
612
|
+
dev: identity.dev,
|
|
613
|
+
ino: identity.ino,
|
|
614
|
+
references: 0,
|
|
615
|
+
mutationTail: Promise.resolve()
|
|
616
|
+
};
|
|
617
|
+
store = new _SqliteReplicaStore(dir, db, identity, options, directoryFd, namedAncestors, shared);
|
|
618
|
+
if (shared) writableStores.set(key, shared);
|
|
619
|
+
db = void 0;
|
|
520
620
|
}
|
|
521
|
-
const after = (0, import_node_fs.lstatSync)(dbPath);
|
|
522
|
-
if (!after.isFile() || after.dev !== identity.dev || after.ino !== identity.ino) {
|
|
523
|
-
throw new Error("The replica database changed while SQLite opened it.");
|
|
524
|
-
}
|
|
525
|
-
db.exec("PRAGMA busy_timeout = 5000");
|
|
526
|
-
db.exec("PRAGMA journal_mode = WAL");
|
|
527
|
-
db.exec("PRAGMA synchronous = FULL");
|
|
528
|
-
db.exec("PRAGMA secure_delete = ON");
|
|
529
|
-
db.exec("PRAGMA foreign_keys = ON");
|
|
530
|
-
const version = db.get("PRAGMA user_version")?.user_version ?? 0;
|
|
531
|
-
if (version > SCHEMA_VERSION) {
|
|
532
|
-
throw new ReplicaError(
|
|
533
|
-
ReplicaErrorCode.STORAGE_ERROR,
|
|
534
|
-
`The replica at ${dir} was written by a newer tc (schema ${version}); upgrade tc to read it.`
|
|
535
|
-
);
|
|
536
|
-
}
|
|
537
|
-
if (version < SCHEMA_VERSION) {
|
|
538
|
-
db.exec("BEGIN IMMEDIATE");
|
|
539
|
-
db.exec(SCHEMA);
|
|
540
|
-
db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
541
|
-
db.exec("COMMIT");
|
|
542
|
-
}
|
|
543
|
-
store = new _SqliteReplicaStore(dir, db, identity, options, directoryFd, namedAncestors);
|
|
544
|
-
db = void 0;
|
|
545
621
|
} finally {
|
|
546
622
|
try {
|
|
547
623
|
db?.close();
|
|
@@ -580,30 +656,53 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
580
656
|
);
|
|
581
657
|
}
|
|
582
658
|
}
|
|
659
|
+
/** New calls stop at close; accepted mutation sections may still finish their transactions. */
|
|
660
|
+
#assertAccepting() {
|
|
661
|
+
if (this.#closing || this.#closed) {
|
|
662
|
+
throw new ReplicaError(ReplicaErrorCode.CLOSED, "The replica store is closed.");
|
|
663
|
+
}
|
|
664
|
+
}
|
|
583
665
|
/** A short mutation section: guarded (profile lock) and checked against the database this store opened. */
|
|
584
666
|
#mutate(section) {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
667
|
+
this.#assertAccepting();
|
|
668
|
+
this.#activeMutations++;
|
|
669
|
+
return (async () => {
|
|
670
|
+
try {
|
|
671
|
+
return await this.#guard(async () => {
|
|
672
|
+
await this.#assertPresent();
|
|
673
|
+
return section();
|
|
674
|
+
});
|
|
675
|
+
} finally {
|
|
676
|
+
if (--this.#activeMutations === 0) {
|
|
677
|
+
const drained = this.#drained;
|
|
678
|
+
this.#drained = void 0;
|
|
679
|
+
drained?.();
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
})();
|
|
589
683
|
}
|
|
590
684
|
/** Run `body` in a write transaction (BEGIN IMMEDIATE). Callers outside a mutation section use `#guardedWrite`. */
|
|
591
|
-
#write(action, body) {
|
|
685
|
+
async #write(action, body) {
|
|
686
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
592
687
|
try {
|
|
593
|
-
this.#db.exec("BEGIN IMMEDIATE");
|
|
594
|
-
} catch (error) {
|
|
595
|
-
throw storageError(error, action);
|
|
596
|
-
}
|
|
597
|
-
try {
|
|
598
|
-
const result = body();
|
|
599
|
-
this.#db.exec("COMMIT");
|
|
600
|
-
return result;
|
|
601
|
-
} catch (error) {
|
|
602
688
|
try {
|
|
603
|
-
this.#db.exec("
|
|
604
|
-
} catch {
|
|
689
|
+
this.#db.exec("BEGIN IMMEDIATE");
|
|
690
|
+
} catch (error) {
|
|
691
|
+
throw storageError(error, action);
|
|
605
692
|
}
|
|
606
|
-
|
|
693
|
+
try {
|
|
694
|
+
const result = body();
|
|
695
|
+
this.#db.exec("COMMIT");
|
|
696
|
+
return result;
|
|
697
|
+
} catch (error) {
|
|
698
|
+
try {
|
|
699
|
+
this.#db.exec("ROLLBACK");
|
|
700
|
+
} catch {
|
|
701
|
+
}
|
|
702
|
+
throw storageError(error, action);
|
|
703
|
+
}
|
|
704
|
+
} finally {
|
|
705
|
+
release?.();
|
|
607
706
|
}
|
|
608
707
|
}
|
|
609
708
|
/** One write transaction as its own mutation section. */
|
|
@@ -630,6 +729,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
630
729
|
}
|
|
631
730
|
}
|
|
632
731
|
async open() {
|
|
732
|
+
this.#assertAccepting();
|
|
633
733
|
let row;
|
|
634
734
|
try {
|
|
635
735
|
row = this.#row();
|
|
@@ -791,6 +891,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
791
891
|
});
|
|
792
892
|
}
|
|
793
893
|
async hasContent(hashes) {
|
|
894
|
+
this.#assertAccepting();
|
|
794
895
|
const held = /* @__PURE__ */ new Set();
|
|
795
896
|
for (let start = 0; start < hashes.length; start += 500) {
|
|
796
897
|
const chunk = hashes.slice(start, start + 500);
|
|
@@ -873,7 +974,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
873
974
|
}
|
|
874
975
|
await this.#faults.afterBlobs?.();
|
|
875
976
|
try {
|
|
876
|
-
this.#write("Committing a sync page", () => {
|
|
977
|
+
await this.#write("Committing a sync page", () => {
|
|
877
978
|
this.#checkLease(t);
|
|
878
979
|
const now = this.#now();
|
|
879
980
|
if (p.window.notBefore !== null && now < Date.parse(p.window.notBefore)) {
|
|
@@ -981,13 +1082,16 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
981
1082
|
}
|
|
982
1083
|
async collectGarbage(t) {
|
|
983
1084
|
return this.#mutate(async () => {
|
|
1085
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
984
1086
|
try {
|
|
985
1087
|
this.#db.exec("BEGIN IMMEDIATE");
|
|
986
1088
|
} catch (error) {
|
|
1089
|
+
release?.();
|
|
987
1090
|
throw storageError(error, "Collecting unused content");
|
|
988
1091
|
}
|
|
989
1092
|
try {
|
|
990
1093
|
this.#checkLease(t);
|
|
1094
|
+
await this.#faults.afterGarbageCollectionBegin?.();
|
|
991
1095
|
const keep = new Set(
|
|
992
1096
|
this.#db.all("SELECT DISTINCT hash FROM entry WHERE content = 1").map((row) => row.hash)
|
|
993
1097
|
);
|
|
@@ -1000,12 +1104,14 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1000
1104
|
} catch {
|
|
1001
1105
|
}
|
|
1002
1106
|
throw storageError(error, "Collecting unused content");
|
|
1107
|
+
} finally {
|
|
1108
|
+
release?.();
|
|
1003
1109
|
}
|
|
1004
1110
|
});
|
|
1005
1111
|
}
|
|
1006
1112
|
async reset(t, reason, options = {}) {
|
|
1007
1113
|
await this.#mutate(async () => {
|
|
1008
|
-
this.#write("Resetting the replica", () => {
|
|
1114
|
+
await this.#write("Resetting the replica", () => {
|
|
1009
1115
|
this.#checkLease(t);
|
|
1010
1116
|
this.#db.run("DELETE FROM entry");
|
|
1011
1117
|
this.#db.run(
|
|
@@ -1032,9 +1138,11 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1032
1138
|
*/
|
|
1033
1139
|
async destroy(t) {
|
|
1034
1140
|
await this.#mutate(async () => {
|
|
1141
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
1035
1142
|
try {
|
|
1036
1143
|
this.#db.exec("BEGIN IMMEDIATE");
|
|
1037
1144
|
} catch (error) {
|
|
1145
|
+
release?.();
|
|
1038
1146
|
throw storageError(error, "Removing the replica");
|
|
1039
1147
|
}
|
|
1040
1148
|
try {
|
|
@@ -1133,6 +1241,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1133
1241
|
this.#db.exec("ROLLBACK");
|
|
1134
1242
|
} catch {
|
|
1135
1243
|
}
|
|
1244
|
+
release?.();
|
|
1136
1245
|
}
|
|
1137
1246
|
});
|
|
1138
1247
|
}
|
|
@@ -1176,7 +1285,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1176
1285
|
* when both are done.
|
|
1177
1286
|
*/
|
|
1178
1287
|
async #purgeContent() {
|
|
1179
|
-
this.#write("Starting the revocation purge", () => {
|
|
1288
|
+
await this.#write("Starting the revocation purge", () => {
|
|
1180
1289
|
this.#db.run("UPDATE replica SET purge_pending = 1 WHERE id = 1 AND revoked_detail IS NOT NULL");
|
|
1181
1290
|
});
|
|
1182
1291
|
try {
|
|
@@ -1187,7 +1296,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1187
1296
|
if (!this.#checkpoint()) {
|
|
1188
1297
|
throw new ReplicaError(ReplicaErrorCode.BUSY, "A reader holds the replica's write-ahead log; the purge finishes on the next open.");
|
|
1189
1298
|
}
|
|
1190
|
-
this.#write("Finishing the revocation purge", () => {
|
|
1299
|
+
await this.#write("Finishing the revocation purge", () => {
|
|
1191
1300
|
this.#db.run("UPDATE replica SET purge_pending = 0 WHERE id = 1 AND revoked_detail IS NOT NULL");
|
|
1192
1301
|
});
|
|
1193
1302
|
}
|
|
@@ -1197,6 +1306,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1197
1306
|
});
|
|
1198
1307
|
}
|
|
1199
1308
|
async get(key) {
|
|
1309
|
+
this.#assertAccepting();
|
|
1200
1310
|
try {
|
|
1201
1311
|
const row = this.#db.get("SELECT key, deleted, etag, hash, metadata, content FROM entry WHERE key = ?", key);
|
|
1202
1312
|
return row === void 0 ? void 0 : entryOf(row);
|
|
@@ -1205,6 +1315,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1205
1315
|
}
|
|
1206
1316
|
}
|
|
1207
1317
|
async list(o) {
|
|
1318
|
+
this.#assertAccepting();
|
|
1208
1319
|
const where = ["deleted = 0"];
|
|
1209
1320
|
const params = [];
|
|
1210
1321
|
if (o.prefix !== void 0 && o.prefix !== "") {
|
|
@@ -1290,15 +1401,31 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1290
1401
|
lastReset: state.lastReset
|
|
1291
1402
|
};
|
|
1292
1403
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
this.#
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1404
|
+
close() {
|
|
1405
|
+
if (this.#closePromise) return this.#closePromise;
|
|
1406
|
+
this.#closing = true;
|
|
1407
|
+
this.#closePromise = (async () => {
|
|
1408
|
+
if (this.#activeMutations !== 0) {
|
|
1409
|
+
await new Promise((resolve2) => {
|
|
1410
|
+
this.#drained = resolve2;
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
this.#closed = true;
|
|
1414
|
+
const fd = this.#directoryFd;
|
|
1415
|
+
this.#directoryFd = void 0;
|
|
1416
|
+
if (this.#shared) {
|
|
1417
|
+
sharedStores.unregister(this);
|
|
1418
|
+
releaseWritable(this.#shared);
|
|
1419
|
+
} else {
|
|
1420
|
+
if (fd !== void 0) pinnedDirectories.unregister(this);
|
|
1421
|
+
try {
|
|
1422
|
+
this.#database.close();
|
|
1423
|
+
} finally {
|
|
1424
|
+
if (fd !== void 0) (0, import_node_fs.closeSync)(fd);
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
})();
|
|
1428
|
+
return this.#closePromise;
|
|
1302
1429
|
}
|
|
1303
1430
|
};
|
|
1304
1431
|
// Annotate the CommonJS export names for ESM import in node:
|