From 90d9e313f48fe9c34450d94539a8cf5ff6db5572 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Mon, 13 Oct 2025 14:51:35 +0800 Subject: [PATCH] core/rawdb, ethdb: polish --- core/rawdb/chain_freezer.go | 4 +- core/rawdb/database.go | 5 +- core/rawdb/freezer.go | 7 +- core/rawdb/freezer_memory.go | 8 +- core/rawdb/freezer_resettable.go | 8 +- core/rawdb/freezer_table.go | 123 +++++++++++++++---------------- core/rawdb/table.go | 4 +- ethdb/database.go | 5 +- ethdb/remotedb/remotedb.go | 2 +- 9 files changed, 86 insertions(+), 80 deletions(-) diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index db607b1493..d33f7ce33d 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -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) { diff --git a/core/rawdb/database.go b/core/rawdb/database.go index bfe8c9a79f..724c90ead6 100644 --- a/core/rawdb/database.go +++ b/core/rawdb/database.go @@ -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 } diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index b38910fa05..42cd2a7999 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -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 } diff --git a/core/rawdb/freezer_memory.go b/core/rawdb/freezer_memory.go index 24e0dadda4..8cb4cc2006 100644 --- a/core/rawdb/freezer_memory.go +++ b/core/rawdb/freezer_memory.go @@ -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) } diff --git a/core/rawdb/freezer_resettable.go b/core/rawdb/freezer_resettable.go index 3df1633865..f531e668c3 100644 --- a/core/rawdb/freezer_resettable.go +++ b/core/rawdb/freezer_resettable.go @@ -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. diff --git a/core/rawdb/freezer_table.go b/core/rawdb/freezer_table.go index f2095f8fb6..63e3a5bff4 100644 --- a/core/rawdb/freezer_table.go +++ b/core/rawdb/freezer_table.go @@ -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 -} diff --git a/core/rawdb/table.go b/core/rawdb/table.go index 4d70059e8b..d38afdaa35 100644 --- a/core/rawdb/table.go +++ b/core/rawdb/table.go @@ -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 diff --git a/ethdb/database.go b/ethdb/database.go index e6c10245f6..534fcad4fc 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -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) diff --git a/ethdb/remotedb/remotedb.go b/ethdb/remotedb/remotedb.go index d58048ba58..0d0d854fe4 100644 --- a/ethdb/remotedb/remotedb.go +++ b/ethdb/remotedb/remotedb.go @@ -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") }