diff --git a/src/apps/browser/BrowserKeyValueDatabase.ts b/src/apps/browser/BrowserKeyValueDatabase.ts index f1f17a1f..02acf3dd 100644 --- a/src/apps/browser/BrowserKeyValueDatabase.ts +++ b/src/apps/browser/BrowserKeyValueDatabase.ts @@ -3,14 +3,14 @@ import type { KeyValueDatabaseFactory, } from "@vrtmrz/livesync-commonlib/compat/interfaces/KeyValueDatabase"; import { deleteDB, openDB, type IDBPDatabase } from "idb"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; /** Creates an application-owned IndexedDB key-value factory for browser runtimes. */ export function createBrowserKeyValueDatabaseFactory(): KeyValueDatabaseFactory { const cache = new Map(); return async (databaseKey) => - await serialized(`OpenBrowserKeyValueDatabase-${databaseKey}`, async () => { + await withLock(`OpenBrowserKeyValueDatabase-${databaseKey}`, async () => { const cached = cache.get(databaseKey); if (cached && !cached.isDestroyed) { return cached; diff --git a/src/common/KeyValueDB.ts b/src/common/KeyValueDB.ts index 47a75c70..a571274f 100644 --- a/src/common/KeyValueDB.ts +++ b/src/common/KeyValueDB.ts @@ -1,6 +1,6 @@ import { deleteDB, type IDBPDatabase, openDB } from "idb"; import type { KeyValueDatabase } from "@vrtmrz/livesync-commonlib/compat/interfaces/KeyValueDatabase"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; import { Logger } from "octagonal-wheels/common/logger"; const databaseCache: { [key: string]: IDBPDatabase } = {}; export { OpenKeyValueDatabase } from "./KeyValueDBv2.ts"; @@ -13,7 +13,7 @@ export const _OpenKeyValueDatabase = async (dbKey: string): Promise | null = null; const _openDB = () => { - return serialized("keyvaluedb-" + dbKey, async () => { + return withLock("keyvaluedb-" + dbKey, async () => { const dbInstance = await openDB(dbKey, 1, { upgrade(db, _oldVersion, _newVersion, _transaction, _event) { return db.createObjectStore(storeKey); diff --git a/src/common/KeyValueDBv2.ts b/src/common/KeyValueDBv2.ts index d21c15bd..cf4c3598 100644 --- a/src/common/KeyValueDBv2.ts +++ b/src/common/KeyValueDBv2.ts @@ -1,12 +1,12 @@ import { LOG_LEVEL_VERBOSE, Logger } from "@vrtmrz/livesync-commonlib/compat/common/logger"; import type { KeyValueDatabase } from "@vrtmrz/livesync-commonlib/compat/interfaces/KeyValueDatabase"; import { deleteDB, openDB, type IDBPDatabase } from "idb"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; const databaseCache = new Map(); export async function OpenKeyValueDatabase(dbKey: string): Promise { - return await serialized(`OpenKeyValueDatabase-${dbKey}`, async () => { + return await withLock(`OpenKeyValueDatabase-${dbKey}`, async () => { const cachedDB = databaseCache.get(dbKey); if (cachedDB) { if (!cachedDB.isDestroyed) { diff --git a/src/features/ConfigSync/CmdConfigSync.ts b/src/features/ConfigSync/CmdConfigSync.ts index 55b11869..41219d05 100644 --- a/src/features/ConfigSync/CmdConfigSync.ts +++ b/src/features/ConfigSync/CmdConfigSync.ts @@ -49,7 +49,7 @@ import { decodeBinary, readString, } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/convert"; -import { serialized, shareRunningResult } from "octagonal-wheels/concurrency/lock"; +import { withLock, shareRunningResult } from "octagonal-wheels/concurrency/lock"; import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts"; import { stripAllPrefixes } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/path"; import { cancelTask, EVEN, isCustomisationSyncMetadata, isPluginMetadata, scheduleTask } from "@/common/utils.ts"; @@ -752,7 +752,7 @@ export class ConfigSync extends LiveSyncCommands { // const unifiedFilenameWithKey = this.filenameWithUnifiedKey(updatedDocumentPath); const { pathV1 } = this.parseUnifiedPath(unifiedFilenameWithKey); - await serialized(`config:catalogue:${pathV1}`, async () => { + await withLock(`config:catalogue:${pathV1}`, async () => { if (!isCurrent()) return; const oldEntry = this.pluginList.find((e) => e.documentPath == pathV1); let entry: PluginDataExDisplayV2 | undefined = undefined; @@ -925,7 +925,7 @@ export class ConfigSync extends LiveSyncCommands { path = path.split("%")[1] as FilePath; } if (fileA.path.endsWith(".json")) { - return serialized( + return withLock( "config:merge-data", () => new Promise((res) => { @@ -1276,7 +1276,7 @@ export class ConfigSync extends LiveSyncCommands { requireCompletion: boolean ) { const vf = this.filenameWithUnifiedKey(path, term); - return await serialized(`plugin-${vf}`, async () => { + return await withLock(`plugin-${vf}`, async () => { const prefixedFileName = vf; const id = await this.path2id(prefixedFileName); @@ -1379,7 +1379,7 @@ export class ConfigSync extends LiveSyncCommands { const vf = this.filenameToUnifiedKey(path, term); // console.warn(`Storing ${path} to ${bareVF} :--> ${keyedVF}`); - return await serialized(`plugin-${vf}`, async () => { + return await withLock(`plugin-${vf}`, async () => { const category = this.getFileCategory(path); let mtime = 0; let fileTargets = [] as FilePath[]; @@ -1683,7 +1683,7 @@ export class ConfigSync extends LiveSyncCommands { ) { // const id = await this.path2id(prefixedFileName); const mtime = new Date().getTime(); - return await serialized("file-x-" + prefixedFileName, async () => { + return await withLock("file-x-" + prefixedFileName, async () => { try { const old = (await this.localDatabase.getDBEntryMeta(prefixedFileName, undefined, false)) as | InternalFileEntry diff --git a/src/features/HiddenFileSync/CmdHiddenFileSync.ts b/src/features/HiddenFileSync/CmdHiddenFileSync.ts index e9c32a96..c5d42bde 100644 --- a/src/features/HiddenFileSync/CmdHiddenFileSync.ts +++ b/src/features/HiddenFileSync/CmdHiddenFileSync.ts @@ -40,7 +40,7 @@ import { displayRev, } from "@/common/utils.ts"; import { PeriodicProcessor } from "@/common/PeriodicProcessor.ts"; -import { serialized, skipIfDuplicated } from "octagonal-wheels/concurrency/lock"; +import { withLock, skipIfDuplicated } from "octagonal-wheels/concurrency/lock"; import { JsonResolveModal } from "@/features/HiddenFileCommon/JsonResolveModal.ts"; import { LiveSyncCommands } from "@/features/LiveSyncCommands.ts"; import { addPrefix, stripAllPrefixes } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/path"; @@ -547,7 +547,7 @@ export class HiddenFileSync extends LiveSyncCommands { hiddenFilesEventCount.value++; const rel = await this.semaphore.acquire(); try { - return await serialized(`hidden-file-event:${file}`, async () => { + return await withLock(`hidden-file-event:${file}`, async () => { hiddenFilesProcessingCount.value++; try { return await fn(); @@ -1182,7 +1182,7 @@ Offline Changed files: ${processFiles.length}`; async applyOfflineChanges(showNotice: boolean) { const logLevel = getLogLevel(showNotice); - return await serialized("applyOfflineChanges", async () => { + return await withLock("applyOfflineChanges", async () => { const p = this._progress("[⚙ Apply untracked changes ]\n", logLevel); this._log(`Track changes.`, logLevel); p.log("Enumerating local files..."); @@ -1703,7 +1703,7 @@ Offline Changed files: ${files.length}`; } const prefixedFileName = addPrefix(storeFilePath, ICHeader); - return await serialized("file-" + prefixedFileName, async () => { + return await withLock("file-" + prefixedFileName, async () => { try { const fileInfo = "stat" in file && "body" in file ? file : await this.loadFileWithInfo(storeFilePath); if (fileInfo.deleted) { @@ -1764,7 +1764,7 @@ Offline Changed files: ${files.length}`; } const prefixedFileName = addPrefix(storeFilePath, ICHeader); - return await serialized("file-" + prefixedFileName, async () => { + return await withLock("file-" + prefixedFileName, async () => { try { const baseData = await this.getLiveInternalRevision(prefixedFileName, baseRevision); if (baseData === false) { @@ -1842,7 +1842,7 @@ Offline Changed files: ${files.length}`; if (await this.services.vault.isIgnoredByIgnoreFile(storageFilePath)) { return undefined; } - return await serialized("file-" + prefixedFileName, async () => { + return await withLock("file-" + prefixedFileName, async () => { try { const baseData = strict ? await this.loadBaseSaveDataStrict(storeFilePath, false) @@ -1913,7 +1913,7 @@ Offline Changed files: ${files.length}`; if (await this.services.vault.isIgnoredByIgnoreFile(storageFilePath)) { return undefined; } - return await serialized("file-" + prefixedFileName, async () => { + return await withLock("file-" + prefixedFileName, async () => { try { // Check conflicted status const metaOnDB = requiredLiveRevision diff --git a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts index 955813f3..5300ff03 100644 --- a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts +++ b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.ts @@ -12,7 +12,7 @@ import { } from "@vrtmrz/livesync-commonlib/compat/common/types"; import { getNoFromRev } from "@vrtmrz/livesync-commonlib/compat/pouchdb/LiveSyncLocalDB"; import { LiveSyncCommands } from "@/features/LiveSyncCommands"; -import { serialized } from "octagonal-wheels/concurrency/lock_v2"; +import { withLock } from "octagonal-wheels/concurrency/lock_v2"; import { arrayToChunkedArray } from "octagonal-wheels/collection"; import { EVENT_REQUEST_PERFORM_GC_V3, eventHub } from "@/common/events"; import type { LiveSyncCouchDBReplicator } from "@vrtmrz/livesync-commonlib/compat/replication/couchdb/LiveSyncReplicator"; @@ -435,7 +435,7 @@ Note: **Make sure to synchronise all devices before deletion.** chunkSet.add(doc._id); } else if ("children" in doc) { await processDoc(doc, isDeleted); - await serialized("x-process-doc", async () => await processDocRevisions(doc)); + await withLock("x-process-doc", async () => await processDocRevisions(doc)); } }; // Track changes diff --git a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.unit.spec.ts b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.unit.spec.ts index 89796f4f..8fc5f546 100644 --- a/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.unit.spec.ts +++ b/src/features/LocalDatabaseMainte/CmdLocalDatabaseMainte.unit.spec.ts @@ -4,7 +4,7 @@ vi.mock("octagonal-wheels/number", () => ({ sizeToHumanReadable: vi.fn((value: number) => `${value} B`), })); vi.mock("octagonal-wheels/concurrency/lock_v2", () => ({ - serialized: vi.fn((_key: string, task: () => unknown) => task()), + withLock: vi.fn((_key: string, task: () => unknown) => task()), })); vi.mock("octagonal-wheels/collection", () => ({ arrayToChunkedArray: vi.fn((values: unknown[]) => [values]), diff --git a/src/modules/features/ModuleLog.ts b/src/modules/features/ModuleLog.ts index 58f77daf..cafaf7e7 100644 --- a/src/modules/features/ModuleLog.ts +++ b/src/modules/features/ModuleLog.ts @@ -34,7 +34,7 @@ import { AbstractObsidianModule } from "@/modules/AbstractObsidianModule.ts"; import { addIcon, debounce, normalizePath, Notice, stringifyYaml, type WorkspaceLeaf } from "@/deps.ts"; import { LOG_LEVEL_NOTICE, setGlobalLogFunction } from "octagonal-wheels/common/logger"; import { LogPaneView, VIEW_TYPE_LOG } from "./Log/LogPaneView.ts"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; import { $msg } from "@/common/translation"; import { P2PLogCollector } from "@vrtmrz/livesync-commonlib/compat/replication/trystero/P2PLogCollector"; import { REMOTE_REQUEST_ACTIVITY_MINIMUM_VISIBLE_MS, getTrackedRequestCount } from "./RemoteActivityStatus.ts"; @@ -524,7 +524,7 @@ ${stringifyYaml(info)} writeLogToTheFile(now: Date, vaultName: string, newMessage: string) { fireAndForget(() => - serialized("writeLog", async () => { + withLock("writeLog", async () => { const time = now.toISOString().split("T")[0]; const logDate = `${PREFIXMD_LOGFILE}${time}.md`; const file = await this.core.storageAccess.isExists(normalizePath(logDate)); diff --git a/src/serviceFeatures/conflictResolution/operations.ts b/src/serviceFeatures/conflictResolution/operations.ts index 39059d9f..afb974f8 100644 --- a/src/serviceFeatures/conflictResolution/operations.ts +++ b/src/serviceFeatures/conflictResolution/operations.ts @@ -27,7 +27,7 @@ import type { LiveSyncEventHub } from "@vrtmrz/livesync-commonlib/context"; import type { StorageAccess } from "@vrtmrz/livesync-commonlib/compat/interfaces/StorageAccess"; import { EVENT_CONFLICT_CANCELLED } from "@vrtmrz/livesync-commonlib/compat/events/coreEvents"; import { NO_INTERACTION } from "@vrtmrz/livesync-commonlib/replication"; -import { isLockAcquired, serialized } from "octagonal-wheels/concurrency/lock"; +import { isLockAcquired, withLock } from "octagonal-wheels/concurrency/lock"; import diff_match_patch from "diff-match-patch"; import { stripAllPrefixes, isPlainText } from "@vrtmrz/livesync-commonlib/compat/string_and_binary/path"; @@ -192,7 +192,7 @@ export function createConflictResolutionOperations( // per-file lock. Dialogues for other paths remain untouched. dependencies.events.emitEvent(EVENT_CONFLICT_CANCELLED, filename); } - return await serialized(serialisationKey, async () => { + return await withLock(serialisationKey, async () => { if (latestResolveRequestByFilename.get(filename) !== requestId) { return; } diff --git a/src/serviceFeatures/interactiveConflictResolution/operations.ts b/src/serviceFeatures/interactiveConflictResolution/operations.ts index 4c583e31..3196b126 100644 --- a/src/serviceFeatures/interactiveConflictResolution/operations.ts +++ b/src/serviceFeatures/interactiveConflictResolution/operations.ts @@ -22,7 +22,7 @@ import type { import type { LiveSyncLocalDB } from "@vrtmrz/livesync-commonlib/compat/pouchdb/LiveSyncLocalDB"; import type { LiveSyncEventHub } from "@vrtmrz/livesync-commonlib/context"; import { fireAndForget } from "octagonal-wheels/promises"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; import { NO_INTERACTION } from "@vrtmrz/livesync-commonlib/replication"; import { displayRev } from "@vrtmrz/livesync-commonlib/compat/common/utils"; import { EVENT_CONFLICT_CANCELLED, EVENT_ON_UNRESOLVED_ERROR } from "@/common/events.ts"; @@ -160,7 +160,7 @@ export function createInteractiveConflictResolutionOperations( // UI for resolving different files should proceed one-by-one. A newer // request for the active file replaces its dialogue instead of waiting // behind a comparison which is already stale. - return await serialized(dialogueSerialisationKey, async () => { + return await withLock(dialogueSerialisationKey, async () => { if (disposed || latestRequestByFilename.get(filename) !== requestId) { return false; } diff --git a/src/serviceFeatures/replication/ReplicateResultProcessor.ts b/src/serviceFeatures/replication/ReplicateResultProcessor.ts index e191cdc4..a45d3658 100644 --- a/src/serviceFeatures/replication/ReplicateResultProcessor.ts +++ b/src/serviceFeatures/replication/ReplicateResultProcessor.ts @@ -26,7 +26,7 @@ import { import { fireAndForget, isAnyNote, throttle } from "@vrtmrz/livesync-commonlib/compat/common/utils"; import { Semaphore } from "octagonal-wheels/concurrency/semaphore_v2"; import { withCounting } from "octagonal-wheels/concurrency/counting"; -import { serialized } from "octagonal-wheels/concurrency/lock"; +import { withLock } from "octagonal-wheels/concurrency/lock"; import type { ReactiveSource } from "octagonal-wheels/dataobject/reactive_v2"; import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore"; import { isNotFoundError } from "@vrtmrz/livesync-commonlib/compat/common/utils.doc"; @@ -534,7 +534,7 @@ export class ReplicateResultProcessor { private _applyToDatabase(doc_: PouchDB.Core.ExistingDocument) { const dbDoc = doc_ as LoadedEntry; // It has no `data` const path = this.getPath(dbDoc); - return serialized(`replication-process:${dbDoc._id}`, async () => { + return withLock(`replication-process:${dbDoc._id}`, async () => { const docNote = `${path} (${shortenId(dbDoc._id)}, ${shortenRev(dbDoc._rev)})`; const isRequired = await this.checkIsChangeRequiredForDatabaseProcessing(dbDoc); if (!isRequired) {