From ebed66d49ffd27ebe9c7be509487b4452b21eb90 Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Mon, 13 Sep 2021 11:50:50 +0200 Subject: [PATCH] core/rawdb: use atomic reads --- core/rawdb/accessors_chain.go | 152 ++++++++++++---------------------- 1 file changed, 54 insertions(+), 98 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 8b6d206bfe5bf..21dbdd6a4f634 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -34,20 +34,15 @@ import ( // ReadCanonicalHash retrieves the hash assigned to a canonical block number. func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash { - data, _ := db.Ancient(freezerHashTable, number) - if len(data) == 0 { - data, _ = db.Get(headerHashKey(number)) - // 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. + var data []byte + db.AtomicReadAncients(func(reader ethdb.AncientReader) error { + data, _ := db.Ancient(freezerHashTable, number) if len(data) == 0 { - data, _ = db.Ancient(freezerHashTable, number) + // Get it by hash from leveldb + data, _ = db.Get(headerHashKey(number)) } - } - if len(data) == 0 { - return common.Hash{} - } + return nil + }) return common.BytesToHash(data) } @@ -303,27 +298,21 @@ func WriteFastTxLookupLimit(db ethdb.KeyValueWriter, number uint64) { // ReadHeaderRLP retrieves a block header in its raw RLP database encoding. func ReadHeaderRLP(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(freezerHeaderTable, number) - if len(data) > 0 && crypto.Keccak256Hash(data) == hash { - return data - } - // Then try to look up the data in leveldb. - data, _ = db.Get(headerKey(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(freezerHeaderTable, number) - if len(data) > 0 && crypto.Keccak256Hash(data) == hash { - return data - } - return nil // Can't find the data anywhere. + var data []byte + db.AtomicReadAncients(func(reader ethdb.AncientReader) error { + // First try to look up the data in ancient database. Extra hash + // comparison is necessary since ancient database only maintains + // the canonical data. + d, _ := db.Ancient(freezerHeaderTable, number) + if len(d) > 0 && crypto.Keccak256Hash(d) == hash { + d = data + return nil + } + // If not, try reading from leveldb + data, _ = db.Get(headerKey(number, hash)) + return nil + }) + return data } // HasHeader verifies the existence of a block header corresponding to the hash. @@ -394,7 +383,7 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue // comparison is necessary since ancient database only maintains // the canonical data. var data []byte - db.AtomicReadAncients(func (reader ethdb.AncientReader) error{ + 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) @@ -410,19 +399,16 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue // ReadCanonicalBodyRLP retrieves the block body (transactions and uncles) for the canonical // block at number, in RLP encoding. func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue { - // If it's an ancient one, we don't need the canonical hash - data, _ := db.Ancient(freezerBodiesTable, number) - if len(data) == 0 { - // Need to get the hash - data, _ = db.Get(blockBodyKey(number, ReadCanonicalHash(db, number))) - // 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. - if len(data) == 0 { - data, _ = db.Ancient(freezerBodiesTable, number) + var data []byte + db.AtomicReadAncients(func(reader ethdb.AncientReader) error { + if d, err := db.Ancient(freezerBodiesTable, number); err == nil { + data = d + return nil + // Get it by hash from leveldb } - } + data, _ = db.Get(blockBodyKey(number, ReadCanonicalHash(db, number))) + return nil + }) return data } @@ -476,33 +462,18 @@ func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) { // ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding. func ReadTdRLP(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(freezerDifficultyTable, 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(headerTDKey(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(freezerDifficultyTable, 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(freezerDifficultyTable, number) + return nil } - } - return nil // Can't find the data anywhere. + // If not, try reading from leveldb + data, _ = db.Get(headerTDKey(number, hash)) + return nil + }) + return data } // ReadTd retrieves a block's total difficulty corresponding to the hash. @@ -551,33 +522,18 @@ func HasReceipts(db ethdb.Reader, hash common.Hash, number uint64) bool { // ReadReceiptsRLP retrieves all the transaction receipts belonging to a block in RLP encoding. func ReadReceiptsRLP(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(freezerReceiptTable, 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(blockReceiptsKey(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(freezerReceiptTable, 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(freezerReceiptTable, number) + return nil } - } - return nil // Can't find the data anywhere. + // If not, try reading from leveldb + data, _ = db.Get(blockReceiptsKey(number, hash)) + return nil + }) + return data } // ReadRawReceipts retrieves all the transaction receipts belonging to a block.