1717package rawdb_test
1818
1919import (
20+ "bytes"
2021 "fmt"
2122
2223 "github.com/ava-labs/libevm/common"
2324 // To ensure that all methods are available to importing packages, this test
2425 // is defined in package `rawdb_test` instead of `rawdb`.
2526 "github.com/ava-labs/libevm/core/rawdb"
27+ "github.com/ava-labs/libevm/ethdb"
2628)
2729
2830// ExampleDatabaseStat demonstrates the method signatures of DatabaseStat, which
@@ -42,3 +44,145 @@ func ExampleDatabaseStat() {
4244 // Sum: 7.00 B
4345 // Count: 4
4446}
47+
48+ func ExampleInspectDatabase () {
49+ db := & stubDatabase {
50+ iterator : & stubIterator {
51+ i : - 1 ,
52+ kvs : []keyValue {
53+ // Bloom bits total = 5 + 1 = 6
54+ {key : []byte ("iBxxx" ), value : []byte ("m" )},
55+ // Optional stat record total = 5 + 7 = 12
56+ {key : []byte ("mykey" ), value : []byte ("myvalue" )},
57+ // metadata total = 13 + 7 = 20
58+ {key : []byte ("mymetadatakey" ), value : []byte ("myvalue" )},
59+ },
60+ },
61+ }
62+
63+ keyPrefix := []byte (nil )
64+ keyStart := []byte (nil )
65+
66+ var (
67+ myStat rawdb.DatabaseStat
68+ )
69+ options := []rawdb.InspectDatabaseOption {
70+ rawdb .WithDatabaseStatRecorder (func (key []byte , size common.StorageSize ) bool {
71+ if bytes .Equal (key , []byte ("mykey" )) {
72+ myStat .Add (size )
73+ return true
74+ }
75+ return false
76+ }),
77+ rawdb .WithDatabaseMetadataKeys (func (key []byte ) bool {
78+ return bytes .Equal (key , []byte ("mymetadatakey" ))
79+ }),
80+ rawdb .WithDatabaseStatsTransformer (func (s [][]string ) [][]string {
81+ var modified [][]string
82+ // Remove lines
83+ for _ , line := range s {
84+ database , category := line [0 ], line [1 ]
85+ switch {
86+ case database == "Ancient store (Chain)" :
87+ case database == "Key-Value store" && category == "Difficulties" :
88+ default :
89+ modified = append (modified , line )
90+ }
91+ }
92+ // Add lines for data collected with [rawdb.WithDatabaseStatRecorder]
93+ line := []string {"My database" , "My category" , myStat .Size (), myStat .Count ()}
94+ modified = append (modified , line )
95+ return modified
96+ }),
97+ }
98+
99+ err := rawdb .InspectDatabase (db , keyPrefix , keyStart , options ... )
100+ if err != nil {
101+ fmt .Println (err )
102+ }
103+ // Output:
104+ // +-----------------+-------------------------+---------+-------+
105+ // | DATABASE | CATEGORY | SIZE | ITEMS |
106+ // +-----------------+-------------------------+---------+-------+
107+ // | Key-Value store | Headers | 0.00 B | 0 |
108+ // | Key-Value store | Bodies | 0.00 B | 0 |
109+ // | Key-Value store | Receipt lists | 0.00 B | 0 |
110+ // | Key-Value store | Block number->hash | 0.00 B | 0 |
111+ // | Key-Value store | Block hash->number | 0.00 B | 0 |
112+ // | Key-Value store | Transaction index | 0.00 B | 0 |
113+ // | Key-Value store | Bloombit index | 6.00 B | 1 |
114+ // | Key-Value store | Contract codes | 0.00 B | 0 |
115+ // | Key-Value store | Hash trie nodes | 0.00 B | 0 |
116+ // | Key-Value store | Path trie state lookups | 0.00 B | 0 |
117+ // | Key-Value store | Path trie account nodes | 0.00 B | 0 |
118+ // | Key-Value store | Path trie storage nodes | 0.00 B | 0 |
119+ // | Key-Value store | Trie preimages | 0.00 B | 0 |
120+ // | Key-Value store | Account snapshot | 0.00 B | 0 |
121+ // | Key-Value store | Storage snapshot | 0.00 B | 0 |
122+ // | Key-Value store | Beacon sync headers | 0.00 B | 0 |
123+ // | Key-Value store | Clique snapshots | 0.00 B | 0 |
124+ // | Key-Value store | Singleton metadata | 20.00 B | 1 |
125+ // | Light client | CHT trie nodes | 0.00 B | 0 |
126+ // | Light client | Bloom trie nodes | 0.00 B | 0 |
127+ // | My database | My category | 12.00 B | 1 |
128+ // +-----------------+-------------------------+---------+-------+
129+ // | TOTAL | 38.00 B | |
130+ // +-----------------+-------------------------+---------+-------+
131+ }
132+
133+ type stubDatabase struct {
134+ ethdb.Database
135+ iterator ethdb.Iterator
136+ }
137+
138+ func (s * stubDatabase ) NewIterator (keyPrefix , keyStart []byte ) ethdb.Iterator {
139+ return s .iterator
140+ }
141+
142+ // AncientSize is used in [InspectDatabase] to determine the ancient sizes.
143+ func (s * stubDatabase ) AncientSize (kind string ) (uint64 , error ) {
144+ return 0 , nil
145+ }
146+
147+ func (s * stubDatabase ) Ancients () (uint64 , error ) {
148+ return 0 , nil
149+ }
150+
151+ func (s * stubDatabase ) Tail () (uint64 , error ) {
152+ return 0 , nil
153+ }
154+
155+ func (s * stubDatabase ) Get (key []byte ) ([]byte , error ) {
156+ return nil , nil
157+ }
158+
159+ func (s * stubDatabase ) ReadAncients (fn func (ethdb.AncientReaderOp ) error ) (err error ) {
160+ return nil
161+ }
162+
163+ type stubIterator struct {
164+ ethdb.Iterator
165+ i int
166+ kvs []keyValue
167+ }
168+
169+ type keyValue struct {
170+ key []byte
171+ value []byte
172+ }
173+
174+ func (s * stubIterator ) Next () bool {
175+ s .i ++
176+ available := s .i < len (s .kvs )
177+ return available
178+ }
179+
180+ func (s * stubIterator ) Release () {}
181+
182+ func (s * stubIterator ) Key () []byte {
183+ return s .kvs [s .i ].key
184+ }
185+
186+ func (s * stubIterator ) Value () []byte {
187+ return s .kvs [s .i ].value
188+ }
0 commit comments