diff options
Diffstat (limited to 'packages/idb-bridge')
-rw-r--r-- | packages/idb-bridge/package.json | 4 | ||||
-rw-r--r-- | packages/idb-bridge/src/SqliteBackend.ts | 5 | ||||
-rw-r--r-- | packages/idb-bridge/src/bench.ts | 110 | ||||
-rw-r--r-- | packages/idb-bridge/src/bridge-idb.ts | 13 | ||||
-rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/event-dispatch-active-flag.test.ts | 8 | ||||
-rw-r--r-- | packages/idb-bridge/src/testingdb.ts | 2 |
6 files changed, 133 insertions, 9 deletions
diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json index 54d53e94a..376265c0f 100644 --- a/packages/idb-bridge/package.json +++ b/packages/idb-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@gnu-taler/idb-bridge", - "version": "0.0.16", + "version": "0.10.7", "description": "IndexedDB implementation that uses SQLite3 as storage", "main": "./dist/idb-bridge.js", "module": "./lib/index.js", @@ -38,6 +38,6 @@ "failFast": true }, "optionalDependencies": { - "better-sqlite3": "^9.2.2" + "better-sqlite3": "9.4.0" } } diff --git a/packages/idb-bridge/src/SqliteBackend.ts b/packages/idb-bridge/src/SqliteBackend.ts index a25ec0045..26ed43b0f 100644 --- a/packages/idb-bridge/src/SqliteBackend.ts +++ b/packages/idb-bridge/src/SqliteBackend.ts @@ -992,6 +992,11 @@ export class SqliteBackend implements Backend { object_store_id: objectStoreId, name: indexName, }); + if (!idxInfo) { + throw Error( + `index ${indexName} on object store ${objectStoreName} not found`, + ); + } const indexUnique = expectDbNumber(idxInfo, "unique_index"); const indexMultiEntry = expectDbNumber(idxInfo, "multientry"); const indexKeyPath = deserializeKeyPath( diff --git a/packages/idb-bridge/src/bench.ts b/packages/idb-bridge/src/bench.ts new file mode 100644 index 000000000..d196bacb1 --- /dev/null +++ b/packages/idb-bridge/src/bench.ts @@ -0,0 +1,110 @@ +/* + Copyright 2024 Taler Systems S.A. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the License for the specific language governing + permissions and limitations under the License. + */ + +import * as fs from "node:fs"; +import { + BridgeIDBDatabase, + BridgeIDBFactory, + BridgeIDBRequest, + BridgeIDBTransaction, + createSqliteBackend, +} from "./index.js"; +import { createNodeSqlite3Impl } from "./node-sqlite3-impl.js"; + +function openDb(idbFactory: BridgeIDBFactory): Promise<BridgeIDBDatabase> { + return new Promise((resolve, reject) => { + const openReq = idbFactory.open("mydb", 1); + openReq.addEventListener("success", () => { + const database = openReq.result; + resolve(database); + }); + openReq.addEventListener("upgradeneeded", (event: any) => { + const database: BridgeIDBDatabase = event.target.result; + const transaction: BridgeIDBTransaction = event.target.transaction; + database.createObjectStore("books", { + keyPath: "isbn", + }); + }); + }); +} + +function requestToPromise(req: BridgeIDBRequest): Promise<any> { + //const stack = Error("Failed request was started here."); + return new Promise((resolve, reject) => { + req.onsuccess = () => { + resolve(req.result); + }; + req.onerror = () => { + console.error("error in DB request", req.error); + reject(req.error); + //console.error("Request failed:", stack); + }; + }); +} + +function transactionToPromise(tx: BridgeIDBTransaction): Promise<void> { + //const stack = Error("Failed request was started here."); + return new Promise((resolve, reject) => { + tx.addEventListener("complete", () => { + resolve(); + }); + tx.onerror = () => { + console.error("error in DB txn", tx.error); + reject(tx.error); + //console.error("Request failed:", stack); + }; + }); +} + +const nTx = Number(process.argv[2]); +const nInsert = Number(process.argv[3]); + +async function main() { + const filename = "mytestdb.sqlite3"; + try { + fs.unlinkSync(filename); + } catch (e) { + // Do nothing. + } + + console.log(`doing ${nTx} iterations of ${nInsert} items`); + + const sqlite3Impl = await createNodeSqlite3Impl(); + const backend = await createSqliteBackend(sqlite3Impl, { + filename, + }); + backend.enableTracing = false; + const idbFactory = new BridgeIDBFactory(backend); + const db = await openDb(idbFactory); + + for (let i = 0; i < nTx; i++) { + const tx = db.transaction(["books"], "readwrite"); + const txProm = transactionToPromise(tx); + const books = tx.objectStore("books"); + for (let j = 0; j < nInsert; j++) { + const addReq = books.add({ + isbn: `${i}-${j}`, + name: `book-${i}-${j}`, + }); + await requestToPromise(addReq); + } + await txProm; + } + + console.log("done"); +} + +main(); diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts index f3749c77c..afb3f4224 100644 --- a/packages/idb-bridge/src/bridge-idb.ts +++ b/packages/idb-bridge/src/bridge-idb.ts @@ -997,7 +997,7 @@ export class BridgeIDBFactory { await transaction._waitDone(); - // We re-use the same transaction (as per spec) here. + // We reuse the same transaction (as per spec) here. transaction._active = true; if (db._closed || db._closePending) { @@ -2471,6 +2471,8 @@ export class BridgeIDBTransaction return this._committed || this._aborted; } + _counter = 0; + _openRequest: BridgeIDBOpenDBRequest | null = null; _backendTransaction?: DatabaseTransaction; @@ -2745,7 +2747,14 @@ export class BridgeIDBTransaction // with error handling already built into operation await operation(); } else { - await waitMacroQueue(); + this._counter++; + if (this._counter > 100) { + this._counter = 0; + // Give a chance for macro tasks to do something + // If we don't do this at all, we break WPT tests. + // If we always wait, performance is bad. + await waitMacroQueue(); + } let event; try { diff --git a/packages/idb-bridge/src/idb-wpt-ported/event-dispatch-active-flag.test.ts b/packages/idb-bridge/src/idb-wpt-ported/event-dispatch-active-flag.test.ts index e57b48f76..1d895c712 100644 --- a/packages/idb-bridge/src/idb-wpt-ported/event-dispatch-active-flag.test.ts +++ b/packages/idb-bridge/src/idb-wpt-ported/event-dispatch-active-flag.test.ts @@ -9,7 +9,7 @@ import { test.before("test DB initialization", initTestIndexedDB); -test("WPT test abort-in-initial-upgradeneeded.htm (subtest 1)", async (t) => { +test("WPT test event-dispatch-active-flag.html (subtest 1)", async (t) => { // Transactions are active during success handlers await indexeddb_test( t, @@ -57,7 +57,7 @@ test("WPT test abort-in-initial-upgradeneeded.htm (subtest 1)", async (t) => { ); }); -test("WPT test abort-in-initial-upgradeneeded.htm (subtest 2)", async (t) => { +test("WPT test event-dispatch-active-flag.html (subtest 2)", async (t) => { // Transactions are active during success listeners await indexeddb_test( t, @@ -103,7 +103,7 @@ test("WPT test abort-in-initial-upgradeneeded.htm (subtest 2)", async (t) => { ); }); -test("WPT test abort-in-initial-upgradeneeded.htm (subtest 3)", async (t) => { +test("WPT test event-dispatch-active-flag.html (subtest 3)", async (t) => { // Transactions are active during error handlers await indexeddb_test( t, @@ -152,7 +152,7 @@ test("WPT test abort-in-initial-upgradeneeded.htm (subtest 3)", async (t) => { ); }); -test("WPT test abort-in-initial-upgradeneeded.htm (subtest 4)", async (t) => { +test("WPT test event-dispatch-active-flag.html (subtest 4)", async (t) => { // Transactions are active during error listeners await indexeddb_test( t, diff --git a/packages/idb-bridge/src/testingdb.ts b/packages/idb-bridge/src/testingdb.ts index c6abffa0f..6c13979ca 100644 --- a/packages/idb-bridge/src/testingdb.ts +++ b/packages/idb-bridge/src/testingdb.ts @@ -31,7 +31,7 @@ export async function initTestIndexedDB(): Promise<void> { }); idbFactory = new BridgeIDBFactory(backend); - backend.enableTracing = true; + backend.enableTracing = false; BridgeIDBFactory.enableTracing = false; } |