UNPKG

@daiso-tech/core

Version:

The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.

211 lines 8.13 kB
/** * @module SharedLock */ import {} from "../../../../shared-lock/contracts/_module.js"; import {} from "../../../../time-span/implementations/_module.js"; /** * @internal */ export class DatabaseSharedLockAdapter { adapter; static async _forceReleaseWriter(trx, key) { const readerSemaphore = await trx.reader.findSemaphore(key); if (readerSemaphore !== null) { return false; } const lockData = await trx.writer.remove(key); if (lockData === null) { return false; } if (lockData.expiration === null) { return true; } return lockData.expiration > new Date(); } static async _forceReleaseAllReaders(trx, key) { const writerLock = await trx.writer.find(key); if (writerLock !== null) { return false; } const semapahoreSlotDataArray = await trx.reader.removeAllSlots(key); return semapahoreSlotDataArray.some((semapahoreSlotData) => { return (semapahoreSlotData.expiration === null || semapahoreSlotData.expiration > new Date()); }); } static async getWriterState(trx, key) { const lockData = await trx.writer.find(key); if (lockData === null) { return null; } if (lockData.expiration === null) { return lockData; } if (lockData.expiration <= new Date()) { return null; } return lockData; } static async getReaderState(trx, key) { const semaphore = await trx.reader.findSemaphore(key); if (semaphore === null) { return null; } const slots = await trx.reader.findSlots(key); const unexpiredSlots = slots.filter((slot) => slot.expiration === null || slot.expiration > new Date()); if (unexpiredSlots.length === 0) { return null; } const unexpiredSlotsAsMap = new Map(unexpiredSlots.map((slot) => [slot.id, slot.expiration])); return { limit: semaphore.limit, acquiredSlots: unexpiredSlotsAsMap, }; } constructor(adapter) { this.adapter = adapter; } async acquireWriter(key, lockId, ttl) { const expiration = ttl?.toEndDate() ?? null; return await this.adapter.transaction(async (trx) => { const readerSemaphore = await trx.reader.findSemaphore(key); if (readerSemaphore !== null) { return false; } const writerLock = await trx.writer.find(key); if (writerLock === null) { await trx.writer.upsert(key, lockId, expiration); return true; } if (writerLock.owner === lockId) { return true; } if (writerLock.expiration === null) { return false; } if (writerLock.expiration <= new Date()) { await trx.writer.upsert(key, lockId, expiration); return true; } return writerLock.expiration <= new Date(); }); } async releaseWriter(key, lockId) { return await this.adapter.transaction(async (trx) => { const readerSemaphore = await trx.reader.findSemaphore(key); if (readerSemaphore !== null) { return false; } const lockData = await trx.writer.removeIfOwner(key, lockId); if (lockData === null) { return false; } const { expiration } = lockData; const hasNoExpiration = expiration === null; if (hasNoExpiration) { return true; } const { owner } = lockData; const isNotExpired = expiration > new Date(); const isCurrentOwner = lockId === owner; return isNotExpired && isCurrentOwner; }); } async forceReleaseWriter(key) { return await this.adapter.transaction(async (trx) => { return DatabaseSharedLockAdapter._forceReleaseWriter(trx, key); }); } async refreshWriter(key, lockId, ttl) { return await this.adapter.transaction(async (trx) => { const readerSemaphore = await trx.reader.findSemaphore(key); if (readerSemaphore !== null) { return false; } const updateCount = await trx.writer.updateExpiration(key, lockId, ttl.toEndDate()); return Number(updateCount) > 0; }); } async acquireReader(settings) { const expiration = settings.ttl?.toEndDate() ?? null; return await this.adapter.transaction(async (trx) => { const writerLock = await trx.writer.find(settings.key); if (writerLock !== null) { return false; } const semaphoreData = await trx.reader.findSemaphore(settings.key); let limit = semaphoreData?.limit; if (limit === undefined) { limit = settings.limit; await trx.reader.upsertSemaphore(settings.key, limit); } const slots = await trx.reader.findSlots(settings.key); const unexpiredSlots = slots.filter((slot) => slot.expiration === null || slot.expiration > new Date()); if (unexpiredSlots.length === 0) { await trx.reader.upsertSemaphore(settings.key, settings.limit); } if (unexpiredSlots.length >= limit) { return false; } const hasNotSlot = unexpiredSlots.every((slot) => slot.id !== settings.lockId); if (hasNotSlot) { await trx.reader.upsertSlot(settings.key, settings.lockId, expiration); } return true; }); } async releaseReader(key, lockId) { return await this.adapter.transaction(async (trx) => { const writerLock = await trx.writer.find(key); if (writerLock !== null) { return false; } const semapahoreSlotData = await trx.reader.removeSlot(key, lockId); if (semapahoreSlotData === null) { return false; } return (semapahoreSlotData.expiration === null || semapahoreSlotData.expiration > new Date()); }); } async forceReleaseAllReaders(key) { return await this.adapter.transaction(async (trx) => { return DatabaseSharedLockAdapter._forceReleaseAllReaders(trx, key); }); } async refreshReader(key, slotId, ttl) { return await this.adapter.transaction(async (trx) => { const writerLock = await trx.writer.find(key); if (writerLock !== null) { return false; } const updateCount = await trx.reader.updateExpiration(key, slotId, ttl.toEndDate()); return Number(updateCount) > 0; }); } async forceRelease(key) { return await this.adapter.transaction(async (trx) => { const [hasForceReleasedWriter, hasForceReleasedAllReaders] = await Promise.all([ await DatabaseSharedLockAdapter._forceReleaseWriter(trx, key), await DatabaseSharedLockAdapter._forceReleaseAllReaders(trx, key), ]); return hasForceReleasedWriter || hasForceReleasedAllReaders; }); } async getState(key) { return await this.adapter.transaction(async (trx) => { const [writerState, readerState] = await Promise.all([ DatabaseSharedLockAdapter.getWriterState(trx, key), DatabaseSharedLockAdapter.getReaderState(trx, key), ]); if (writerState === null && readerState === null) { return null; } return { writer: writerState, reader: readerState, }; }); } } //# sourceMappingURL=database-shared-lock-adapter.js.map