From 3a405302bb3a7e1df1f2f58ff13af21fadedfe86 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Tue, 14 Jan 2014 19:06:06 +0100 Subject: [PATCH] More memory optimisations. Run the wallet txConfidenceListener on the calling thread. Move tx broadcast that occurs inside setTransactionBroadcaster outside the wallet lock to avoid inverting on the mempool class (via PeerGroup, but that doesn't lock on the broadcast path). This makes memory usage smoother by avoiding the creation of tons of closures and spamming the event thread with them. --- .../java/com/google/bitcoin/core/Wallet.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index 632e537b..083173fa 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -1341,7 +1341,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi } // This is safe even if the listener has been added before, as TransactionConfidence ignores duplicate // registration requests. That makes the code in the wallet simpler. - tx.getConfidence().addEventListener(txConfidenceListener); + tx.getConfidence().addEventListener(txConfidenceListener, Threading.SAME_THREAD); } /** @@ -3550,6 +3550,7 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi * optimise itself to reduce fees or improve privacy.

*/ public void setTransactionBroadcaster(@Nullable com.google.bitcoin.core.TransactionBroadcaster broadcaster) { + Transaction[] toBroadcast = {}; lock.lock(); try { if (vTransactionBroadcaster == broadcaster) @@ -3557,19 +3558,22 @@ public class Wallet implements Serializable, BlockChainListener, PeerFilterProvi vTransactionBroadcaster = broadcaster; if (broadcaster == null) return; - // Now use it to upload any pending transactions we have that are marked as not being seen by any peers yet. - for (Transaction tx : pending.values()) { - checkState(tx.getConfidence().getConfidenceType() == ConfidenceType.PENDING); - // Re-broadcast even if it's marked as already seen for two reasons - // 1) Old wallets may have transactions marked as broadcast by 1 peer when in reality the network - // never saw it, due to bugs. - // 2) It can't really hurt. - log.info("New broadcaster so uploading waiting tx {}", tx.getHash()); - broadcaster.broadcastTransaction(tx); - } + toBroadcast = pending.values().toArray(toBroadcast); } finally { lock.unlock(); } + // Now use it to upload any pending transactions we have that are marked as not being seen by any peers yet. + // Don't hold the wallet lock whilst doing this, so if the broadcaster accesses the wallet at some point there + // is no inversion. + for (Transaction tx : toBroadcast) { + checkState(tx.getConfidence().getConfidenceType() == ConfidenceType.PENDING); + // Re-broadcast even if it's marked as already seen for two reasons + // 1) Old wallets may have transactions marked as broadcast by 1 peer when in reality the network + // never saw it, due to bugs. + // 2) It can't really hurt. + log.info("New broadcaster so uploading waiting tx {}", tx.getHash()); + broadcaster.broadcastTransaction(tx); + } } /**