17
17
package rawdb
18
18
19
19
import (
20
+ "errors"
20
21
"fmt"
21
22
"sync"
22
- "sync/atomic"
23
23
"time"
24
24
25
25
"github.com/ethereum/go-ethereum/common"
@@ -43,8 +43,6 @@ const (
43
43
// The background thread will keep moving ancient chain segments from key-value
44
44
// database to flat files for saving space on live database.
45
45
type chainFreezer struct {
46
- threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
47
-
48
46
* Freezer
49
47
quit chan struct {}
50
48
wg sync.WaitGroup
@@ -57,13 +55,11 @@ func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFre
57
55
if err != nil {
58
56
return nil , err
59
57
}
60
- cf := chainFreezer {
58
+ return & chainFreezer {
61
59
Freezer : freezer ,
62
60
quit : make (chan struct {}),
63
61
trigger : make (chan chan struct {}),
64
- }
65
- cf .threshold .Store (params .FullImmutabilityThreshold )
66
- return & cf , nil
62
+ }, nil
67
63
}
68
64
69
65
// Close closes the chain freezer instance and terminates the background thread.
@@ -77,6 +73,57 @@ func (f *chainFreezer) Close() error {
77
73
return f .Freezer .Close ()
78
74
}
79
75
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
+
80
127
// freeze is a background thread that periodically checks the blockchain for any
81
128
// import progress and moves ancient data from the fast database into the freezer.
82
129
//
@@ -114,60 +161,39 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
114
161
return
115
162
}
116
163
}
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 {
121
166
backoff = true
167
+ log .Debug ("Current full block not old enough to freeze" , "err" , err )
122
168
continue
123
169
}
124
- number := ReadHeaderNumber (nfdb , hash )
125
- threshold := f .threshold .Load ()
126
170
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
132
171
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 {
140
174
backoff = true
175
+ log .Debug ("Ancient blocks frozen already" , "threshold" , threshold , "frozen" , frozen )
141
176
continue
142
177
}
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
-
150
178
// Seems we have data ready to be frozen, process in usable batches
151
179
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
155
183
)
156
- if limit - first > freezerBatchLimit {
157
- limit = first + freezerBatchLimit
184
+ if last - first + 1 > freezerBatchLimit {
185
+ last = freezerBatchLimit + first - 1
158
186
}
159
- ancients , err := f .freezeRange (nfdb , first , limit )
187
+ ancients , err := f .freezeRange (nfdb , first , last )
160
188
if err != nil {
161
189
log .Error ("Error in block freeze operation" , "err" , err )
162
190
backoff = true
163
191
continue
164
192
}
165
-
166
193
// Batch of blocks have been frozen, flush them before wiping from leveldb
167
194
if err := f .Sync (); err != nil {
168
195
log .Crit ("Failed to flush frozen tables" , "err" , err )
169
196
}
170
-
171
197
// Wipe out all data from the active database
172
198
batch := db .NewBatch ()
173
199
for i := 0 ; i < len (ancients ); i ++ {
@@ -250,8 +276,11 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
250
276
}
251
277
}
252
278
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.
253
282
func (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 )
255
284
256
285
_ , err = f .ModifyAncients (func (op ethdb.AncientWriteOp ) error {
257
286
for ; number <= limit ; number ++ {
@@ -293,11 +322,9 @@ func (f *chainFreezer) freezeRange(nfdb *nofreezedb, number, limit uint64) (hash
293
322
if err := op .AppendRaw (ChainFreezerDifficultyTable , number , td ); err != nil {
294
323
return fmt .Errorf ("can't write td to Freezer: %v" , err )
295
324
}
296
-
297
325
hashes = append (hashes , hash )
298
326
}
299
327
return nil
300
328
})
301
-
302
329
return hashes , err
303
330
}
0 commit comments