Skip to content

Commit

Permalink
core/rawdb, ethdb: introduce batched/atomic reads from ancients
Browse files Browse the repository at this point in the history
  • Loading branch information
holiman committed Sep 13, 2021
1 parent 9ada4a2 commit a528b7f
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 27 deletions.
34 changes: 11 additions & 23 deletions core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,30 +393,18 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue
// First try to look up the data in ancient database. Extra hash
// comparison is necessary since ancient database only maintains
// the canonical data.
data, _ := db.Ancient(freezerBodiesTable, number)
if len(data) > 0 {
h, _ := db.Ancient(freezerHashTable, number)
if common.BytesToHash(h) == hash {
return data
}
}
// Then try to look up the data in leveldb.
data, _ = db.Get(blockBodyKey(number, hash))
if len(data) > 0 {
return data
}
// In the background freezer is moving data from leveldb to flatten files.
// So during the first check for ancient db, the data is not yet in there,
// but when we reach into leveldb, the data was already moved. That would
// result in a not found error.
data, _ = db.Ancient(freezerBodiesTable, number)
if len(data) > 0 {
h, _ := db.Ancient(freezerHashTable, number)
if common.BytesToHash(h) == hash {
return data
var data []byte
db.AtomicReadAncients(func (reader ethdb.AncientReader) error{
// Check if the data is in ancients
if h, _ := db.Ancient(freezerHashTable, number); common.BytesToHash(h) == hash {
data, _ = db.Ancient(freezerBodiesTable, number)
return nil
}
}
return nil // Can't find the data anywhere.
// If not, try reading from leveldb
data, _ = db.Get(blockBodyKey(number, hash))
return nil
})
return data
}

// ReadCanonicalBodyRLP retrieves the block body (transactions and uncles) for the canonical
Expand Down
4 changes: 4 additions & 0 deletions core/rawdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ func (db *nofreezedb) Sync() error {
return errNotSupported
}

func (db *nofreezedb) AtomicReadAncients(fn func(reader ethdb.AncientReader) error) (err error){
return errNotSupported
}

// NewDatabase creates a high level database on top of a given key-value data
// store without a freezer moving immutable chain segments into cold storage.
func NewDatabase(db ethdb.KeyValueStore) ethdb.Database {
Expand Down
17 changes: 13 additions & 4 deletions core/rawdb/freezer.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ type freezer struct {
frozen uint64 // Number of blocks already frozen
threshold uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)

// This lock synchronizes writers and the truncate operation.
writeLock sync.Mutex
// This lock synchronizes writers and the truncate operation, as well as
// the "atomic" (batched) read operations.
writeLock sync.RWMutex
writeBatch *freezerBatch

readonly bool
Expand Down Expand Up @@ -222,15 +223,23 @@ func (f *freezer) Ancients() (uint64, error) {
func (f *freezer) AncientSize(kind string) (uint64, error) {
// This needs the write lock to avoid data races on table fields.
// Speed doesn't matter here, AncientSize is for debugging.
f.writeLock.Lock()
defer f.writeLock.Unlock()
f.writeLock.RLock()
defer f.writeLock.RUnlock()

if table := f.tables[kind]; table != nil {
return table.size()
}
return 0, errUnknownTable
}

// AtomicReadAncients runs the given read operation while ensuring that no writes take place
// on the underlying freezer.
func (f *freezer) AtomicReadAncients(fn func(ethdb.AncientReader) error) (err error) {
f.writeLock.RLock()
defer f.writeLock.RUnlock()
return fn(f)
}

// ModifyAncients runs the given write operation.
func (f *freezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) {
if f.readonly {
Expand Down
4 changes: 4 additions & 0 deletions core/rawdb/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ func (t *table) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (int64, erro
return t.db.ModifyAncients(fn)
}

func (t *table) AtomicReadAncients(fn func(reader ethdb.AncientReader) error) (err error){
return errNotSupported
}

// TruncateAncients is a noop passthrough that just forwards the request to the underlying
// database.
func (t *table) TruncateAncients(items uint64) error {
Expand Down
5 changes: 5 additions & 0 deletions ethdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ type AncientReader interface {

// AncientSize returns the ancient size of the specified category.
AncientSize(kind string) (uint64, error)

// AtomicReadAncients runs the given read operation while ensuring that no writes take place
// on the underlying freezer.
AtomicReadAncients(fn func(AncientReader) error) (err error)

}

// AncientWriter contains the methods required to write to immutable ancient data.
Expand Down

0 comments on commit a528b7f

Please sign in to comment.