mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
core/rawdb: improve freezer TruncateTail
This commit is contained in:
parent
1cd4b02579
commit
3a90107843
3 changed files with 104 additions and 4 deletions
|
|
@ -320,6 +320,8 @@ func (f *Freezer) TruncateTail(tail uint64) (uint64, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.tail.Store(tail)
|
f.tail.Store(tail)
|
||||||
|
|
||||||
|
// Update the head if the requested tail exceeds the current head
|
||||||
if f.head.Load() < tail {
|
if f.head.Load() < tail {
|
||||||
f.head.Store(tail)
|
f.head.Store(tail)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -707,12 +707,13 @@ func (t *freezerTable) truncateTail(items uint64) error {
|
||||||
t.lock.Lock()
|
t.lock.Lock()
|
||||||
defer t.lock.Unlock()
|
defer t.lock.Unlock()
|
||||||
|
|
||||||
// Ensure the given truncate target falls in the correct range
|
// Short-circuit if the requested tail deletion points to a stale position
|
||||||
if t.itemHidden.Load() >= items {
|
if t.itemHidden.Load() >= items {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// If the requested tail exceeds the current head, reset the entire table
|
||||||
if t.items.Load() < items {
|
if t.items.Load() < items {
|
||||||
return errors.New("truncation above head")
|
return t.resetTo(items)
|
||||||
}
|
}
|
||||||
// Load the new tail index by the given new tail position
|
// Load the new tail index by the given new tail position
|
||||||
var (
|
var (
|
||||||
|
|
@ -835,6 +836,55 @@ func (t *freezerTable) truncateTail(items uint64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resetTo clears the entire table and sets both the head and tail to the given
|
||||||
|
// value. It assumes the caller holds the lock and that tail > t.items.
|
||||||
|
func (t *freezerTable) resetTo(tail uint64) error {
|
||||||
|
// Sync the entire table before resetting, eliminating the potential
|
||||||
|
// data corruption.
|
||||||
|
err := t.Sync()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Update the index file to reflect the new offset
|
||||||
|
if err := t.index.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
entry := &indexEntry{
|
||||||
|
filenum: t.headId + 1,
|
||||||
|
offset: uint32(tail),
|
||||||
|
}
|
||||||
|
if err := reset(t.index.Name(), entry.append(nil)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := t.metadata.setFlushOffset(indexEntrySize, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.index, err = openFreezerFileForAppend(t.index.Name())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Purge all the existing data file
|
||||||
|
if err := t.head.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.headId = t.headId + 1
|
||||||
|
t.tailId = t.headId
|
||||||
|
|
||||||
|
t.head, err = t.openFile(t.headId, openFreezerFileForAppend)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
t.releaseFilesBefore(t.headId, true)
|
||||||
|
|
||||||
|
t.items.Store(tail)
|
||||||
|
t.itemOffset.Store(tail)
|
||||||
|
t.itemHidden.Store(tail)
|
||||||
|
t.sizeGauge.Update(0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Close closes all opened files and finalizes the freezer table for use.
|
// Close closes all opened files and finalizes the freezer table for use.
|
||||||
// This operation must be completed before shutdown to prevent the loss of
|
// This operation must be completed before shutdown to prevent the loss of
|
||||||
// recent writes.
|
// recent writes.
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,19 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func atomicRename(src, dest string) error {
|
||||||
|
if err := os.Rename(src, dest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
dir, err := os.Open(filepath.Dir(src))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
return dir.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
// copyFrom copies data from 'srcPath' at offset 'offset' into 'destPath'.
|
// copyFrom copies data from 'srcPath' at offset 'offset' into 'destPath'.
|
||||||
// The 'destPath' is created if it doesn't exist, otherwise it is overwritten.
|
// The 'destPath' is created if it doesn't exist, otherwise it is overwritten.
|
||||||
// Before the copy is executed, there is a callback can be registered to
|
// Before the copy is executed, there is a callback can be registered to
|
||||||
|
|
@ -73,13 +86,48 @@ func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
f = nil
|
f = nil
|
||||||
return os.Rename(fname, destPath)
|
|
||||||
|
return atomicRename(fname, destPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset atomically replaces the file at the given path with the provided content.
|
||||||
|
func reset(path string, content []byte) error {
|
||||||
|
// Create a temp file in the same dir where we want it to wind up
|
||||||
|
f, err := os.CreateTemp(filepath.Dir(path), "*")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fname := f.Name()
|
||||||
|
|
||||||
|
// Clean up the leftover file
|
||||||
|
defer func() {
|
||||||
|
if f != nil {
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
os.Remove(fname)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Write the content into the temp file
|
||||||
|
_, err = f.Write(content)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Permanently persist the content into disk
|
||||||
|
if err := f.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f = nil
|
||||||
|
|
||||||
|
return atomicRename(fname, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// openFreezerFileForAppend opens a freezer table file and seeks to the end
|
// openFreezerFileForAppend opens a freezer table file and seeks to the end
|
||||||
func openFreezerFileForAppend(filename string) (*os.File, error) {
|
func openFreezerFileForAppend(filename string) (*os.File, error) {
|
||||||
// Open the file without the O_APPEND flag
|
// Open the file without the O_APPEND flag
|
||||||
// because it has differing behaviour during Truncate operations
|
// because it has differing behavior during Truncate operations
|
||||||
// on different OS's
|
// on different OS's
|
||||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
|
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue