@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.js
CHANGED
|
@@ -326,9 +326,44 @@ var pinnedDirectories = new FinalizationRegistry((fd) => {
|
|
|
326
326
|
} catch {
|
|
327
327
|
}
|
|
328
328
|
});
|
|
329
|
+
var writableStores = /* @__PURE__ */ new Map();
|
|
330
|
+
function releaseWritable(shared) {
|
|
331
|
+
if (shared.references === 0 || --shared.references !== 0) return;
|
|
332
|
+
if (writableStores.get(shared.key) === shared) writableStores.delete(shared.key);
|
|
333
|
+
try {
|
|
334
|
+
shared.db.close();
|
|
335
|
+
} finally {
|
|
336
|
+
if (shared.directoryFd !== void 0) closeSync(shared.directoryFd);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
var sharedStores = new FinalizationRegistry((shared) => {
|
|
340
|
+
try {
|
|
341
|
+
releaseWritable(shared);
|
|
342
|
+
} catch {
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
async function acquireWritableMutation(shared) {
|
|
346
|
+
const previous = shared.mutationTail;
|
|
347
|
+
let release;
|
|
348
|
+
shared.mutationTail = new Promise((resolve2) => {
|
|
349
|
+
release = resolve2;
|
|
350
|
+
});
|
|
351
|
+
await previous;
|
|
352
|
+
return release;
|
|
353
|
+
}
|
|
329
354
|
var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
330
355
|
dir;
|
|
331
|
-
#
|
|
356
|
+
#database;
|
|
357
|
+
get #db() {
|
|
358
|
+
if (this.#closed) throw new ReplicaError(ReplicaErrorCode.CLOSED, "The replica store is closed.");
|
|
359
|
+
return this.#database;
|
|
360
|
+
}
|
|
361
|
+
#closed = false;
|
|
362
|
+
#closing = false;
|
|
363
|
+
#closePromise;
|
|
364
|
+
#activeMutations = 0;
|
|
365
|
+
#drained;
|
|
366
|
+
#shared;
|
|
332
367
|
#pinnedDir;
|
|
333
368
|
#directoryFd;
|
|
334
369
|
#holder = `${process.pid}-${randomBytes(6).toString("hex")}`;
|
|
@@ -339,12 +374,18 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
339
374
|
#ino;
|
|
340
375
|
#dev;
|
|
341
376
|
#namedAncestors;
|
|
342
|
-
constructor(dir, db, identity, options, directoryFd, namedAncestors = []) {
|
|
377
|
+
constructor(dir, db, identity, options, directoryFd, namedAncestors = [], shared) {
|
|
343
378
|
this.dir = dir;
|
|
344
|
-
this.#pinnedDir = directoryFd !== void 0 && process.platform === "linux" ? `/proc/self/fd/${directoryFd}` : dir;
|
|
379
|
+
this.#pinnedDir = shared?.pinnedDir ?? (directoryFd !== void 0 && process.platform === "linux" ? `/proc/self/fd/${directoryFd}` : dir);
|
|
345
380
|
this.#directoryFd = directoryFd;
|
|
346
|
-
|
|
347
|
-
|
|
381
|
+
this.#shared = shared;
|
|
382
|
+
if (shared) {
|
|
383
|
+
shared.references++;
|
|
384
|
+
sharedStores.register(this, shared, this);
|
|
385
|
+
} else if (directoryFd !== void 0) {
|
|
386
|
+
pinnedDirectories.register(this, directoryFd, this);
|
|
387
|
+
}
|
|
388
|
+
this.#database = db;
|
|
348
389
|
this.#ino = identity.ino;
|
|
349
390
|
this.#dev = identity.dev;
|
|
350
391
|
this.#now = options.now ?? Date.now;
|
|
@@ -414,7 +455,6 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
414
455
|
);
|
|
415
456
|
if (!exists) throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `No regular replica database at ${dir}.`);
|
|
416
457
|
}
|
|
417
|
-
const opener = options.sqlite ?? await loadSqlite();
|
|
418
458
|
const releaseOpen = await acquireSqliteOpen();
|
|
419
459
|
let store;
|
|
420
460
|
let directoryFd;
|
|
@@ -456,63 +496,99 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
456
496
|
if (!identity.isFile() || !named.isFile() || named.dev !== identity.dev || named.ino !== identity.ino) {
|
|
457
497
|
throw new Error("The replica database changed before SQLite opened it.");
|
|
458
498
|
}
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
499
|
+
const key = `${opened.dev}:${opened.ino}`;
|
|
500
|
+
const active = writableStores.get(key);
|
|
501
|
+
if (active && (active.dev !== identity.dev || active.ino !== identity.ino)) {
|
|
502
|
+
throw new Error("The replica database changed while another controller holds it open.");
|
|
503
|
+
}
|
|
504
|
+
if (active && !options.sqlite) {
|
|
505
|
+
const namedDirectory = lstatSync(dir, { bigint: true });
|
|
506
|
+
if (!namedDirectory.isDirectory() || namedDirectory.dev !== opened.dev || namedDirectory.ino !== opened.ino) {
|
|
507
|
+
throw new Error("The replica directory changed before its checked SQLite handle could be shared.");
|
|
508
|
+
}
|
|
509
|
+
const pinned = active.directoryFd === void 0 ? lstatSync(active.pinnedDir, { bigint: true }) : fstatSync(active.directoryFd, { bigint: true });
|
|
510
|
+
const activeLeaf = lstatSync(join(active.pinnedDir, "replica.db"));
|
|
511
|
+
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) {
|
|
512
|
+
throw new Error("The live replica changed before its checked SQLite handle could be shared.");
|
|
464
513
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
514
|
+
if (directoryFd !== void 0) {
|
|
515
|
+
closeSync(directoryFd);
|
|
516
|
+
directoryFd = void 0;
|
|
517
|
+
}
|
|
518
|
+
store = new _SqliteReplicaStore(dir, active.db, identity, options, active.directoryFd, namedAncestors, active);
|
|
470
519
|
}
|
|
471
|
-
if (
|
|
472
|
-
|
|
473
|
-
const
|
|
520
|
+
if (!store) {
|
|
521
|
+
const opener = options.sqlite ?? await loadSqlite();
|
|
522
|
+
const previousFds = process.platform === "linux" && !options.sqlite ? new Map(readdirSync("/proc/self/fd").map((fd) => {
|
|
474
523
|
try {
|
|
475
|
-
|
|
476
|
-
return target.endsWith("/replica.db") && previousFds.get(fd) !== target;
|
|
524
|
+
return [fd, readlinkSync(`/proc/self/fd/${fd}`)];
|
|
477
525
|
} catch {
|
|
478
|
-
return
|
|
526
|
+
return [fd, ""];
|
|
479
527
|
}
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
528
|
+
})) : null;
|
|
529
|
+
db = opener(dbPath);
|
|
530
|
+
const afterOpen = lstatSync(dbPath);
|
|
531
|
+
if (!afterOpen.isFile() || afterOpen.dev !== identity.dev || afterOpen.ino !== identity.ino) {
|
|
532
|
+
throw new Error("The replica database changed while SQLite opened it.");
|
|
533
|
+
}
|
|
534
|
+
if (previousFds) db.get("SELECT count(*) FROM sqlite_master");
|
|
535
|
+
if (previousFds) {
|
|
536
|
+
const databases = readdirSync("/proc/self/fd").filter((fd) => {
|
|
537
|
+
try {
|
|
538
|
+
const target = readlinkSync(`/proc/self/fd/${fd}`);
|
|
539
|
+
return target.endsWith("/replica.db") && previousFds.get(fd) !== target;
|
|
540
|
+
} catch {
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
if (databases.length === 0 || databases.some((fd) => {
|
|
545
|
+
try {
|
|
546
|
+
const actual = fstatSync(Number(fd));
|
|
547
|
+
return actual.dev !== identity.dev || actual.ino !== identity.ino;
|
|
548
|
+
} catch {
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
})) {
|
|
552
|
+
throw new Error("SQLite opened a different replica database.");
|
|
487
553
|
}
|
|
488
|
-
})) {
|
|
489
|
-
throw new Error("SQLite opened a different replica database.");
|
|
490
554
|
}
|
|
555
|
+
const after = lstatSync(dbPath);
|
|
556
|
+
if (!after.isFile() || after.dev !== identity.dev || after.ino !== identity.ino) {
|
|
557
|
+
throw new Error("The replica database changed while SQLite opened it.");
|
|
558
|
+
}
|
|
559
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
560
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
561
|
+
db.exec("PRAGMA synchronous = FULL");
|
|
562
|
+
db.exec("PRAGMA secure_delete = ON");
|
|
563
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
564
|
+
const version = db.get("PRAGMA user_version")?.user_version ?? 0;
|
|
565
|
+
if (version > SCHEMA_VERSION) {
|
|
566
|
+
throw new ReplicaError(
|
|
567
|
+
ReplicaErrorCode.STORAGE_ERROR,
|
|
568
|
+
`The replica at ${dir} was written by a newer tc (schema ${version}); upgrade tc to read it.`
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
if (version < SCHEMA_VERSION) {
|
|
572
|
+
db.exec("BEGIN IMMEDIATE");
|
|
573
|
+
db.exec(SCHEMA);
|
|
574
|
+
db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
575
|
+
db.exec("COMMIT");
|
|
576
|
+
}
|
|
577
|
+
const shared = options.sqlite ? void 0 : {
|
|
578
|
+
key,
|
|
579
|
+
db,
|
|
580
|
+
directoryFd,
|
|
581
|
+
pinnedDir,
|
|
582
|
+
namedPath: dir,
|
|
583
|
+
dev: identity.dev,
|
|
584
|
+
ino: identity.ino,
|
|
585
|
+
references: 0,
|
|
586
|
+
mutationTail: Promise.resolve()
|
|
587
|
+
};
|
|
588
|
+
store = new _SqliteReplicaStore(dir, db, identity, options, directoryFd, namedAncestors, shared);
|
|
589
|
+
if (shared) writableStores.set(key, shared);
|
|
590
|
+
db = void 0;
|
|
491
591
|
}
|
|
492
|
-
const after = lstatSync(dbPath);
|
|
493
|
-
if (!after.isFile() || after.dev !== identity.dev || after.ino !== identity.ino) {
|
|
494
|
-
throw new Error("The replica database changed while SQLite opened it.");
|
|
495
|
-
}
|
|
496
|
-
db.exec("PRAGMA busy_timeout = 5000");
|
|
497
|
-
db.exec("PRAGMA journal_mode = WAL");
|
|
498
|
-
db.exec("PRAGMA synchronous = FULL");
|
|
499
|
-
db.exec("PRAGMA secure_delete = ON");
|
|
500
|
-
db.exec("PRAGMA foreign_keys = ON");
|
|
501
|
-
const version = db.get("PRAGMA user_version")?.user_version ?? 0;
|
|
502
|
-
if (version > SCHEMA_VERSION) {
|
|
503
|
-
throw new ReplicaError(
|
|
504
|
-
ReplicaErrorCode.STORAGE_ERROR,
|
|
505
|
-
`The replica at ${dir} was written by a newer tc (schema ${version}); upgrade tc to read it.`
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
if (version < SCHEMA_VERSION) {
|
|
509
|
-
db.exec("BEGIN IMMEDIATE");
|
|
510
|
-
db.exec(SCHEMA);
|
|
511
|
-
db.exec(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
512
|
-
db.exec("COMMIT");
|
|
513
|
-
}
|
|
514
|
-
store = new _SqliteReplicaStore(dir, db, identity, options, directoryFd, namedAncestors);
|
|
515
|
-
db = void 0;
|
|
516
592
|
} finally {
|
|
517
593
|
try {
|
|
518
594
|
db?.close();
|
|
@@ -551,30 +627,53 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
551
627
|
);
|
|
552
628
|
}
|
|
553
629
|
}
|
|
630
|
+
/** New calls stop at close; accepted mutation sections may still finish their transactions. */
|
|
631
|
+
#assertAccepting() {
|
|
632
|
+
if (this.#closing || this.#closed) {
|
|
633
|
+
throw new ReplicaError(ReplicaErrorCode.CLOSED, "The replica store is closed.");
|
|
634
|
+
}
|
|
635
|
+
}
|
|
554
636
|
/** A short mutation section: guarded (profile lock) and checked against the database this store opened. */
|
|
555
637
|
#mutate(section) {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
638
|
+
this.#assertAccepting();
|
|
639
|
+
this.#activeMutations++;
|
|
640
|
+
return (async () => {
|
|
641
|
+
try {
|
|
642
|
+
return await this.#guard(async () => {
|
|
643
|
+
await this.#assertPresent();
|
|
644
|
+
return section();
|
|
645
|
+
});
|
|
646
|
+
} finally {
|
|
647
|
+
if (--this.#activeMutations === 0) {
|
|
648
|
+
const drained = this.#drained;
|
|
649
|
+
this.#drained = void 0;
|
|
650
|
+
drained?.();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
})();
|
|
560
654
|
}
|
|
561
655
|
/** Run `body` in a write transaction (BEGIN IMMEDIATE). Callers outside a mutation section use `#guardedWrite`. */
|
|
562
|
-
#write(action, body) {
|
|
656
|
+
async #write(action, body) {
|
|
657
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
563
658
|
try {
|
|
564
|
-
this.#db.exec("BEGIN IMMEDIATE");
|
|
565
|
-
} catch (error) {
|
|
566
|
-
throw storageError(error, action);
|
|
567
|
-
}
|
|
568
|
-
try {
|
|
569
|
-
const result = body();
|
|
570
|
-
this.#db.exec("COMMIT");
|
|
571
|
-
return result;
|
|
572
|
-
} catch (error) {
|
|
573
659
|
try {
|
|
574
|
-
this.#db.exec("
|
|
575
|
-
} catch {
|
|
660
|
+
this.#db.exec("BEGIN IMMEDIATE");
|
|
661
|
+
} catch (error) {
|
|
662
|
+
throw storageError(error, action);
|
|
576
663
|
}
|
|
577
|
-
|
|
664
|
+
try {
|
|
665
|
+
const result = body();
|
|
666
|
+
this.#db.exec("COMMIT");
|
|
667
|
+
return result;
|
|
668
|
+
} catch (error) {
|
|
669
|
+
try {
|
|
670
|
+
this.#db.exec("ROLLBACK");
|
|
671
|
+
} catch {
|
|
672
|
+
}
|
|
673
|
+
throw storageError(error, action);
|
|
674
|
+
}
|
|
675
|
+
} finally {
|
|
676
|
+
release?.();
|
|
578
677
|
}
|
|
579
678
|
}
|
|
580
679
|
/** One write transaction as its own mutation section. */
|
|
@@ -601,6 +700,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
601
700
|
}
|
|
602
701
|
}
|
|
603
702
|
async open() {
|
|
703
|
+
this.#assertAccepting();
|
|
604
704
|
let row;
|
|
605
705
|
try {
|
|
606
706
|
row = this.#row();
|
|
@@ -762,6 +862,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
762
862
|
});
|
|
763
863
|
}
|
|
764
864
|
async hasContent(hashes) {
|
|
865
|
+
this.#assertAccepting();
|
|
765
866
|
const held = /* @__PURE__ */ new Set();
|
|
766
867
|
for (let start = 0; start < hashes.length; start += 500) {
|
|
767
868
|
const chunk = hashes.slice(start, start + 500);
|
|
@@ -844,7 +945,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
844
945
|
}
|
|
845
946
|
await this.#faults.afterBlobs?.();
|
|
846
947
|
try {
|
|
847
|
-
this.#write("Committing a sync page", () => {
|
|
948
|
+
await this.#write("Committing a sync page", () => {
|
|
848
949
|
this.#checkLease(t);
|
|
849
950
|
const now = this.#now();
|
|
850
951
|
if (p.window.notBefore !== null && now < Date.parse(p.window.notBefore)) {
|
|
@@ -952,13 +1053,16 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
952
1053
|
}
|
|
953
1054
|
async collectGarbage(t) {
|
|
954
1055
|
return this.#mutate(async () => {
|
|
1056
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
955
1057
|
try {
|
|
956
1058
|
this.#db.exec("BEGIN IMMEDIATE");
|
|
957
1059
|
} catch (error) {
|
|
1060
|
+
release?.();
|
|
958
1061
|
throw storageError(error, "Collecting unused content");
|
|
959
1062
|
}
|
|
960
1063
|
try {
|
|
961
1064
|
this.#checkLease(t);
|
|
1065
|
+
await this.#faults.afterGarbageCollectionBegin?.();
|
|
962
1066
|
const keep = new Set(
|
|
963
1067
|
this.#db.all("SELECT DISTINCT hash FROM entry WHERE content = 1").map((row) => row.hash)
|
|
964
1068
|
);
|
|
@@ -971,12 +1075,14 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
971
1075
|
} catch {
|
|
972
1076
|
}
|
|
973
1077
|
throw storageError(error, "Collecting unused content");
|
|
1078
|
+
} finally {
|
|
1079
|
+
release?.();
|
|
974
1080
|
}
|
|
975
1081
|
});
|
|
976
1082
|
}
|
|
977
1083
|
async reset(t, reason, options = {}) {
|
|
978
1084
|
await this.#mutate(async () => {
|
|
979
|
-
this.#write("Resetting the replica", () => {
|
|
1085
|
+
await this.#write("Resetting the replica", () => {
|
|
980
1086
|
this.#checkLease(t);
|
|
981
1087
|
this.#db.run("DELETE FROM entry");
|
|
982
1088
|
this.#db.run(
|
|
@@ -1003,9 +1109,11 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1003
1109
|
*/
|
|
1004
1110
|
async destroy(t) {
|
|
1005
1111
|
await this.#mutate(async () => {
|
|
1112
|
+
const release = this.#shared ? await acquireWritableMutation(this.#shared) : void 0;
|
|
1006
1113
|
try {
|
|
1007
1114
|
this.#db.exec("BEGIN IMMEDIATE");
|
|
1008
1115
|
} catch (error) {
|
|
1116
|
+
release?.();
|
|
1009
1117
|
throw storageError(error, "Removing the replica");
|
|
1010
1118
|
}
|
|
1011
1119
|
try {
|
|
@@ -1104,6 +1212,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1104
1212
|
this.#db.exec("ROLLBACK");
|
|
1105
1213
|
} catch {
|
|
1106
1214
|
}
|
|
1215
|
+
release?.();
|
|
1107
1216
|
}
|
|
1108
1217
|
});
|
|
1109
1218
|
}
|
|
@@ -1147,7 +1256,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1147
1256
|
* when both are done.
|
|
1148
1257
|
*/
|
|
1149
1258
|
async #purgeContent() {
|
|
1150
|
-
this.#write("Starting the revocation purge", () => {
|
|
1259
|
+
await this.#write("Starting the revocation purge", () => {
|
|
1151
1260
|
this.#db.run("UPDATE replica SET purge_pending = 1 WHERE id = 1 AND revoked_detail IS NOT NULL");
|
|
1152
1261
|
});
|
|
1153
1262
|
try {
|
|
@@ -1158,7 +1267,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1158
1267
|
if (!this.#checkpoint()) {
|
|
1159
1268
|
throw new ReplicaError(ReplicaErrorCode.BUSY, "A reader holds the replica's write-ahead log; the purge finishes on the next open.");
|
|
1160
1269
|
}
|
|
1161
|
-
this.#write("Finishing the revocation purge", () => {
|
|
1270
|
+
await this.#write("Finishing the revocation purge", () => {
|
|
1162
1271
|
this.#db.run("UPDATE replica SET purge_pending = 0 WHERE id = 1 AND revoked_detail IS NOT NULL");
|
|
1163
1272
|
});
|
|
1164
1273
|
}
|
|
@@ -1168,6 +1277,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1168
1277
|
});
|
|
1169
1278
|
}
|
|
1170
1279
|
async get(key) {
|
|
1280
|
+
this.#assertAccepting();
|
|
1171
1281
|
try {
|
|
1172
1282
|
const row = this.#db.get("SELECT key, deleted, etag, hash, metadata, content FROM entry WHERE key = ?", key);
|
|
1173
1283
|
return row === void 0 ? void 0 : entryOf(row);
|
|
@@ -1176,6 +1286,7 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1176
1286
|
}
|
|
1177
1287
|
}
|
|
1178
1288
|
async list(o) {
|
|
1289
|
+
this.#assertAccepting();
|
|
1179
1290
|
const where = ["deleted = 0"];
|
|
1180
1291
|
const params = [];
|
|
1181
1292
|
if (o.prefix !== void 0 && o.prefix !== "") {
|
|
@@ -1261,15 +1372,31 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
|
|
|
1261
1372
|
lastReset: state.lastReset
|
|
1262
1373
|
};
|
|
1263
1374
|
}
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
this.#
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1375
|
+
close() {
|
|
1376
|
+
if (this.#closePromise) return this.#closePromise;
|
|
1377
|
+
this.#closing = true;
|
|
1378
|
+
this.#closePromise = (async () => {
|
|
1379
|
+
if (this.#activeMutations !== 0) {
|
|
1380
|
+
await new Promise((resolve2) => {
|
|
1381
|
+
this.#drained = resolve2;
|
|
1382
|
+
});
|
|
1383
|
+
}
|
|
1384
|
+
this.#closed = true;
|
|
1385
|
+
const fd = this.#directoryFd;
|
|
1386
|
+
this.#directoryFd = void 0;
|
|
1387
|
+
if (this.#shared) {
|
|
1388
|
+
sharedStores.unregister(this);
|
|
1389
|
+
releaseWritable(this.#shared);
|
|
1390
|
+
} else {
|
|
1391
|
+
if (fd !== void 0) pinnedDirectories.unregister(this);
|
|
1392
|
+
try {
|
|
1393
|
+
this.#database.close();
|
|
1394
|
+
} finally {
|
|
1395
|
+
if (fd !== void 0) closeSync(fd);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
})();
|
|
1399
|
+
return this.#closePromise;
|
|
1273
1400
|
}
|
|
1274
1401
|
};
|
|
1275
1402
|
export {
|