mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-25 07:56:16 +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)
|
||||
|
||||
// Update the head if the requested tail exceeds the current head
|
||||
if f.head.Load() < tail {
|
||||
f.head.Store(tail)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -707,12 +707,13 @@ func (t *freezerTable) truncateTail(items uint64) error {
|
|||
t.lock.Lock()
|
||||
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 {
|
||||
return nil
|
||||
}
|
||||
// If the requested tail exceeds the current head, reset the entire table
|
||||
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
|
||||
var (
|
||||
|
|
@ -835,6 +836,55 @@ func (t *freezerTable) truncateTail(items uint64) error {
|
|||
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.
|
||||
// This operation must be completed before shutdown to prevent the loss of
|
||||
// recent writes.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,19 @@ import (
|
|||
"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'.
|
||||
// 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
|
||||
|
|
@ -73,13 +86,48 @@ func copyFrom(srcPath, destPath string, offset uint64, before func(f *os.File) e
|
|||
return err
|
||||
}
|
||||
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
|
||||
func openFreezerFileForAppend(filename string) (*os.File, error) {
|
||||
// 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
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0644)
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue