- Databases now correctly closed after rebuilding.
This commit is contained in:
vorotamoroz
2026-01-09 11:45:00 +00:00
parent 02aa9319c3
commit 4c3393d8b2
4 changed files with 73 additions and 16 deletions
+64 -10
View File
@@ -1,5 +1,7 @@
import { deleteDB, type IDBPDatabase, openDB } from "idb"; import { deleteDB, type IDBPDatabase, openDB } from "idb";
import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts"; import type { KeyValueDatabase } from "../lib/src/interfaces/KeyValueDatabase.ts";
import { serialized } from "octagonal-wheels/concurrency/lock";
import { Logger } from "octagonal-wheels/common/logger";
const databaseCache: { [key: string]: IDBPDatabase<any> } = {}; const databaseCache: { [key: string]: IDBPDatabase<any> } = {};
export const OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatabase> => { export const OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatabase> => {
if (dbKey in databaseCache) { if (dbKey in databaseCache) {
@@ -7,37 +9,89 @@ export const OpenKeyValueDatabase = async (dbKey: string): Promise<KeyValueDatab
delete databaseCache[dbKey]; delete databaseCache[dbKey];
} }
const storeKey = dbKey; const storeKey = dbKey;
const dbPromise = openDB(dbKey, 1, { let db: IDBPDatabase<any> | null = null;
upgrade(db, _oldVersion, _newVersion, _transaction, _event) { const _openDB = () => {
return db.createObjectStore(storeKey); return serialized("keyvaluedb-" + dbKey, async () => {
}, const dbInstance = await openDB(dbKey, 1, {
}); upgrade(db, _oldVersion, _newVersion, _transaction, _event) {
const db = await dbPromise; return db.createObjectStore(storeKey);
databaseCache[dbKey] = db; },
blocking(currentVersion, blockedVersion, event) {
Logger(
`Blocking database open for ${dbKey}: currentVersion=${currentVersion}, blockedVersion=${blockedVersion}`
);
databaseCache[dbKey]?.close();
delete databaseCache[dbKey];
},
blocked(currentVersion, blockedVersion, event) {
Logger(
`Database open blocked for ${dbKey}: currentVersion=${currentVersion}, blockedVersion=${blockedVersion}`
);
},
terminated() {
Logger(`Database connection terminated for ${dbKey}`);
},
});
databaseCache[dbKey] = dbInstance;
return dbInstance;
});
};
const closeDB = () => {
if (db) {
db.close();
delete databaseCache[dbKey];
db = null;
}
};
db = await _openDB();
return { return {
async get<T>(key: IDBValidKey): Promise<T> { async get<T>(key: IDBValidKey): Promise<T> {
if (!db) {
db = await _openDB();
databaseCache[dbKey] = db;
}
return await db.get(storeKey, key); return await db.get(storeKey, key);
}, },
async set<T>(key: IDBValidKey, value: T) { async set<T>(key: IDBValidKey, value: T) {
if (!db) {
db = await _openDB();
databaseCache[dbKey] = db;
}
return await db.put(storeKey, value, key); return await db.put(storeKey, value, key);
}, },
async del(key: IDBValidKey) { async del(key: IDBValidKey) {
if (!db) {
db = await _openDB();
databaseCache[dbKey] = db;
}
return await db.delete(storeKey, key); return await db.delete(storeKey, key);
}, },
async clear() { async clear() {
if (!db) {
db = await _openDB();
databaseCache[dbKey] = db;
}
return await db.clear(storeKey); return await db.clear(storeKey);
}, },
async keys(query?: IDBValidKey | IDBKeyRange, count?: number) { async keys(query?: IDBValidKey | IDBKeyRange, count?: number) {
if (!db) {
db = await _openDB();
databaseCache[dbKey] = db;
}
return await db.getAllKeys(storeKey, query, count); return await db.getAllKeys(storeKey, query, count);
}, },
close() { close() {
delete databaseCache[dbKey]; delete databaseCache[dbKey];
return db.close(); return closeDB();
}, },
async destroy() { async destroy() {
delete databaseCache[dbKey]; delete databaseCache[dbKey];
db.close(); // await closeDB();
await deleteDB(dbKey); await deleteDB(dbKey, {
blocked() {
console.warn(`Database delete blocked for ${dbKey}`);
},
});
}, },
}; };
}; };
+1 -1
Submodule src/lib updated: 1adec8f126...bc761fcf57
+6 -5
View File
@@ -50,27 +50,28 @@ export class ModuleKeyValueDB extends AbstractModule {
return Promise.resolve(true); return Promise.resolve(true);
} }
_getSimpleStore<T>(kind: string) { _getSimpleStore<T>(kind: string) {
const getDB = () => this.core.kvDB;
const prefix = `${kind}-`; const prefix = `${kind}-`;
return { return {
get: async (key: string): Promise<T> => { get: async (key: string): Promise<T> => {
return await this.core.kvDB.get(`${prefix}${key}`); return await getDB().get(`${prefix}${key}`);
}, },
set: async (key: string, value: any): Promise<void> => { set: async (key: string, value: any): Promise<void> => {
await this.core.kvDB.set(`${prefix}${key}`, value); await getDB().set(`${prefix}${key}`, value);
}, },
delete: async (key: string): Promise<void> => { delete: async (key: string): Promise<void> => {
await this.core.kvDB.del(`${prefix}${key}`); await getDB().del(`${prefix}${key}`);
}, },
keys: async ( keys: async (
from: string | undefined, from: string | undefined,
to: string | undefined, to: string | undefined,
count?: number | undefined count?: number | undefined
): Promise<string[]> => { ): Promise<string[]> => {
const ret = this.core.kvDB.keys( const ret = await getDB().keys(
IDBKeyRange.bound(`${prefix}${from || ""}`, `${prefix}${to || ""}`), IDBKeyRange.bound(`${prefix}${from || ""}`, `${prefix}${to || ""}`),
count count
); );
return (await ret) return ret
.map((e) => e.toString()) .map((e) => e.toString())
.filter((e) => e.startsWith(prefix)) .filter((e) => e.startsWith(prefix))
.map((e) => e.substring(prefix.length)); .map((e) => e.substring(prefix.length));
+2
View File
@@ -16,6 +16,7 @@ import { AbstractModule } from "../AbstractModule.ts";
import { EVENT_PLATFORM_UNLOADED } from "../../lib/src/PlatformAPIs/base/APIBase.ts"; import { EVENT_PLATFORM_UNLOADED } from "../../lib/src/PlatformAPIs/base/APIBase.ts";
import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts"; import type { InjectableServiceHub } from "../../lib/src/services/InjectableServices.ts";
import type { LiveSyncCore } from "../../main.ts"; import type { LiveSyncCore } from "../../main.ts";
import { initialiseWorkerModule } from "@/lib/src/worker/bgWorker.ts";
export class ModuleLiveSyncMain extends AbstractModule { export class ModuleLiveSyncMain extends AbstractModule {
async _onLiveSyncReady() { async _onLiveSyncReady() {
@@ -80,6 +81,7 @@ export class ModuleLiveSyncMain extends AbstractModule {
} }
async _onLiveSyncLoad(): Promise<boolean> { async _onLiveSyncLoad(): Promise<boolean> {
initialiseWorkerModule();
await this.services.appLifecycle.onWireUpEvents(); await this.services.appLifecycle.onWireUpEvents();
// debugger; // debugger;
eventHub.emitEvent(EVENT_PLUGIN_LOADED, this.core); eventHub.emitEvent(EVENT_PLUGIN_LOADED, this.core);