UNPKG

rxdb

Version:

A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/

98 lines (85 loc) 3.21 kB
import type { LokiDatabaseSettings } from '../../types/index.d.ts'; import { PROMISE_RESOLVE_VOID, requestIdlePromise } from '../utils/index.ts'; /** * The autosave feature of lokijs has strange behaviors * and often runs a save in critical moments when other * more important tasks are running. * So instead we use a custom save queue that ensures we * only run loki.saveDatabase() when nothing else is running. */ export class LokiSaveQueue { public writesSinceLastRun: number = 0; /** * Ensures that we do not run multiple saves * in parallel */ public saveQueue: Promise<void> = PROMISE_RESOLVE_VOID; // track amount of non-finished save calls in the queue. public saveQueueC = 0; constructor( public readonly lokiDatabase: any, public readonly databaseSettings: LokiDatabaseSettings ) { } public addWrite() { this.writesSinceLastRun = this.writesSinceLastRun + 1; this.run(); } public run() { if ( // no persistence adapter given, so we do not need to save !this.databaseSettings.adapter || // do not add more then two pending calls to the queue. this.saveQueueC > 2 ) { return this.saveQueue; } this.saveQueueC = this.saveQueueC + 1; this.saveQueue = this.saveQueue .then(async () => { /** * Always wait until the JavaScript process is idle. * This ensures that CPU blocking writes are finished * before we proceed. */ await requestIdlePromise(); // no write happened since the last save call if (this.writesSinceLastRun === 0) { return; } /** * Because LokiJS is a in-memory database, * we can just wait until the JavaScript process is idle * via requestIdlePromise(). Then we know that nothing important * is running at the moment. */ await requestIdlePromise().then(() => requestIdlePromise()); if (this.writesSinceLastRun === 0) { return; } const writeAmount = this.writesSinceLastRun; this.writesSinceLastRun = 0; return new Promise<void>((res, rej) => { this.lokiDatabase.saveDatabase((err: any) => { if (err) { this.writesSinceLastRun = this.writesSinceLastRun + writeAmount; rej(err); } else { if (this.databaseSettings.autosaveCallback) { this.databaseSettings.autosaveCallback(); } res(); } }); }); }) .catch(() => { }) .then(() => { this.saveQueueC = this.saveQueueC - 1; }); return this.saveQueue; } }