Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Cache current chain head info #1335

Merged
merged 11 commits into from
Apr 26, 2019
Merged

Conversation

ajsutton
Copy link
Contributor

PR description

Cache the current chain head in DefaultMutableBlockchain to avoid having to retrieve it's info from RocksDB. For the common case of getting the current chain head number that saves 2 DB reads. When importing blocks we take advantage of having cached the header when checking if the block has already been imported - if it's parent is the chain head it can't have been imported (or it would be the chain head) which saves a DB lookup in the most common case of extending chain head.

This primarily improves fast sync times where RocksDB read and write is being hammered by the world state import.

@@ -77,7 +82,7 @@ public static void setupSuite() {
@Before
public void setup() {
blockchainUtil = BlockchainSetupUtil.forTesting();
blockchain = spy(blockchainUtil.getBlockchain());
blockchain = blockchainUtil.getBlockchain();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a spy here causes problems because spy doesn't wrap the existing object, it creates a new instance. So we wind up with two instances of DefaultMutableBlockchain - one inside BlockchainSetupUtil which isn't a spy and the one in blockchain which is and they wind up getting out of sync. Sadly this creates some pain in the two tests that wanted to verify how many times a block was imported but it's at least a little more controlled and we consistently use the spies.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you wrap the original object in a spy inside of BlockchainSetupUtil?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible to do it that way but using spies is a really invasive technique - you don't get the test isolation you do from mocks but pick up the brittleness of testing specific interactions rather than results. So I was really hesitant to embed it in such a commonly used util and encourage it to spread.

() ->
bestPeer.hasOutstandingRequests()
|| otherPeers.stream().anyMatch(RespondingEthPeer::hasOutstandingRequests)
|| localBlockchain.getChainHeadBlockNumber() >= bestPeerChainHead);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this test is intermittent in master, but it becomes really intermittent once you make getChainHeadBlockNumber much faster. So we wait for there to be an outstanding request to respond to.

@@ -171,6 +175,10 @@ private BlockAddedEvent appendBlockHelper(
final BlockAddedEvent blockAddedEvent = updateCanonicalChainData(updater, block, td);

updater.commit();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to synchronize around the commit + chainHeader / totalDifficulty updates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are called from the appendBlock method which is synchronized.

@@ -77,7 +82,7 @@ public static void setupSuite() {
@Before
public void setup() {
blockchainUtil = BlockchainSetupUtil.forTesting();
blockchain = spy(blockchainUtil.getBlockchain());
blockchain = blockchainUtil.getBlockchain();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if you wrap the original object in a spy inside of BlockchainSetupUtil?

@ajsutton ajsutton merged commit 8ae3aed into PegaSysEng:master Apr 26, 2019
@ajsutton ajsutton deleted the cache-metadata branch April 26, 2019 22:01
ajsutton added a commit to ajsutton/pantheon that referenced this pull request Apr 28, 2019
Store the header for the current chain head and total difficulty to avoid RocksDB lookups when requesting those common values.

Also uses that cache to avoid a database lookup when checking if a block has already been imported if the block's parent is the current chain head.
notlesh pushed a commit to notlesh/pantheon that referenced this pull request May 4, 2019
Store the header for the current chain head and total difficulty to avoid RocksDB lookups when requesting those common values.

Also uses that cache to avoid a database lookup when checking if a block has already been imported if the block's parent is the current chain head.
notlesh pushed a commit to notlesh/pantheon that referenced this pull request May 14, 2019
Store the header for the current chain head and total difficulty to avoid RocksDB lookups when requesting those common values.

Also uses that cache to avoid a database lookup when checking if a block has already been imported if the block's parent is the current chain head.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants