diff options
author | Florian Dold <florian@dold.me> | 2024-02-27 22:47:59 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2024-02-27 22:47:59 +0100 |
commit | 2c86a9ec76b60ad065da65e5d2adfd1a79189ae6 (patch) | |
tree | ed04791360812b9ed3df5c2f8bbc3938e7f2fd7a | |
parent | d3572014b06f60250e3bb9e99898b89cd11a4294 (diff) | |
download | wallet-core-2c86a9ec76b60ad065da65e5d2adfd1a79189ae6.tar.xz |
DB observability
-rw-r--r-- | packages/taler-wallet-core/src/db.ts | 7 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/observable-wrappers.ts | 81 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/query.ts | 24 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/shepherd.ts | 3 | ||||
-rw-r--r-- | packages/taler-wallet-core/src/wallet.ts | 3 |
5 files changed, 112 insertions, 6 deletions
diff --git a/packages/taler-wallet-core/src/db.ts b/packages/taler-wallet-core/src/db.ts index 3a593a523..9efc9fbe0 100644 --- a/packages/taler-wallet-core/src/db.ts +++ b/packages/taler-wallet-core/src/db.ts @@ -63,6 +63,7 @@ import { import { DbRetryInfo, TaskIdentifiers } from "./common.js"; import { DbAccess, + DbAccessImpl, DbReadOnlyTransaction, DbReadWriteTransaction, IndexDescriptor, @@ -3164,7 +3165,7 @@ export async function openStoredBackupsDatabase( onStoredBackupsDbUpgradeNeeded, ); - const handle = new DbAccess(backupsDbHandle, StoredBackupStores); + const handle = new DbAccessImpl(backupsDbHandle, StoredBackupStores); return handle; } @@ -3187,7 +3188,7 @@ export async function openTalerDatabase( onMetaDbUpgradeNeeded, ); - const metaDb = new DbAccess(metaDbHandle, walletMetadataStore); + const metaDb = new DbAccessImpl(metaDbHandle, walletMetadataStore); let currentMainVersion: string | undefined; await metaDb.runReadWriteTx(["metaConfig"], async (tx) => { const dbVersionRecord = await tx.metaConfig.get(CURRENT_DB_CONFIG_KEY); @@ -3236,7 +3237,7 @@ export async function openTalerDatabase( onTalerDbUpgradeNeeded, ); - const handle = new DbAccess(mainDbHandle, WalletStoresV1); + const handle = new DbAccessImpl(mainDbHandle, WalletStoresV1); await applyFixups(handle); diff --git a/packages/taler-wallet-core/src/observable-wrappers.ts b/packages/taler-wallet-core/src/observable-wrappers.ts index 77839e047..3df084268 100644 --- a/packages/taler-wallet-core/src/observable-wrappers.ts +++ b/packages/taler-wallet-core/src/observable-wrappers.ts @@ -21,6 +21,7 @@ /** * Imports. */ +import { IDBDatabase } from "@gnu-taler/idb-bridge"; import { ObservabilityContext, ObservabilityEventType, @@ -33,6 +34,12 @@ import { HttpResponse, } from "@gnu-taler/taler-util/http"; import { TaskIdStr } from "./common.js"; +import { + DbAccess, + DbReadOnlyTransaction, + DbReadWriteTransaction, + StoreNames, +} from "./query.js"; import { TaskScheduler } from "./shepherd.js"; /** @@ -129,3 +136,77 @@ export class ObservableHttpClientLibrary implements HttpRequestLibrary { } } } + +const locRegex = /\s*at\s*([a-zA-Z0-9_.!]*)\s*/; + +export function getCallerInfo(up: number = 2): string { + const stack = new Error().stack ?? ""; + const identifies: string[] = []; + for (const line of stack.split("\n")) { + let l = line.match(locRegex); + if (l) { + identifies.push(l[1]); + } + } + return identifies.slice(up, up + 2).join("/"); +} + +export class ObservableDbAccess<StoreMap> implements DbAccess<StoreMap> { + constructor( + private impl: DbAccess<StoreMap>, + private oc: ObservabilityContext, + ) {} + idbHandle(): IDBDatabase { + return this.impl.idbHandle(); + } + + runAllStoresReadWriteTx<T>( + txf: ( + tx: DbReadWriteTransaction<StoreMap, StoreNames<StoreMap>[]>, + ) => Promise<T>, + ): Promise<T> { + this.oc.observe({ + type: ObservabilityEventType.DbQueryStart, + name: "<unknown>", + location: getCallerInfo(), + }); + return this.impl.runAllStoresReadWriteTx(txf); + } + + runAllStoresReadOnlyTx<T>( + txf: ( + tx: DbReadOnlyTransaction<StoreMap, StoreNames<StoreMap>[]>, + ) => Promise<T>, + ): Promise<T> { + this.oc.observe({ + type: ObservabilityEventType.DbQueryStart, + name: "<unknown>", + location: getCallerInfo(), + }); + return this.impl.runAllStoresReadOnlyTx(txf); + } + + runReadWriteTx<T, StoreNameArray extends StoreNames<StoreMap>[]>( + storeNames: StoreNameArray, + txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>, + ): Promise<T> { + this.oc.observe({ + type: ObservabilityEventType.DbQueryStart, + name: "<unknown>", + location: getCallerInfo(), + }); + return this.impl.runReadWriteTx(storeNames, txf); + } + + runReadOnlyTx<T, StoreNameArray extends StoreNames<StoreMap>[]>( + storeNames: StoreNameArray, + txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>, + ): Promise<T> { + this.oc.observe({ + type: ObservabilityEventType.DbQueryStart, + name: "<unknown>", + location: getCallerInfo(), + }); + return this.impl.runReadOnlyTx(storeNames, txf); + } +} diff --git a/packages/taler-wallet-core/src/query.ts b/packages/taler-wallet-core/src/query.ts index 4c169946c..994a6a96d 100644 --- a/packages/taler-wallet-core/src/query.ts +++ b/packages/taler-wallet-core/src/query.ts @@ -742,12 +742,34 @@ function makeWriteContext( return ctx; } +export interface DbAccess<StoreMap> { + idbHandle(): IDBDatabase; + runAllStoresReadWriteTx<T>( + txf: ( + tx: DbReadWriteTransaction<StoreMap, Array<StoreNames<StoreMap>>>, + ) => Promise<T>, + ): Promise<T>; + runAllStoresReadOnlyTx<T>( + txf: ( + tx: DbReadOnlyTransaction<StoreMap, Array<StoreNames<StoreMap>>>, + ) => Promise<T>, + ): Promise<T>; + runReadWriteTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>( + storeNames: StoreNameArray, + txf: (tx: DbReadWriteTransaction<StoreMap, StoreNameArray>) => Promise<T>, + ): Promise<T>; + runReadOnlyTx<T, StoreNameArray extends Array<StoreNames<StoreMap>>>( + storeNames: StoreNameArray, + txf: (tx: DbReadOnlyTransaction<StoreMap, StoreNameArray>) => Promise<T>, + ): Promise<T>; +} + /** * Type-safe access to a database with a particular store map. * * A store map is the metadata that describes the store. */ -export class DbAccess<StoreMap> { +export class DbAccessImpl<StoreMap> implements DbAccess<StoreMap> { constructor( private db: IDBDatabase, private stores: StoreMap, diff --git a/packages/taler-wallet-core/src/shepherd.ts b/packages/taler-wallet-core/src/shepherd.ts index 1c23ab6b5..66c39ee48 100644 --- a/packages/taler-wallet-core/src/shepherd.ts +++ b/packages/taler-wallet-core/src/shepherd.ts @@ -64,6 +64,7 @@ import { } from "./deposits.js"; import { updateExchangeFromUrlHandler } from "./exchanges.js"; import { + ObservableDbAccess, ObservableHttpClientLibrary, ObservableTaskScheduler, } from "./observable-wrappers.js"; @@ -593,7 +594,7 @@ async function callOperationHandlerForTaskId( ws, cancellationToken, cryptoApi: ws.cryptoApi, - db: ws.db, + db: new ObservableDbAccess(ws.db, oc), http: new ObservableHttpClientLibrary(ws.http, oc), taskScheduler: new ObservableTaskScheduler(ws.taskScheduler, oc), oc, diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 9185ee48c..c3aa68303 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -201,6 +201,7 @@ import { getMaxPeerPushAmount, } from "./instructedAmountConversion.js"; import { + ObservableDbAccess, ObservableHttpClientLibrary, ObservableTaskScheduler, } from "./observable-wrappers.js"; @@ -1388,7 +1389,7 @@ async function handleCoreApiRequest( ws, cancellationToken: CancellationToken.CONTINUE, cryptoApi: ws.cryptoApi, - db: ws.db, + db: new ObservableDbAccess(ws.db, oc), http: new ObservableHttpClientLibrary(ws.http, oc), taskScheduler: new ObservableTaskScheduler(ws.taskScheduler, oc), oc, |