@@ -82,11 +82,6 @@ var Defaults = &Config{
82
82
// Database is an intermediate write layer between the trie data structures and
83
83
// the disk database. The aim is to accumulate trie writes in-memory and only
84
84
// periodically flush a couple tries to disk, garbage collecting the remainder.
85
- //
86
- // Note, the trie Database is **not** thread safe in its mutations, but it **is**
87
- // thread safe in providing individual, independent node access. The rationale
88
- // behind this split design is to provide read access to RPC handlers and sync
89
- // servers even while the trie is executing expensive garbage collection.
90
85
type Database struct {
91
86
diskdb ethdb.Database // Persistent storage for matured trie nodes
92
87
resolver ChildResolver // The handler to resolve children of nodes
@@ -113,7 +108,7 @@ type Database struct {
113
108
// cachedNode is all the information we know about a single cached trie node
114
109
// in the memory database write layer.
115
110
type cachedNode struct {
116
- node []byte // Encoded node blob
111
+ node []byte // Encoded node blob, immutable
117
112
parents uint32 // Number of live nodes referencing this one
118
113
external map [common.Hash ]struct {} // The set of external children
119
114
flushPrev common.Hash // Previous node in the flush-list
@@ -152,9 +147,9 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas
152
147
}
153
148
}
154
149
155
- // insert inserts a simplified trie node into the memory database.
156
- // All nodes inserted by this function will be reference tracked
157
- // and in theory should only used for **trie nodes** insertion .
150
+ // insert inserts a trie node into the memory database. All nodes inserted by
151
+ // this function will be reference tracked. This function assumes the lock is
152
+ // already held .
158
153
func (db * Database ) insert (hash common.Hash , node []byte ) {
159
154
// If the node's already cached, skip
160
155
if _ , ok := db .dirties [hash ]; ok {
@@ -183,9 +178,9 @@ func (db *Database) insert(hash common.Hash, node []byte) {
183
178
db .dirtiesSize += common .StorageSize (common .HashLength + len (node ))
184
179
}
185
180
186
- // Node retrieves an encoded cached trie node from memory. If it cannot be found
181
+ // node retrieves an encoded cached trie node from memory. If it cannot be found
187
182
// cached, the method queries the persistent database for the content.
188
- func (db * Database ) Node (hash common.Hash ) ([]byte , error ) {
183
+ func (db * Database ) node (hash common.Hash ) ([]byte , error ) {
189
184
// It doesn't make sense to retrieve the metaroot
190
185
if hash == (common.Hash {}) {
191
186
return nil , errors .New ("not found" )
@@ -198,11 +193,14 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) {
198
193
return enc , nil
199
194
}
200
195
}
201
- // Retrieve the node from the dirty cache if available
196
+ // Retrieve the node from the dirty cache if available.
202
197
db .lock .RLock ()
203
198
dirty := db .dirties [hash ]
204
199
db .lock .RUnlock ()
205
200
201
+ // Return the cached node if it's found in the dirty set.
202
+ // The dirty.node field is immutable and safe to read it
203
+ // even without lock guard.
206
204
if dirty != nil {
207
205
memcacheDirtyHitMeter .Mark (1 )
208
206
memcacheDirtyReadMeter .Mark (int64 (len (dirty .node )))
@@ -223,20 +221,6 @@ func (db *Database) Node(hash common.Hash) ([]byte, error) {
223
221
return nil , errors .New ("not found" )
224
222
}
225
223
226
- // Nodes retrieves the hashes of all the nodes cached within the memory database.
227
- // This method is extremely expensive and should only be used to validate internal
228
- // states in test code.
229
- func (db * Database ) Nodes () []common.Hash {
230
- db .lock .RLock ()
231
- defer db .lock .RUnlock ()
232
-
233
- var hashes = make ([]common.Hash , 0 , len (db .dirties ))
234
- for hash := range db .dirties {
235
- hashes = append (hashes , hash )
236
- }
237
- return hashes
238
- }
239
-
240
224
// Reference adds a new reference from a parent node to a child node.
241
225
// This function is used to add reference between internal trie node
242
226
// and external node(e.g. storage trie root), all internal trie nodes
@@ -344,16 +328,16 @@ func (db *Database) dereference(hash common.Hash) {
344
328
345
329
// Cap iteratively flushes old but still referenced trie nodes until the total
346
330
// memory usage goes below the given threshold.
347
- //
348
- // Note, this method is a non-synchronized mutator. It is unsafe to call this
349
- // concurrently with other mutators.
350
331
func (db * Database ) Cap (limit common.StorageSize ) error {
332
+ db .lock .Lock ()
333
+ defer db .lock .Unlock ()
334
+
351
335
// Create a database batch to flush persistent data out. It is important that
352
336
// outside code doesn't see an inconsistent state (referenced data removed from
353
337
// memory cache during commit but not yet in persistent storage). This is ensured
354
338
// by only uncaching existing data when the database write finalizes.
355
- nodes , storage , start := len (db .dirties ), db .dirtiesSize , time .Now ()
356
339
batch := db .diskdb .NewBatch ()
340
+ nodes , storage , start := len (db .dirties ), db .dirtiesSize , time .Now ()
357
341
358
342
// db.dirtiesSize only contains the useful data in the cache, but when reporting
359
343
// the total memory consumption, the maintenance metadata is also needed to be
@@ -391,9 +375,6 @@ func (db *Database) Cap(limit common.StorageSize) error {
391
375
return err
392
376
}
393
377
// Write successful, clear out the flushed data
394
- db .lock .Lock ()
395
- defer db .lock .Unlock ()
396
-
397
378
for db .oldest != oldest {
398
379
node := db .dirties [db .oldest ]
399
380
delete (db .dirties , db .oldest )
@@ -424,10 +405,10 @@ func (db *Database) Cap(limit common.StorageSize) error {
424
405
// Commit iterates over all the children of a particular node, writes them out
425
406
// to disk, forcefully tearing down all references in both directions. As a side
426
407
// effect, all pre-images accumulated up to this point are also written.
427
- //
428
- // Note, this method is a non-synchronized mutator. It is unsafe to call this
429
- // concurrently with other mutators.
430
408
func (db * Database ) Commit (node common.Hash , report bool ) error {
409
+ db .lock .Lock ()
410
+ defer db .lock .Unlock ()
411
+
431
412
// Create a database batch to flush persistent data out. It is important that
432
413
// outside code doesn't see an inconsistent state (referenced data removed from
433
414
// memory cache during commit but not yet in persistent storage). This is ensured
@@ -449,8 +430,6 @@ func (db *Database) Commit(node common.Hash, report bool) error {
449
430
return err
450
431
}
451
432
// Uncache any leftovers in the last batch
452
- db .lock .Lock ()
453
- defer db .lock .Unlock ()
454
433
if err := batch .Replay (uncacher ); err != nil {
455
434
return err
456
435
}
@@ -499,13 +478,11 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane
499
478
if err := batch .Write (); err != nil {
500
479
return err
501
480
}
502
- db .lock .Lock ()
503
481
err := batch .Replay (uncacher )
504
- batch .Reset ()
505
- db .lock .Unlock ()
506
482
if err != nil {
507
483
return err
508
484
}
485
+ batch .Reset ()
509
486
}
510
487
return nil
511
488
}
@@ -574,7 +551,7 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {
574
551
func (db * Database ) Update (root common.Hash , parent common.Hash , block uint64 , nodes * trienode.MergedNodeSet , states * triestate.Set ) error {
575
552
// Ensure the parent state is present and signal a warning if not.
576
553
if parent != types .EmptyRootHash {
577
- if blob , _ := db .Node (parent ); len (blob ) == 0 {
554
+ if blob , _ := db .node (parent ); len (blob ) == 0 {
578
555
log .Error ("parent state is not present" )
579
556
}
580
557
}
@@ -655,7 +632,7 @@ func (db *Database) Scheme() string {
655
632
// Reader retrieves a node reader belonging to the given state root.
656
633
// An error will be returned if the requested state is not available.
657
634
func (db * Database ) Reader (root common.Hash ) (* reader , error ) {
658
- if _ , err := db .Node (root ); err != nil {
635
+ if _ , err := db .node (root ); err != nil {
659
636
return nil , fmt .Errorf ("state %#x is not available, %v" , root , err )
660
637
}
661
638
return & reader {db : db }, nil
@@ -666,9 +643,9 @@ type reader struct {
666
643
db * Database
667
644
}
668
645
669
- // Node retrieves the trie node with the given node hash.
670
- // No error will be returned if the node is not found.
646
+ // Node retrieves the trie node with the given node hash. No error will be
647
+ // returned if the node is not found.
671
648
func (reader * reader ) Node (owner common.Hash , path []byte , hash common.Hash ) ([]byte , error ) {
672
- blob , _ := reader .db .Node (hash )
649
+ blob , _ := reader .db .node (hash )
673
650
return blob , nil
674
651
}
0 commit comments