Skip to content

core: split the db blocks into components, move TD out top level#1779

Merged
obscuren merged 2 commits intoethereum:developfrom
karalabe:split-block-storage-3000
Sep 11, 2015
Merged

core: split the db blocks into components, move TD out top level#1779
obscuren merged 2 commits intoethereum:developfrom
karalabe:split-block-storage-3000

Conversation

@karalabe
Copy link
Copy Markdown
Member

@karalabe karalabe commented Sep 7, 2015

This PR features the following:

  • Split the block storage into separate headers and bodies (need pure header mode of operation).
  • Support retrieving the raw RLP header/body data (during query, no need to parse and re-flatten).
  • Refactor eth to use direct header/body accesses instead of entire block reads from the database.
  • Factor out the TD from the blocks and assign top level database entries (prep header only mode).
  • Drop direct database "by number" gets (don't duplicate chain manager logic (also has cache)).
  • Tests for all primitive (header, body, td, block) data storage and retrieval operations.
  • Tests for metadata (canonical number, head header, head block) data storage and retrieval.

@robotally
Copy link
Copy Markdown

Vote Count Reviewers
👍 2 @obscuren @zsfelfoldi
👎 0

Updated: Fri Sep 11 15:10:42 UTC 2015

@karalabe
Copy link
Copy Markdown
Member Author

karalabe commented Sep 8, 2015

@fjl @obscuren Please review this PR so that maybe we could push it into the next release.

@karalabe karalabe changed the title Split block storage 3000 core: split the db blocks into primitive components, move TD out top level too Sep 8, 2015
@karalabe karalabe changed the title core: split the db blocks into primitive components, move TD out top level too core: split the db blocks into components, move TD out top level Sep 8, 2015
Comment thread core/chain_manager.go
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Is there a benchmark to show if/how much performance gain these caches give? Given that both leveldb and the OS will cache frequently used data I'm wary of adding yet another caching layer and the complexity that goes with it unless benchmarks show it's a bottleneck and would give significant performance boost.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

You are partially right, but there's a catch. LevelDB keeps its data sorted by key on disk, rearranging them when some thresholds are crossed. As we're storing everything by hash, we are essentially doing random writes and random reads. From the write perspective it means, that disk caches get invalidated frequently (i.e. if there's a leveldb compaction, I'm betting everything goes stale). From the read perspective it means, that as every read is at a completely different location than the previous ones, there's extremely small chance of a disk cache hit, so we'll keep trashing the disk unless we find a way to do smarter caching.

Maybe the values are off and not completely correct. Those should be benchmarked somehow and experimented with, but the current chain size is inappropriate for these purposes as it's tiny compared to total available OS memory. Unless we start hitting 2-3x the OS memory limits, we won't see much action from these caches. However, I would not simply remove them just to readd them when the time comes.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Right, makes sense in context of our keys being effectively random as they are (even cryptographically secure) hashes. Note I'm not doubting that it would give something - I know you researched the leveldb caching thoroughly before - it's more about the practice of having benchmarks to back up optimisations. In my book this is similar to adding tests proving correctness of new functionality. Even if it's evident that caching here will give a boost, benchmarks will quantify it and inform us of where bottlenecks and prioritises are.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Agreed, but sadly we don't have a big enough network to realistically test it. We could write some superficial benchmarks, but those can generate any result we want. If we do a trashing benchmark, it will show that it matters, a naive benchmark may show it doesn't. But neither will represent reality. The reason I suggest to leave it in for now is because we introduced it at a certain point in Olympic to lighten the db load, and I'm assuming there was some actual benefit. However, we cannot really test it out now so we'll have to wait until high load appears again to verify (realistically I mean).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If we cannot test it then we shouldn't add it, because we cannot verify how much benefit it gives. That would be like making a bug fix but have no way to verify if the fix worked.

It's better we have some benchmarks to start with even if they do not cover everything or are artificial in nature. At least they would provide a starting point for reasoning about how different caches and cache sizes affect performance.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Debate it with @obscuren, he's the one who originally added the cache :P. I just extended it for the split database layout.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The cache is a relic. I'm completely fine removing it (and re-adding it if required + benchmarks)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I shall pick up this task in core-refactor or in a separate PR #1788

@fjl fjl mentioned this pull request Sep 9, 2015
@obscuren
Copy link
Copy Markdown
Contributor

👍 requires squashing

@karalabe
Copy link
Copy Markdown
Member Author

Will do after enough fingers :D

@zsfelfoldi
Copy link
Copy Markdown
Contributor

👍

Comment thread eth/peer.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please use rlp.RawValue instead of *blockBodyRLP when #1778 is on develop (edit: it is now).
The conversion to blockBodiesRLPData is also unnecessary (package rlp knows how to encode slices of encoder types).

Btw, I don't get why we have these methods. IMHO using p2p.Send(p.rw, ...) in place of the method is just as clear. They're just boilerplate.

@fjl fjl added this to the 1.2.0 milestone Sep 10, 2015
@karalabe
Copy link
Copy Markdown
Member Author

@obscuren Rebased on develop, squashed into two commits (block split and extraction). Before merging please wait for a thumbs up from @fjl as he requested some minor changes that were enabled by his PR.

@fjl PTAL

@fjl
Copy link
Copy Markdown
Contributor

fjl commented Sep 11, 2015

                                                                                  I didn't really mean that the return types of GetHeaderRLP, GetBodyRLP should also be RawValue but it might make it even clearer. 

obscuren added a commit that referenced this pull request Sep 11, 2015
core: split the db blocks into components, move TD out top level
@obscuren obscuren merged commit 0eac601 into ethereum:develop Sep 11, 2015
@obscuren obscuren removed the review label Sep 11, 2015
@fjl
Copy link
Copy Markdown
Contributor

fjl commented Sep 11, 2015

                                                                                  Just to ‎make it clear: that part now LGTM.I must say that I only skimmed most of the PR, but others reviewed in detail so it's probably OK too. Some general background on the return types:Go's type system defines types as assignable when their underlying type is the same and they're not both named types. This is supposed to prevent bugs because a named type signals intent. As a consequence, returning a named type (rlp.RawValue) instead of a primitive type ([]byte) can have the unintended consequence that callers need to convert explicitly if they want to assign to some other named type. Returning a named type also makes less usable in caller-defined interfaces because they need to import the type's package just to list the type in the interface definition.‎ That doesn't apply here though because these aren't methods.

fjl added a commit to fjl/go-ethereum that referenced this pull request Sep 22, 2015
Most eth RPC calls that work with blocks crashed when the block was not
found because they called Hash on a nil block. This is a regression
introduced in cdc2662 (ethereum#1779).

While here, remove the insane conversions in get*CountBy*. There is no
need to construct a complete BlockRes and converting
int->int64->*big.Int->[]byte->hexnum->string to format the length of a
slice as hex.
sduchesneau pushed a commit to streamingfast/go-ethereum that referenced this pull request Sep 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants