@@ -23,6 +23,7 @@ import (
2323 "time"
2424
2525 "github.com/CortexFoundation/CortexTheseus/common"
26+ "github.com/CortexFoundation/CortexTheseus/core/rawdb/eradb"
2627 "github.com/CortexFoundation/CortexTheseus/ctxcdb"
2728 "github.com/CortexFoundation/CortexTheseus/log"
2829 "github.com/CortexFoundation/CortexTheseus/params"
@@ -43,7 +44,10 @@ const (
4344// feature. The background thread will keep moving ancient chain segments from
4445// key-value database to flat files for saving space on live database.
4546type chainFreezer struct {
46- ctxcdb.AncientStore // Ancient store for storing cold chain segment
47+ ancients ctxcdb.AncientStore // Ancient store for storing cold chain segment
48+
49+ // Optional Era database used as a backup for the pruned chain.
50+ eradb * eradb.Store
4751
4852 quit chan struct {}
4953 wg sync.WaitGroup
@@ -56,23 +60,27 @@ type chainFreezer struct {
5660// state freezer (e.g. dev mode).
5761// - if non-empty directory is given, initializes the regular file-based
5862// state freezer.
59- func newChainFreezer (datadir string , namespace string , readonly bool ) (* chainFreezer , error ) {
60- var (
61- err error
62- freezer ctxcdb.AncientStore
63- )
63+ func newChainFreezer (datadir string , eraDir string , namespace string , readonly bool ) (* chainFreezer , error ) {
6464 if datadir == "" {
65- freezer = NewMemoryFreezer (readonly , chainFreezerNoSnappy )
66- } else {
67- freezer , err = NewFreezer (datadir , namespace , readonly , freezerTableSize , chainFreezerNoSnappy )
65+ return & chainFreezer {
66+ ancients : NewMemoryFreezer (readonly , chainFreezerTableConfigs ),
67+ quit : make (chan struct {}),
68+ trigger : make (chan chan struct {}),
69+ }, nil
70+ }
71+ freezer , err := NewFreezer (datadir , namespace , readonly , freezerTableSize , chainFreezerTableConfigs )
72+ if err != nil {
73+ return nil , err
6874 }
75+ edb , err := eradb .New (resolveChainEraDir (datadir , eraDir ))
6976 if err != nil {
7077 return nil , err
7178 }
7279 return & chainFreezer {
73- AncientStore : freezer ,
74- quit : make (chan struct {}),
75- trigger : make (chan chan struct {}),
80+ ancients : freezer ,
81+ eradb : edb ,
82+ quit : make (chan struct {}),
83+ trigger : make (chan chan struct {}),
7684 }, nil
7785}
7886
@@ -84,7 +92,11 @@ func (f *chainFreezer) Close() error {
8492 close (f .quit )
8593 }
8694 f .wg .Wait ()
87- return f .AncientStore .Close ()
95+
96+ if f .eradb != nil {
97+ f .eradb .Close ()
98+ }
99+ return f .ancients .Close ()
88100}
89101
90102// readHeadNumber returns the number of chain head block. 0 is returned if the
@@ -342,3 +354,75 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
342354 })
343355 return hashes , err
344356}
357+
358+ // Ancient retrieves an ancient binary blob from the append-only immutable files.
359+ func (f * chainFreezer ) Ancient (kind string , number uint64 ) ([]byte , error ) {
360+ // Lookup the entry in the underlying ancient store, assuming that
361+ // headers and hashes are always available.
362+ if kind == ChainFreezerHeaderTable || kind == ChainFreezerHashTable {
363+ return f .ancients .Ancient (kind , number )
364+ }
365+ tail , err := f .ancients .Tail ()
366+ if err != nil {
367+ return nil , err
368+ }
369+ // Lookup the entry in the underlying ancient store if it's not pruned
370+ if number >= tail {
371+ return f .ancients .Ancient (kind , number )
372+ }
373+ // Lookup the entry in the optional era backend
374+ if f .eradb == nil {
375+ return nil , errOutOfBounds
376+ }
377+ switch kind {
378+ case ChainFreezerBodiesTable :
379+ return f .eradb .GetRawBody (number )
380+ case ChainFreezerReceiptTable :
381+ return f .eradb .GetRawReceipts (number )
382+ }
383+ return nil , errUnknownTable
384+ }
385+
386+ // ReadAncients executes an operation while preventing mutations to the freezer,
387+ // i.e. if fn performs multiple reads, they will be consistent with each other.
388+ func (f * chainFreezer ) ReadAncients (fn func (ctxcdb.AncientReaderOp ) error ) (err error ) {
389+ if store , ok := f .ancients .(* Freezer ); ok {
390+ store .writeLock .Lock ()
391+ defer store .writeLock .Unlock ()
392+ }
393+ return fn (f )
394+ }
395+
396+ // Methods below are just pass-through to the underlying ancient store.
397+
398+ func (f * chainFreezer ) Ancients () (uint64 , error ) {
399+ return f .ancients .Ancients ()
400+ }
401+
402+ func (f * chainFreezer ) Tail () (uint64 , error ) {
403+ return f .ancients .Tail ()
404+ }
405+
406+ func (f * chainFreezer ) AncientSize (kind string ) (uint64 , error ) {
407+ return f .ancients .AncientSize (kind )
408+ }
409+
410+ func (f * chainFreezer ) AncientRange (kind string , start , count , maxBytes uint64 ) ([][]byte , error ) {
411+ return f .ancients .AncientRange (kind , start , count , maxBytes )
412+ }
413+
414+ func (f * chainFreezer ) ModifyAncients (fn func (ctxcdb.AncientWriteOp ) error ) (int64 , error ) {
415+ return f .ancients .ModifyAncients (fn )
416+ }
417+
418+ func (f * chainFreezer ) TruncateHead (items uint64 ) (uint64 , error ) {
419+ return f .ancients .TruncateHead (items )
420+ }
421+
422+ func (f * chainFreezer ) TruncateTail (items uint64 ) (uint64 , error ) {
423+ return f .ancients .TruncateTail (items )
424+ }
425+
426+ func (f * chainFreezer ) SyncAncient () error {
427+ return f .ancients .SyncAncient ()
428+ }
0 commit comments