Change how DownloadProgressTracker waits for progress to avoid possible deadlocks.

This commit is contained in:
Mike Hearn 2014-12-18 13:59:28 +01:00
parent b25899de58
commit 2967e07c8b

View File

@ -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;
/**
* <p>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<Long> 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<Long> getFuture() {
return future;
}
}