From 2967e07c8b5e16018dbd68b3f78199e75e865bd3 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Thu, 18 Dec 2014 13:59:28 +0100 Subject: [PATCH] Change how DownloadProgressTracker waits for progress to avoid possible deadlocks. --- .../core/DownloadProgressTracker.java | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/core/DownloadProgressTracker.java b/core/src/main/java/org/bitcoinj/core/DownloadProgressTracker.java index 920dda0c..dea4e7ac 100644 --- a/core/src/main/java/org/bitcoinj/core/DownloadProgressTracker.java +++ b/core/src/main/java/org/bitcoinj/core/DownloadProgressTracker.java @@ -17,11 +17,13 @@ package org.bitcoinj.core; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Date; -import java.util.concurrent.Semaphore; +import java.util.concurrent.ExecutionException; /** *

An implementation of {@link AbstractPeerEventListener} that listens to chain download events and tracks progress @@ -32,12 +34,13 @@ public class DownloadProgressTracker extends AbstractPeerEventListener { private static final Logger log = LoggerFactory.getLogger(DownloadProgressTracker.class); private int originalBlocksLeft = -1; private int lastPercent = 0; - private Semaphore done = new Semaphore(0); + private SettableFuture future = SettableFuture.create(); private boolean caughtUp = false; @Override public void onChainDownloadStarted(Peer peer, int blocksLeft) { - startDownload(blocksLeft); + if (blocksLeft > 0 && originalBlocksLeft == -1) + startDownload(blocksLeft); // Only mark this the first time, because this method can be called more than once during a chain download // if we switch peers during it. if (originalBlocksLeft == -1) @@ -46,7 +49,7 @@ public class DownloadProgressTracker extends AbstractPeerEventListener { log.info("Chain download switched to {}", peer); if (blocksLeft == 0) { doneDownload(); - done.release(); + future.set(peer.getBestHeight()); } } @@ -58,7 +61,7 @@ public class DownloadProgressTracker extends AbstractPeerEventListener { if (blocksLeft == 0) { caughtUp = true; doneDownload(); - done.release(); + future.set(peer.getBestHeight()); } if (blocksLeft < 0 || originalBlocksLeft <= 0) @@ -88,10 +91,8 @@ public class DownloadProgressTracker extends AbstractPeerEventListener { * @param blocks the number of blocks to download, estimated */ protected void startDownload(int blocks) { - if (blocks > 0 && originalBlocksLeft == -1) - log.info("Downloading block chain of size " + blocks + ". " + - (blocks > 1000 ? "This may take a while." : "")); - + log.info("Downloading block chain of size " + blocks + ". " + + (blocks > 1000 ? "This may take a while." : "")); } /** @@ -104,6 +105,18 @@ public class DownloadProgressTracker extends AbstractPeerEventListener { * Wait for the chain to be downloaded. */ public void await() throws InterruptedException { - done.acquire(); + try { + future.get(); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } + } + + /** + * Returns a listenable future that completes with the height of the best chain (as reported by the peer) once chain + * download seems to be finished. + */ + public ListenableFuture getFuture() { + return future; } }