-
Notifications
You must be signed in to change notification settings - Fork 130
Separate download state tracking from WorldStateDownloader #967
Conversation
…iled requests from a stalled download don't wind up being added to the queue for a later attempt.
…old versions of DownloadState fields.
…n via the future.
|
||
public abstract class NodeDataRequest { | ||
private static final Logger LOG = LogManager.getLogger(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see LOG used, can this file be taken out of the PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep good spot.
}); | ||
} | ||
|
||
private synchronized void doCancel(final Void result, final Throwable error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doShutdown? doCancel implies a failure state to me instead of a finished state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
&& !waitingForNewPeer; | ||
} | ||
|
||
public CompletableFuture<Void> getFuture() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
either the method name or the field name should be renamed. I would have expected to get the internal future
instead of tearDownFuture
or I would have expected to call getTearDownFuture
- a field rename would involve both fields being renamed. future
-> downloadingFuture
and getFuture
-> getTearDownFuture
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that did wind up weird...
*/ | ||
package tech.pegasys.pantheon.ethereum.eth.sync.worldstate; | ||
|
||
enum WorldStateDownloadStatus { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another unused file? Looks to have initially been factored out of WorldStateDownloader but it is no longer needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, fixed.
assertThat(pendingRequests.isEmpty()).isTrue(); | ||
} | ||
|
||
private Runnable mustNotBeCalled() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Putting on my paranoid tin foil hat, do we have a test where mustNotBeCalled is called so we can assert the failure escapes the lambdas? Or maybe I'm being too paranoid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was going to say you were paranoid but Meredith had the same question. I know it works because I always check my tests fail but worth adding an explicit test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a couple minor comments, but otherwise looks good
|
||
@Test | ||
public void shouldStoreRootNodeBeforeReturnedFutureCompletes() { | ||
future.thenAccept( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to check the result of this future - throwing inside the accept lambda won't trigger a failure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch.
*/ | ||
package tech.pegasys.pantheon.ethereum.eth.sync.worldstate; | ||
|
||
enum WorldStateDownloadStatus { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is unused now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
} | ||
} | ||
|
||
public void whileAdditionalRequestCanBeSent(final Runnable action) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public void whileAdditionalRequestCanBeSent(final Runnable action) { | |
public void whileAdditionalRequestsCanBeSent(final Runnable action) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
}); | ||
} | ||
|
||
private synchronized void doCancel(final Void result, final Throwable error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe rename this to onShutdown
or cleanup
or something since it always runs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, went with cleanup.
|
||
public synchronized void markAsFailed(final Task<NodeDataRequest> task) { | ||
if (!future.isDone()) { | ||
task.markFailed(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just an fyi - if task.markFailed()
is called after the queue is cleared, it doesn't requeue the failed task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, that's true. I know I had a test failing when I added it but it definitely seems fine now and all the code checks out. It's much nicer without it so removing...
PR description
The logic around tracking the state for a world state downloader is complex and hard to clearly analyse because it was mixed in with the details of performing actions in WorldStateDownloader. This PR splits the state tracking out to a separate class so it can be tested separately and the synchronization is clearer and more consistent.
Each download uses a new instance of of the state class which ensures that any events which occurs after the download is cancelled and restarted still see the cancelled future and abort correctly.
This revealed and fixes a couple of issues:
WaitForNewPeer
task. Only one thread should do that to limit the number of timers required.