1717package rawdb
1818
1919import (
20+ "errors"
2021 "fmt"
2122 "sync"
22- "sync/atomic"
2323 "time"
2424
2525 "github.com/ethereum/go-ethereum/common"
@@ -43,8 +43,6 @@ const (
4343// The background thread will keep moving ancient chain segments from key-value
4444// database to flat files for saving space on live database.
4545type chainFreezer struct {
46- threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
47-
4846 * Freezer
4947 quit chan struct {}
5048 wg sync.WaitGroup
@@ -57,13 +55,11 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre
5755 if err != nil {
5856 return nil , err
5957 }
60- cf := chainFreezer {
58+ return & chainFreezer {
6159 Freezer : freezer ,
6260 quit : make (chan struct {}),
6361 trigger : make (chan chan struct {}),
64- }
65- cf .threshold .Store (params .FullImmutabilityThreshold )
66- return & cf , nil
62+ }, nil
6763}
6864
6965// Close closes the chain freezer instance and terminates the background thread.
@@ -77,6 +73,57 @@ func (f *chainFreezer) Close() error {
7773 return f .Freezer .Close ()
7874}
7975
76+ // readHeadNumber returns the number of chain head block. 0 is returned if the
77+ // block is unknown or not available yet.
78+ func (f * chainFreezer ) readHeadNumber (db ethdb.KeyValueReader ) uint64 {
79+ hash := ReadHeadBlockHash (db )
80+ if hash == (common.Hash {}) {
81+ log .Error ("Head block is not reachable" )
82+ return 0
83+ }
84+ number := ReadHeaderNumber (db , hash )
85+ if number == nil {
86+ log .Error ("Number of head block is missing" )
87+ return 0
88+ }
89+ return * number
90+ }
91+
92+ // readFinalizedNumber returns the number of finalized block. 0 is returned
93+ // if the block is unknown or not available yet.
94+ func (f * chainFreezer ) readFinalizedNumber (db ethdb.KeyValueReader ) uint64 {
95+ hash := ReadFinalizedBlockHash (db )
96+ if hash == (common.Hash {}) {
97+ return 0
98+ }
99+ number := ReadHeaderNumber (db , hash )
100+ if number == nil {
101+ log .Error ("Number of finalized block is missing" )
102+ return 0
103+ }
104+ return * number
105+ }
106+
107+ // freezeThreshold returns the threshold for chain freezing. It's determined
108+ // by formula: max(finality, HEAD-params.FullImmutabilityThreshold).
109+ func (f * chainFreezer ) freezeThreshold (db ethdb.KeyValueReader ) (uint64 , error ) {
110+ var (
111+ head = f .readHeadNumber (db )
112+ final = f .readFinalizedNumber (db )
113+ headLimit uint64
114+ )
115+ if head > params .FullImmutabilityThreshold {
116+ headLimit = head - params .FullImmutabilityThreshold
117+ }
118+ if final == 0 && headLimit == 0 {
119+ return 0 , errors .New ("freezing threshold is not available" )
120+ }
121+ if final > headLimit {
122+ return final , nil
123+ }
124+ return headLimit , nil
125+ }
126+
80127// freeze is a background thread that periodically checks the blockchain for any
81128// import progress and moves ancient data from the fast database into the freezer.
82129//
@@ -114,60 +161,39 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
114161 return
115162 }
116163 }
117- // Retrieve the freezing threshold.
118- hash := ReadHeadBlockHash (nfdb )
119- if hash == (common.Hash {}) {
120- log .Debug ("Current full block hash unavailable" ) // new chain, empty database
164+ threshold , err := f .freezeThreshold (nfdb )
165+ if err != nil {
121166 backoff = true
167+ log .Debug ("Current full block not old enough to freeze" , "err" , err )
122168 continue
123169 }
124- number := ReadHeaderNumber (nfdb , hash )
125- threshold := f .threshold .Load ()
126170 frozen := f .frozen .Load ()
127- switch {
128- case number == nil :
129- log .Error ("Current full block number unavailable" , "hash" , hash )
130- backoff = true
131- continue
132171
133- case * number < threshold :
134- log .Debug ("Current full block not old enough to freeze" , "number" , * number , "hash" , hash , "delay" , threshold )
135- backoff = true
136- continue
137-
138- case * number - threshold <= frozen :
139- log .Debug ("Ancient blocks frozen already" , "number" , * number , "hash" , hash , "frozen" , frozen )
172+ // Short circuit if the blocks below threshold are already frozen.
173+ if frozen != 0 && frozen - 1 >= threshold {
140174 backoff = true
175+ log .Debug ("Ancient blocks frozen already" , "threshold" , threshold , "frozen" , frozen )
141176 continue
142177 }
143- head := ReadHeader (nfdb , hash , * number )
144- if head == nil {
145- log .Error ("Current full block unavailable" , "number" , * number , "hash" , hash )
146- backoff = true
147- continue
148- }
149-
150178 // Seems we have data ready to be frozen, process in usable batches
151179 var (
152- start = time .Now ()
153- first , _ = f . Ancients ()
154- limit = * number - threshold
180+ start = time .Now ()
181+ first = frozen // the first block to freeze
182+ last = threshold // the last block to freeze
155183 )
156- if limit - first > freezerBatchLimit {
157- limit = first + freezerBatchLimit
184+ if last - first + 1 > freezerBatchLimit {
185+ last = freezerBatchLimit + first - 1
158186 }
159- ancients , err := f .freezeRange (nfdb , first , limit )
187+ ancients , err := f .freezeRange (nfdb , first , last )
160188 if err != nil {
161189 log .Error ("Error in block freeze operation" , "err" , err )
162190 backoff = true
163191 continue
164192 }
165-
166193 // Batch of blocks have been frozen, flush them before wiping from leveldb
167194 if err := f .Sync (); err != nil {
168195 log .Crit ("Failed to flush frozen tables" , "err" , err )
169196 }
170-
171197 // Wipe out all data from the active database
172198 batch := db .NewBatch ()
173199 for i := 0 ; i < len (ancients ); i ++ {
@@ -250,8 +276,11 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
250276 }
251277}
252278
279+ // freezeRange moves a batch of chain segments from the fast database to the freezer.
280+ // The parameters (number, limit) specify the relevant block range, both of which
281+ // are included.
253282func (f * chainFreezer ) freezeRange (nfdb * nofreezedb , number , limit uint64 ) (hashes []common.Hash , err error ) {
254- hashes = make ([]common.Hash , 0 , limit - number )
283+ hashes = make ([]common.Hash , 0 , limit - number + 1 )
255284
256285 _ , err = f .ModifyAncients (func (op ethdb.AncientWriteOp ) error {
257286 for ; number <= limit ; number ++ {
@@ -293,11 +322,9 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
293322 if err := op .AppendRaw (ChainFreezerDifficultyTable , number , td ); err != nil {
294323 return fmt .Errorf ("can't write td to Freezer: %v" , err )
295324 }
296-
297325 hashes = append (hashes , hash )
298326 }
299327 return nil
300328 })
301-
302329 return hashes , err
303330}
0 commit comments