Skip to content

Commit 8a91464

Browse files
committed
regularly save wallets after minimum interval of 5 mins
1 parent fee4bd0 commit 8a91464

File tree

3 files changed

+45
-32
lines changed

3 files changed

+45
-32
lines changed

core/src/main/java/haveno/core/trade/Trade.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,14 +1000,20 @@ public void changeWalletPassword(String oldPassword, String newPassword) {
10001000
}
10011001

10021002
@Override
1003-
public void requestSaveWallet() {
1003+
public void requestSaveWalletIfAfterInterval() {
1004+
ThreadUtils.submitToPool(() -> {
1005+
synchronized (walletLock) {
1006+
if (walletExists()) saveWalletIfAfterInterval();
1007+
}
1008+
});
1009+
}
10041010

1005-
// save wallet off main thread
1006-
ThreadUtils.execute(() -> {
1011+
private void requestSaveWallet() {
1012+
ThreadUtils.submitToPool(() -> {
10071013
synchronized (walletLock) {
10081014
if (walletExists()) saveWallet();
10091015
}
1010-
}, getId());
1016+
});
10111017
}
10121018

10131019
@Override
@@ -1019,6 +1025,7 @@ public void saveWallet() {
10191025
}
10201026
if (wallet == null) throw new RuntimeException("Trade wallet is not open for trade " + getShortId());
10211027
xmrWalletService.saveWallet(wallet);
1028+
lastSaveTimeMs = System.currentTimeMillis();
10221029
maybeBackupWallet();
10231030
}
10241031
}
@@ -1447,8 +1454,8 @@ public void processPayoutTx(String payoutTxHex, boolean sign, boolean publish) {
14471454
if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e;
14481455
HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying
14491456
} finally {
1450-
requestSaveWallet();
1451-
requestPersistence();
1457+
saveWallet();
1458+
persistNow(null);
14521459
}
14531460
}
14541461
}
@@ -2965,7 +2972,7 @@ private void doPollWallet(boolean offlinePoll) {
29652972
}
29662973
}
29672974
wasWalletPolled.set(true);
2968-
saveWalletWithDelay();
2975+
requestSaveWalletIfAfterInterval();
29692976
}
29702977
}
29712978

@@ -3344,7 +3351,7 @@ public void rescanSpent(boolean skipLog) {
33443351
if (!skipLog) log.info("Rescanning spent outputs for {} {}", getClass().getSimpleName(), getShortId());
33453352
wallet.rescanSpent();
33463353
if (!skipLog) log.info("Done rescanning spent outputs for {} {}", getClass().getSimpleName(), getShortId());
3347-
saveWalletWithDelay();
3354+
saveWalletIfAfterInterval();
33483355
} catch (Exception e) {
33493356
log.warn("Error rescanning spent outputs for {} {}, errorMessage={}", getClass().getSimpleName(), getShortId(), e.getMessage());
33503357
if (HavenoUtils.isUnresponsive(e)) forceRestartTradeWallet(); // wallet can be stuck a while

core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.util.concurrent.TimeUnit;
1313
import java.util.concurrent.TimeoutException;
1414

15+
import haveno.common.ThreadUtils;
1516
import haveno.common.Timer;
1617
import haveno.common.UserThread;
1718
import haveno.core.api.XmrConnectionService;
@@ -35,8 +36,10 @@ public abstract class XmrWalletBase {
3536
// constants
3637
public static final int SYNC_TIMEOUT_SECONDS = 180;
3738
public static final int DIRECT_SYNC_WITHIN_BLOCKS = 100;
38-
public static final int SAVE_WALLET_DELAY_SECONDS = 300;
3939
private static final String SYNC_PROGRESS_TIMEOUT_MSG = "Sync progress timeout called";
40+
private static final long MIN_SAVE_INTERVAL_MS = 300000;
41+
protected long lastSaveTimeMs = 0;
42+
private Object saveIntervalLock = new Object();
4043

4144
// inherited
4245
protected MoneroWallet wallet;
@@ -81,6 +84,7 @@ public MoneroSyncResult syncWithTimeout(long timeout) {
8184

8285
Callable<MoneroSyncResult> task = () -> {
8386
MoneroSyncResult result = wallet.sync();
87+
saveWalletIfAfterInterval();
8488
walletHeight.set(wallet.getHeight());
8589
return result;
8690
};
@@ -191,7 +195,7 @@ public void onSyncProgress(long height, long startHeight, long endHeight, double
191195
if (wallet != null) { // can become null if interrupted by force close
192196
if (syncProgressError == null || !HavenoUtils.isUnresponsive(syncProgressError)) { // TODO: skipping stop sync if unresponsive because wallet will hang. if unresponsive, wallet is assumed to be force restarted by caller, but that should be done internally here instead of externally?
193197
wallet.stopSyncing();
194-
saveWallet();
198+
saveWalletIfAfterInterval();
195199
}
196200
}
197201
if (syncProgressError != null) throw new RuntimeException(syncProgressError);
@@ -211,25 +215,26 @@ public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConne
211215
return false;
212216
}
213217

214-
public void saveWalletWithDelay() {
215-
// delay writing to disk to avoid frequent write operations
216-
if (saveWalletDelayTimer == null) {
217-
saveWalletDelayTimer = UserThread.runAfter(() -> {
218-
requestSaveWallet();
219-
UserThread.execute(() -> saveWalletDelayTimer = null);
220-
}, SAVE_WALLET_DELAY_SECONDS, TimeUnit.SECONDS);
218+
public void saveWalletIfAfterInterval() {
219+
synchronized (saveIntervalLock) {
220+
if (System.currentTimeMillis() - lastSaveTimeMs >= MIN_SAVE_INTERVAL_MS) {
221+
saveWallet();
222+
lastSaveTimeMs = System.currentTimeMillis();
223+
}
221224
}
222225
}
223226

224-
// --------------------------------- ABSTRACT -----------------------------
227+
public void requestSaveWalletIfAfterInterval() {
228+
ThreadUtils.submitToPool(() -> saveWalletIfAfterInterval());
229+
}
225230

226231
public static boolean isSyncWithProgressTimeout(Throwable e) {
227232
return e.getMessage().contains(SYNC_PROGRESS_TIMEOUT_MSG);
228233
}
229234

230-
public abstract void saveWallet();
235+
// --------------------------------- ABSTRACT -----------------------------
231236

232-
public abstract void requestSaveWallet();
237+
public abstract void saveWallet();
233238

234239
protected abstract void onConnectionChanged(MoneroRpcConnection connection);
235240

@@ -242,6 +247,9 @@ private void updateSyncProgress(long height, long targetHeight) {
242247
resetSyncProgressTimeout();
243248
}
244249

250+
// save wallet periodically
251+
saveWalletIfAfterInterval();
252+
245253
// set wallet height
246254
walletHeight.set(height);
247255

core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,10 @@ public long getWalletCreationDate() {
239239

240240
@Override
241241
public void saveWallet() {
242-
saveWallet(shouldBackup(wallet));
242+
synchronized (walletLock) {
243+
saveWallet(shouldBackup(wallet));
244+
lastSaveTimeMs = System.currentTimeMillis();
245+
}
243246
}
244247

245248
private boolean shouldBackup(MoneroWallet wallet) {
@@ -252,11 +255,6 @@ public void saveWallet(boolean backup) {
252255
}
253256
}
254257

255-
@Override
256-
public void requestSaveWallet() {
257-
ThreadUtils.submitToPool(() -> saveWallet()); // save wallet off main thread
258-
}
259-
260258
public boolean isWalletAvailable() {
261259
try {
262260
return getWallet() != null;
@@ -432,7 +430,7 @@ public MoneroTxWallet createTx(MoneroTxConfig txConfig) {
432430
if (Boolean.TRUE.equals(txConfig.getRelay())) {
433431
cachedTxs.addFirst(tx);
434432
cacheWalletInfo();
435-
requestSaveWallet();
433+
saveWallet();
436434
}
437435
return tx;
438436
}
@@ -450,7 +448,7 @@ public List<MoneroTxWallet> createSweepTxs(MoneroTxConfig txConfig) {
450448
if (Boolean.TRUE.equals(txConfig.getRelay())) {
451449
for (MoneroTxWallet tx : txs) cachedTxs.addFirst(tx);
452450
cacheWalletInfo();
453-
requestSaveWallet();
451+
saveWallet();
454452
}
455453
return txs;
456454
}
@@ -460,7 +458,7 @@ public List<MoneroTxWallet> createSweepTxs(MoneroTxConfig txConfig) {
460458
public List<String> relayTxs(List<String> metadatas) {
461459
synchronized (walletLock) {
462460
List<String> txIds = wallet.relayTxs(metadatas);
463-
requestSaveWallet();
461+
saveWallet();
464462
return txIds;
465463
}
466464
}
@@ -554,7 +552,7 @@ public void freezeOutputs(Collection<String> keyImages) {
554552
for (String keyImage : unfrozenKeyImages) wallet.freezeOutput(keyImage);
555553
cacheNonPoolTxs();
556554
cacheWalletInfo();
557-
requestSaveWallet();
555+
saveWallet();
558556
}
559557
}
560558

@@ -577,7 +575,7 @@ public void thawOutputs(Collection<String> keyImages) {
577575
for (String keyImage : frozenKeyImages) wallet.thawOutput(keyImage);
578576
cacheNonPoolTxs();
579577
cacheWalletInfo();
580-
requestSaveWallet();
578+
saveWallet();
581579
}
582580
}
583581

@@ -2075,7 +2073,7 @@ else if (isWalletConnectedToDaemon()) {
20752073
pollInProgress = false;
20762074
}
20772075
}
2078-
saveWalletWithDelay();
2076+
saveWalletIfAfterInterval();
20792077

20802078
// cache wallet info last
20812079
synchronized (walletLock) {

0 commit comments

Comments
 (0)