aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-05-11 21:47:35 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-05-11 21:47:35 +0530
commit857a2b9dcaf64d4298027644f8e6716fa22db941 (patch)
treedc711c998d153a5f3169e71c851adbf5d7ad12ec
parent277a513a8f9c46392446514e7a37e77e4f4b5327 (diff)
perf: reserve history in separate object store
-rw-r--r--src/db.ts2
-rw-r--r--src/operations/balance.ts6
-rw-r--r--src/operations/history.ts7
-rw-r--r--src/operations/reserves.ts64
-rw-r--r--src/operations/withdraw.ts2
-rw-r--r--src/types/dbTypes.ts14
-rw-r--r--src/webex/pages/popup.tsx7
7 files changed, 83 insertions, 19 deletions
diff --git a/src/db.ts b/src/db.ts
index efc3b78ad..098767b55 100644
--- a/src/db.ts
+++ b/src/db.ts
@@ -7,7 +7,7 @@ import { openDatabase, Database, Store, Index } from "./util/query";
* with each major change. When incrementing the major version,
* the wallet should import data from the previous version.
*/
-const TALER_DB_NAME = "taler-walletdb-v2";
+const TALER_DB_NAME = "taler-walletdb-v3";
/**
* Current database minor version, should be incremented
diff --git a/src/operations/balance.ts b/src/operations/balance.ts
index b5c1ec79e..6f9135028 100644
--- a/src/operations/balance.ts
+++ b/src/operations/balance.ts
@@ -145,7 +145,7 @@ export async function getBalances(
): Promise<WalletBalance> {
logger.trace("starting to compute balance");
- return await ws.db.runWithReadTransaction(
+ const wbal = await ws.db.runWithReadTransaction(
[
Stores.coins,
Stores.refreshGroups,
@@ -157,4 +157,8 @@ export async function getBalances(
return getBalancesInsideTransaction(ws, tx);
},
);
+
+ logger.trace("finished computing wallet balance");
+
+ return wbal;
}
diff --git a/src/operations/history.ts b/src/operations/history.ts
index 669a6cf85..1271c56ef 100644
--- a/src/operations/history.ts
+++ b/src/operations/history.ts
@@ -172,6 +172,7 @@ export async function getHistory(
Stores.purchases,
Stores.refreshGroups,
Stores.reserves,
+ Stores.reserveHistory,
Stores.tips,
Stores.withdrawalGroups,
Stores.payEvents,
@@ -384,8 +385,12 @@ export async function getHistory(
type: ReserveType.Manual,
};
}
+ const hist = await tx.get(Stores.reserveHistory, reserve.reservePub);
+ if (!hist) {
+ throw Error("inconsistent database");
+ }
const s = summarizeReserveHistory(
- reserve.reserveTransactions,
+ hist.reserveTransactions,
reserve.currency,
);
history.push({
diff --git a/src/operations/reserves.ts b/src/operations/reserves.ts
index a3c6d56a4..2bbb085d5 100644
--- a/src/operations/reserves.ts
+++ b/src/operations/reserves.ts
@@ -33,8 +33,8 @@ import {
updateRetryInfoTimeout,
ReserveUpdatedEventRecord,
WalletReserveHistoryItemType,
- PlanchetRecord,
WithdrawalSourceType,
+ ReserveHistoryRecord,
} from "../types/dbTypes";
import { Logger } from "../util/logging";
import { Amounts } from "../util/amounts";
@@ -114,11 +114,15 @@ export async function createReserve(
lastSuccessfulStatusQuery: undefined,
retryInfo: initRetryInfo(),
lastError: undefined,
- reserveTransactions: [],
currency: req.amount.currency,
};
- reserveRecord.reserveTransactions.push({
+ const reserveHistoryRecord: ReserveHistoryRecord = {
+ reservePub: keypair.pub,
+ reserveTransactions: [],
+ };
+
+ reserveHistoryRecord.reserveTransactions.push({
type: WalletReserveHistoryItemType.Credit,
expectedAmount: req.amount,
});
@@ -161,7 +165,12 @@ export async function createReserve(
const cr: CurrencyRecord = currencyRecord;
const resp = await ws.db.runWithWriteTransaction(
- [Stores.currencies, Stores.reserves, Stores.bankWithdrawUris],
+ [
+ Stores.currencies,
+ Stores.reserves,
+ Stores.reserveHistory,
+ Stores.bankWithdrawUris,
+ ],
async (tx) => {
// Check if we have already created a reserve for that bankWithdrawStatusUrl
if (reserveRecord.bankWithdrawStatusUrl) {
@@ -188,6 +197,7 @@ export async function createReserve(
}
await tx.put(Stores.currencies, cr);
await tx.put(Stores.reserves, reserveRecord);
+ await tx.put(Stores.reserveHistory, reserveHistoryRecord);
const r: CreateReserveResponse = {
exchange: canonExchange,
reservePub: keypair.pub,
@@ -462,7 +472,7 @@ async function updateReserve(
const balance = Amounts.parseOrThrow(reserveInfo.balance);
const currency = balance.currency;
await ws.db.runWithWriteTransaction(
- [Stores.reserves, Stores.reserveUpdatedEvents],
+ [Stores.reserves, Stores.reserveUpdatedEvents, Stores.reserveHistory],
async (tx) => {
const r = await tx.get(Stores.reserves, reservePub);
if (!r) {
@@ -472,14 +482,19 @@ async function updateReserve(
return;
}
+ const hist = await tx.get(Stores.reserveHistory, reservePub);
+ if (!hist) {
+ throw Error("inconsistent database");
+ }
+
const newHistoryTransactions = reserveInfo.history.slice(
- r.reserveTransactions.length,
+ hist.reserveTransactions.length,
);
const reserveUpdateId = encodeCrock(getRandomBytes(32));
const reconciled = reconcileReserveHistory(
- r.reserveTransactions,
+ hist.reserveTransactions,
reserveInfo.history,
);
@@ -514,9 +529,10 @@ async function updateReserve(
r.retryInfo = initRetryInfo(false);
}
r.lastSuccessfulStatusQuery = getTimestampNow();
- r.reserveTransactions = reconciled.updatedLocalHistory;
+ hist.reserveTransactions = reconciled.updatedLocalHistory;
r.lastError = undefined;
await tx.put(Stores.reserves, r);
+ await tx.put(Stores.reserveHistory, hist);
},
);
ws.notify({ type: NotificationType.ReserveUpdated });
@@ -602,17 +618,29 @@ async function depleteReserve(
ws: InternalWalletState,
reservePub: string,
): Promise<void> {
- const reserve = await ws.db.get(Stores.reserves, reservePub);
+ let reserve: ReserveRecord | undefined;
+ let hist: ReserveHistoryRecord | undefined;
+ await ws.db.runWithReadTransaction(
+ [Stores.reserves, Stores.reserveHistory],
+ async (tx) => {
+ reserve = await tx.get(Stores.reserves, reservePub);
+ hist = await tx.get(Stores.reserveHistory, reservePub);
+ },
+ );
+
if (!reserve) {
return;
}
+ if (!hist) {
+ throw Error("inconsistent database");
+ }
if (reserve.reserveStatus !== ReserveRecordStatus.WITHDRAWING) {
return;
}
logger.trace(`depleting reserve ${reservePub}`);
const summary = summarizeReserveHistory(
- reserve.reserveTransactions,
+ hist.reserveTransactions,
reserve.currency,
);
@@ -674,7 +702,12 @@ async function depleteReserve(
};
const success = await ws.db.runWithWriteTransaction(
- [Stores.withdrawalGroups, Stores.reserves, Stores.planchets],
+ [
+ Stores.withdrawalGroups,
+ Stores.reserves,
+ Stores.reserveHistory,
+ Stores.planchets,
+ ],
async (tx) => {
const newReserve = await tx.get(Stores.reserves, reservePub);
if (!newReserve) {
@@ -683,8 +716,12 @@ async function depleteReserve(
if (newReserve.reserveStatus !== ReserveRecordStatus.WITHDRAWING) {
return false;
}
+ const newHist = await tx.get(Stores.reserveHistory, reservePub);
+ if (!newHist) {
+ throw Error("inconsistent database");
+ }
const newSummary = summarizeReserveHistory(
- newReserve.reserveTransactions,
+ newHist.reserveTransactions,
newReserve.currency,
);
if (
@@ -703,7 +740,7 @@ async function depleteReserve(
const sd = denomsForWithdraw.selectedDenoms[i];
for (let j = 0; j < sd.count; j++) {
const amt = Amounts.add(sd.denom.value, sd.denom.feeWithdraw).amount;
- newReserve.reserveTransactions.push({
+ newHist.reserveTransactions.push({
type: WalletReserveHistoryItemType.Withdraw,
expectedAmount: amt,
});
@@ -712,6 +749,7 @@ async function depleteReserve(
newReserve.reserveStatus = ReserveRecordStatus.DORMANT;
newReserve.retryInfo = initRetryInfo(false);
await tx.put(Stores.reserves, newReserve);
+ await tx.put(Stores.reserveHistory, newHist);
await tx.put(Stores.withdrawalGroups, withdrawalRecord);
return true;
},
diff --git a/src/operations/withdraw.ts b/src/operations/withdraw.ts
index 36b9f1c0f..e1c4ed57c 100644
--- a/src/operations/withdraw.ts
+++ b/src/operations/withdraw.ts
@@ -564,7 +564,7 @@ async function processWithdrawGroupImpl(
// Withdraw coins in batches.
// The batch size is relatively large
- await processInBatches(genWork(), 50);
+ await processInBatches(genWork(), 10);
}
export async function getExchangeWithdrawalInfo(
diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts
index 26fcca9e8..4cf19a56e 100644
--- a/src/types/dbTypes.ts
+++ b/src/types/dbTypes.ts
@@ -210,6 +210,11 @@ export type WalletReserveHistoryItem =
| WalletReserveHistoryRecoupItem
| WalletReserveHistoryClosingItem;
+export interface ReserveHistoryRecord {
+ reservePub: string;
+ reserveTransactions: WalletReserveHistoryItem[];
+}
+
/**
* A reserve record as stored in the wallet's database.
*/
@@ -295,8 +300,6 @@ export interface ReserveRecord {
* (either talking to the bank or the exchange).
*/
lastError: OperationError | undefined;
-
- reserveTransactions: WalletReserveHistoryItem[];
}
/**
@@ -1639,6 +1642,12 @@ export namespace Stores {
}
}
+ class ReserveHistoryStore extends Store<ReserveHistoryRecord> {
+ constructor() {
+ super("reserveHistory", { keyPath: "reservePub" });
+ }
+ }
+
class TipsStore extends Store<TipRecord> {
constructor() {
super("tips", { keyPath: "tipId" });
@@ -1725,6 +1734,7 @@ export namespace Stores {
keyPath: "recoupGroupId",
});
export const reserves = new ReservesStore();
+ export const reserveHistory = new ReserveHistoryStore();
export const purchases = new PurchasesStore();
export const tips = new TipsStore();
export const senderWires = new SenderWiresStore();
diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx
index 450aae4ce..4d3c65b26 100644
--- a/src/webex/pages/popup.tsx
+++ b/src/webex/pages/popup.tsx
@@ -177,6 +177,7 @@ class WalletBalanceView extends React.Component<any, any> {
private gotError = false;
private canceler: (() => void) | undefined = undefined;
private unmount = false;
+ private updateBalanceRunning = false;
componentWillMount(): void {
this.canceler = wxApi.onUpdateNotification(() => this.updateBalance());
@@ -192,6 +193,10 @@ class WalletBalanceView extends React.Component<any, any> {
}
async updateBalance(): Promise<void> {
+ if (this.updateBalanceRunning) {
+ return;
+ }
+ this.updateBalanceRunning = true;
let balance: WalletBalance;
try {
balance = await wxApi.getBalance();
@@ -203,6 +208,8 @@ class WalletBalanceView extends React.Component<any, any> {
console.error("could not retrieve balances", e);
this.setState({});
return;
+ } finally {
+ this.updateBalanceRunning = false;
}
if (this.unmount) {
return;