core/rawdb, ethdb: polish

This commit is contained in:
Gary Rong 2025-10-13 14:51:35 +08:00
parent e6e78637e7
commit 90d9e313f4
9 changed files with 86 additions and 80 deletions

View file

@ -403,8 +403,8 @@ func (f *chainFreezer) AncientRange(kind string, start, count, maxBytes uint64)
return f.ancients.AncientRange(kind, start, count, maxBytes)
}
func (f *chainFreezer) AncientBytes(kind string, item, offset, length uint64) ([]byte, error) {
return f.ancients.AncientBytes(kind, item, offset, length)
func (f *chainFreezer) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
return f.ancients.AncientBytes(kind, id, offset, length)
}
func (f *chainFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (int64, error) {

View file

@ -100,8 +100,9 @@ func (db *nofreezedb) AncientRange(kind string, start, max, maxByteSize uint64)
return nil, errNotSupported
}
// AncientBytes retrieves a byte range [offset:offset+length] from the specified ancient item.
func (db *nofreezedb) AncientBytes(kind string, item, offset, length uint64) ([]byte, error) {
// AncientBytes retrieves the value segment of the element specified by the id
// and value offsets.
func (db *nofreezedb) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
return nil, errNotSupported
}

View file

@ -202,10 +202,11 @@ func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]
return nil, errUnknownTable
}
// RetrieveBytes retrieves a byte range [offset:offset+length] from the specified ancient item.
func (f *Freezer) AncientBytes(kind string, number, offset, length uint64) ([]byte, error) {
// AncientBytes retrieves the value segment of the element specified by the id
// and value offsets.
func (f *Freezer) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
if table := f.tables[kind]; table != nil {
return table.RetrieveBytes(number, offset, length)
return table.RetrieveBytes(id, offset, length)
}
return nil, errUnknownTable
}

View file

@ -413,8 +413,9 @@ func (f *MemoryFreezer) AncientDatadir() (string, error) {
return "", nil
}
// AncientBytes retrieves a byte range [offset:offset+length] from the specified ancient item in memory.
func (f *MemoryFreezer) AncientBytes(kind string, item, offset, length uint64) ([]byte, error) {
// AncientBytes retrieves the value segment of the element specified by the id
// and value offsets.
func (f *MemoryFreezer) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
f.lock.RLock()
defer f.lock.RUnlock()
@ -422,7 +423,7 @@ func (f *MemoryFreezer) AncientBytes(kind string, item, offset, length uint64) (
if table == nil {
return nil, errUnknownTable
}
entries, err := table.retrieve(item, 1, 0)
entries, err := table.retrieve(id, 1, 0)
if err != nil {
return nil, err
}
@ -430,6 +431,7 @@ func (f *MemoryFreezer) AncientBytes(kind string, item, offset, length uint64) (
return nil, errOutOfBounds
}
data := entries[0]
if offset > uint64(len(data)) || offset+length > uint64(len(data)) {
return nil, fmt.Errorf("requested range out of bounds: item size %d, offset %d, length %d", len(data), offset, length)
}

View file

@ -126,11 +126,13 @@ func (f *resettableFreezer) AncientRange(kind string, start, count, maxBytes uin
return f.freezer.AncientRange(kind, start, count, maxBytes)
}
// RetrieveBytes retrieves a byte range [offset:offset+length] from the specified ancient item.
func (f *resettableFreezer) AncientBytes(kind string, number, offset, length uint64) ([]byte, error) {
// AncientBytes retrieves the value segment of the element specified by the id
// and value offsets.
func (f *resettableFreezer) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
f.lock.RLock()
defer f.lock.RUnlock()
return f.freezer.AncientBytes(kind, number, offset, length)
return f.freezer.AncientBytes(kind, id, offset, length)
}
// Ancients returns the length of the frozen items.

View file

@ -1107,6 +1107,67 @@ func (t *freezerTable) retrieveItems(start, count, maxBytes uint64) ([]byte, []i
return output, sizes, nil
}
// RetrieveBytes retrieves the value segment of the element specified by the id
// and value offsets.
func (t *freezerTable) RetrieveBytes(item, offset, length uint64) ([]byte, error) {
t.lock.RLock()
defer t.lock.RUnlock()
if t.index == nil || t.head == nil || t.metadata.file == nil {
return nil, errClosed
}
items, hidden := t.items.Load(), t.itemHidden.Load()
if items <= item || hidden > item {
return nil, errOutOfBounds
}
// Retrieves the index entries for the specified ID and its immediate successor
indices, err := t.getIndices(item, 1)
if err != nil {
return nil, err
}
index0, index1 := indices[0], indices[1]
itemStart, endLimit, fileId := index0.bounds(index1)
itemSize := endLimit - itemStart
dataFile, exist := t.files[fileId]
if !exist {
return nil, fmt.Errorf("missing data file %d", fileId)
}
// Perform the partial read if no-compression was enabled upon
if t.config.noSnappy {
// Range check before reading
if offset > uint64(itemSize) || offset+length > uint64(itemSize) {
return nil, fmt.Errorf("requested range out of bounds: item size %d, offset %d, length %d", itemSize, offset, length)
}
itemStart += uint32(offset)
buf := make([]byte, length)
_, err = dataFile.ReadAt(buf, int64(itemStart))
if err != nil {
return nil, err
}
return buf, nil
} else {
buf := make([]byte, itemSize)
_, err = dataFile.ReadAt(buf, int64(itemStart))
if err != nil {
return nil, err
}
// If compressed, read the full item, decompress, then slice
data, err := snappy.Decode(nil, buf)
if err != nil {
return nil, err
}
if offset > uint64(len(data)) || offset+length > uint64(len(data)) {
return nil, fmt.Errorf("requested range out of bounds: item size %d, offset %d, length %d", len(data), offset, length)
}
return data[offset : offset+length], nil
}
}
// size returns the total data size in the freezer table.
func (t *freezerTable) size() (uint64, error) {
t.lock.RLock()
@ -1235,65 +1296,3 @@ func (t *freezerTable) dumpIndex(w io.Writer, start, stop int64) {
}
fmt.Fprintf(w, "|--------------------------|\n")
}
// RetrieveBytes retrieves a byte range [offset:offset+length] from the specified ancient item.
func (t *freezerTable) RetrieveBytes(item, offset, length uint64) ([]byte, error) {
t.lock.RLock()
defer t.lock.RUnlock()
if t.index == nil || t.head == nil || t.metadata.file == nil {
return nil, errClosed
}
items := t.items.Load()
hidden := t.itemHidden.Load()
if items <= item || hidden > item {
return nil, errOutOfBounds
}
// Read the index entries for the item and the next item,
// this method will return two indices or an error.
indices, err := t.getIndices(item, 1)
if err != nil {
return nil, err
}
index0 := indices[0]
index1 := indices[1]
startOffset, endOffset, fileId := index0.bounds(index1)
itemSize := endOffset - startOffset
dataFile, exist := t.files[fileId]
if !exist {
return nil, fmt.Errorf("missing data file %d", fileId)
}
readBytes := int(itemSize)
if t.config.noSnappy {
// Range check before reading
if offset > uint64(itemSize) || offset+length > uint64(itemSize) {
return nil, fmt.Errorf("requested range out of bounds: item size %d, offset %d, length %d", itemSize, offset, length)
}
startOffset += uint32(offset)
readBytes = int(length)
}
buf := make([]byte, readBytes)
_, err = dataFile.ReadAt(buf, int64(startOffset))
if err != nil {
return nil, err
}
// If not compressed, read only the requested bytes
if t.config.noSnappy {
return buf, nil
}
// If compressed, read the full item, decompress, then slice
data, err := snappy.Decode(nil, buf)
if err != nil {
return nil, err
}
if offset > uint64(len(data)) || offset+length > uint64(len(data)) {
return nil, fmt.Errorf("requested range out of bounds after decompression: item size %d, offset %d, length %d", len(data), offset, length)
}
return data[offset : offset+length], nil
}

View file

@ -64,8 +64,8 @@ func (t *table) AncientRange(kind string, start, count, maxBytes uint64) ([][]by
// AncientBytes is a noop passthrough that just forwards the request to the underlying
// database.
func (t *table) AncientBytes(kind string, item, offset, length uint64) ([]byte, error) {
return t.db.AncientBytes(kind, item, offset, length)
func (t *table) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
return t.db.AncientBytes(kind, id, offset, length)
}
// Ancients is a noop passthrough that just forwards the request to the underlying

View file

@ -121,8 +121,9 @@ type AncientReaderOp interface {
// - if maxBytes is not specified, 'count' items will be returned if they are present
AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error)
// AncientBytes retrieves a byte range [offset:offset+length] from the specified ancient item.
AncientBytes(kind string, number, offset, length uint64) ([]byte, error)
// AncientBytes retrieves the value segment of the element specified by the id
// and value offsets.
AncientBytes(kind string, id, offset, length uint64) ([]byte, error)
// Ancients returns the ancient item numbers in the ancient store.
Ancients() (uint64, error)

View file

@ -140,7 +140,7 @@ func (db *Database) Close() error {
return nil
}
func (db *Database) AncientBytes(kind string, item, offset, length uint64) ([]byte, error) {
func (db *Database) AncientBytes(kind string, id, offset, length uint64) ([]byte, error) {
panic("not supported")
}