@@ -19,6 +19,7 @@ package state
19
19
import (
20
20
"errors"
21
21
"sync"
22
+ "sync/atomic"
22
23
23
24
"github.com/ethereum/go-ethereum/common"
24
25
"github.com/ethereum/go-ethereum/common/lru"
@@ -82,6 +83,20 @@ type Reader interface {
82
83
StateReader
83
84
}
84
85
86
+ // ReaderStats wraps the statistics of reader.
87
+ type ReaderStats struct {
88
+ AccountHit int64
89
+ AccountMiss int64
90
+ StorageHit int64
91
+ StorageMiss int64
92
+ }
93
+
94
+ // ReaderWithStats wraps the additional method to retrieve the reader statistics from.
95
+ type ReaderWithStats interface {
96
+ Reader
97
+ GetStats () ReaderStats
98
+ }
99
+
85
100
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
86
101
// local key-value store or the shared code cache.
87
102
//
@@ -414,35 +429,43 @@ func newReaderWithCache(reader Reader) *readerWithCache {
414
429
return r
415
430
}
416
431
417
- // Account implements StateReader, retrieving the account specified by the address.
418
- // The returned account might be nil if it's not existent.
432
+ // account retrieves the account specified by the address along with a flag
433
+ // indicating whether it's found in the cache or not. The returned account
434
+ // might be nil if it's not existent.
419
435
//
420
436
// An error will be returned if the state is corrupted in the underlying reader.
421
- func (r * readerWithCache ) Account (addr common.Address ) (* types.StateAccount , error ) {
437
+ func (r * readerWithCache ) account (addr common.Address ) (* types.StateAccount , bool , error ) {
422
438
// Try to resolve the requested account in the local cache
423
439
r .accountLock .RLock ()
424
440
acct , ok := r .accounts [addr ]
425
441
r .accountLock .RUnlock ()
426
442
if ok {
427
- return acct , nil
443
+ return acct , true , nil
428
444
}
429
445
// Try to resolve the requested account from the underlying reader
430
446
acct , err := r .Reader .Account (addr )
431
447
if err != nil {
432
- return nil , err
448
+ return nil , false , err
433
449
}
434
450
r .accountLock .Lock ()
435
451
r .accounts [addr ] = acct
436
452
r .accountLock .Unlock ()
437
- return acct , nil
453
+ return acct , false , nil
438
454
}
439
455
440
- // Storage implements StateReader, retrieving the storage slot specified by the
441
- // address and slot key. The returned storage slot might be empty if it's not
442
- // existent.
456
+ // Account implements StateReader, retrieving the account specified by the address.
457
+ // The returned account might be nil if it's not existent.
443
458
//
444
459
// An error will be returned if the state is corrupted in the underlying reader.
445
- func (r * readerWithCache ) Storage (addr common.Address , slot common.Hash ) (common.Hash , error ) {
460
+ func (r * readerWithCache ) Account (addr common.Address ) (* types.StateAccount , error ) {
461
+ account , _ , err := r .account (addr )
462
+ return account , err
463
+ }
464
+
465
+ // storage retrieves the storage slot specified by the address and slot key, along
466
+ // with a flag indicating whether it's found in the cache or not. The returned
467
+ // storage slot might be empty if it's not existent.
468
+ func (r * readerWithCache ) storage (addr common.Address , slot common.Hash ) (common.Hash , bool , error ) {
446
469
var (
447
470
value common.Hash
448
471
ok bool
@@ -456,12 +479,12 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common
456
479
}
457
480
bucket .lock .RUnlock ()
458
481
if ok {
459
- return value , nil
482
+ return value , true , nil
460
483
}
461
484
// Try to resolve the requested storage slot from the underlying reader
462
485
value , err := r .Reader .Storage (addr , slot )
463
486
if err != nil {
464
- return common.Hash {}, err
487
+ return common.Hash {}, false , err
465
488
}
466
489
bucket .lock .Lock ()
467
490
slots , ok = bucket .storages [addr ]
@@ -472,5 +495,75 @@ func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common
472
495
slots [slot ] = value
473
496
bucket .lock .Unlock ()
474
497
498
+ return value , false , nil
499
+ }
500
+
501
+ // Storage implements StateReader, retrieving the storage slot specified by the
502
+ // address and slot key. The returned storage slot might be empty if it's not
503
+ // existent.
504
+ //
505
+ // An error will be returned if the state is corrupted in the underlying reader.
506
+ func (r * readerWithCache ) Storage (addr common.Address , slot common.Hash ) (common.Hash , error ) {
507
+ value , _ , err := r .storage (addr , slot )
508
+ return value , err
509
+ }
510
+
511
+ type readerWithCacheStats struct {
512
+ * readerWithCache
513
+ accountHit atomic.Int64
514
+ accountMiss atomic.Int64
515
+ storageHit atomic.Int64
516
+ storageMiss atomic.Int64
517
+ }
518
+
519
+ // newReaderWithCacheStats constructs the reader with additional statistics tracked.
520
+ func newReaderWithCacheStats (reader * readerWithCache ) * readerWithCacheStats {
521
+ return & readerWithCacheStats {
522
+ readerWithCache : reader ,
523
+ }
524
+ }
525
+
526
+ // Account implements StateReader, retrieving the account specified by the address.
527
+ // The returned account might be nil if it's not existent.
528
+ //
529
+ // An error will be returned if the state is corrupted in the underlying reader.
530
+ func (r * readerWithCacheStats ) Account (addr common.Address ) (* types.StateAccount , error ) {
531
+ account , incache , err := r .readerWithCache .account (addr )
532
+ if err != nil {
533
+ return nil , err
534
+ }
535
+ if incache {
536
+ r .accountHit .Add (1 )
537
+ } else {
538
+ r .accountMiss .Add (1 )
539
+ }
540
+ return account , nil
541
+ }
542
+
543
+ // Storage implements StateReader, retrieving the storage slot specified by the
544
+ // address and slot key. The returned storage slot might be empty if it's not
545
+ // existent.
546
+ //
547
+ // An error will be returned if the state is corrupted in the underlying reader.
548
+ func (r * readerWithCacheStats ) Storage (addr common.Address , slot common.Hash ) (common.Hash , error ) {
549
+ value , incache , err := r .readerWithCache .storage (addr , slot )
550
+ if err != nil {
551
+ return common.Hash {}, err
552
+ }
553
+ if incache {
554
+ r .storageHit .Add (1 )
555
+ } else {
556
+ r .storageMiss .Add (1 )
557
+ }
475
558
return value , nil
476
559
}
560
+
561
+ // GetStats implements ReaderWithStats, returning the statistics of state reader.
562
+ func (r * readerWithCacheStats ) GetStats () ReaderStats {
563
+ return ReaderStats {
564
+ AccountHit : r .accountHit .Load (),
565
+ AccountMiss : r .accountMiss .Load (),
566
+ StorageHit : r .storageHit .Load (),
567
+ StorageMiss : r .storageMiss .Load (),
568
+ }
569
+ }
0 commit comments