Skip to content

Commit

Permalink
Merge pull request #89 from rhashimoto/idb-timeout-workaround
Browse files Browse the repository at this point in the history
Rework IDBBatchAtomicVFS to avoid transaction timeouts
  • Loading branch information
rhashimoto authored May 18, 2023
2 parents 96de5e0 + bddeba9 commit dc81eaa
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 113 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wa-sqlite",
"version": "0.9.1",
"version": "0.9.2",
"type": "module",
"main": "src/sqlite-api.js",
"types": "src/types/index.d.ts",
Expand Down
76 changes: 67 additions & 9 deletions src/examples/IDBBatchAtomicVFS.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { WebLocksExclusive as WebLocks } from './WebLocks.js';
import { IDBContext } from './IDBContext.js';

const SECTOR_SIZE = 512;
const MAX_TASK_MILLIS = 3000;

/**
* @typedef VFSOptions
Expand Down Expand Up @@ -53,6 +54,9 @@ export class IDBBatchAtomicVFS extends VFS.Base {
/** @type {IDBContext} */ #idb;
/** @type {Set<string>} */ #pendingPurges = new Set();

#taskTimestamp = performance.now();
#pendingAsync = new Set();

constructor(idbDatabaseName = 'wa-sqlite', options = DEFAULT_OPTIONS) {
super();
this.name = idbDatabaseName;
Expand All @@ -67,7 +71,7 @@ export class IDBBatchAtomicVFS extends VFS.Base {
await this.xClose(fileId);
}

this.#idb?.close();
await this.#idb?.close();
this.#idb = null;
}

Expand Down Expand Up @@ -203,6 +207,36 @@ export class IDBBatchAtomicVFS extends VFS.Base {
* @returns {number}
*/
xWrite(fileId, pData, iOffset) {
// Handle asynchronously every MAX_TASK_MILLIS milliseconds. This is
// tricky because Asyncify calls asynchronous methods twice: once
// to initiate the call and unwinds the stack, then rewinds the
// stack and calls again to retrieve the completed result.
const rewound = this.#pendingAsync.has(fileId);
if (rewound || performance.now() - this.#taskTimestamp > MAX_TASK_MILLIS) {
const result = this.handleAsync(async () => {
if (this.handleAsync !== super.handleAsync) {
this.#pendingAsync.add(fileId);
}
await new Promise(resolve => setTimeout(resolve));

const result = this.#xWriteHelper(fileId, pData, iOffset);
this.#taskTimestamp = performance.now();
return result;
});

if (rewound) this.#pendingAsync.delete(fileId);
return result;
}
return this.#xWriteHelper(fileId, pData, iOffset);
}

/**
* @param {number} fileId
* @param {Uint8Array} pData
* @param {number} iOffset
* @returns {number}
*/
#xWriteHelper(fileId, pData, iOffset) {
const file = this.#mapIdToFile.get(fileId);
log(`xWrite ${file.path} ${pData.byteLength} ${iOffset}`);

Expand Down Expand Up @@ -275,25 +309,49 @@ export class IDBBatchAtomicVFS extends VFS.Base {

/**
* @param {number} fileId
* @param {*} flags
* @param {number} flags
* @returns {number}
*/
xSync(fileId, flags) {
// Skip IndexedDB sync if durability is relaxed and the last
// sync was recent enough.
const rewound = this.#pendingAsync.has(fileId);
if (rewound || this.#options.durability !== 'relaxed' ||
performance.now() - this.#taskTimestamp > MAX_TASK_MILLIS) {
const result = this.handleAsync(async () => {
if (this.handleAsync !== super.handleAsync) {
this.#pendingAsync.add(fileId);
}

const result = await this.#xSyncHelper(fileId, flags);
this.#taskTimestamp = performance.now();
return result;
});

if (rewound) this.#pendingAsync.delete(fileId);
return result;
}

const file = this.#mapIdToFile.get(fileId);
log(`xSync ${file.path} ${flags}`);
return VFS.SQLITE_OK;
}

/**
* @param {number} fileId
* @param {number} flags
* @returns {Promise<number>}
*/
async #xSyncHelper(fileId, flags) {
const file = this.#mapIdToFile.get(fileId);
log(`xSync ${file.path} ${flags}`);
try {
if (this.#options.durability !== 'relaxed') {
return this.handleAsync(async () => {
await this.#idb.sync();
return VFS.SQLITE_OK;
});
}
return VFS.SQLITE_OK;
await this.#idb.sync();
} catch (e) {
console.error(e);
return VFS.SQLITE_IOERR;
}
return VFS.SQLITE_OK;
}

/**
Expand Down
Loading

0 comments on commit dc81eaa

Please sign in to comment.