@@ -44,10 +44,12 @@ type Fetcher interface {
4444type Fsck struct {
4545 origin string
4646 verifier note.Verifier
47- fetcher Fetcher
47+ fetcher * countingFetcher
4848 bundleHasher func ([]byte ) ([][]byte , error )
4949 rangeTracker * rangeTracker
5050 opts Opts
51+
52+ fsckTree * fsckTree
5153}
5254
5355type Opts struct {
@@ -72,13 +74,15 @@ func New(origin string, verifier note.Verifier, f Fetcher, bundleHasher func([]b
7274 return & Fsck {
7375 origin : origin ,
7476 verifier : verifier ,
75- fetcher : f ,
77+ fetcher : newCountingFetcher ( f ) ,
7678 opts : opts ,
7779 bundleHasher : bundleHasher ,
7880 }
7981}
8082
8183// Check performs an integrity check against the log.
84+ //
85+ // Check may only be called once per instance of Fsck.
8286func (f * Fsck ) Check (ctx context.Context ) error {
8387 cp , cpRaw , _ , err := client .FetchCheckpoint (ctx , f .fetcher .ReadCheckpoint , f .verifier , f .origin )
8488 if err != nil {
@@ -90,7 +94,7 @@ func (f *Fsck) Check(ctx context.Context) error {
9094
9195 f .rangeTracker = newRangeTracker (cp .Size )
9296
93- fTree := fsckTree {
97+ f . fsckTree = & fsckTree {
9498 fetcher : f .fetcher ,
9599 bundleHasher : f .bundleHasher ,
96100 tree : (& compact.RangeFactory {Hash : rfc6962 .DefaultHasher .HashChildren }).NewEmptyRange (0 ),
@@ -106,17 +110,17 @@ func (f *Fsck) Check(ctx context.Context) error {
106110
107111 // Kick off resource comparing workers
108112 for range f .opts .N {
109- eg .Go (fTree .resourceCheckWorker (ctx ))
113+ eg .Go (f . fsckTree .resourceCheckWorker (ctx ))
110114 }
111115
112116 trackBundle := func (ctx context.Context , idx uint64 , p uint8 ) ([]byte , error ) {
113- fTree .rangeTracker .Update (- 1 , idx , Fetching )
117+ f . fsckTree .rangeTracker .Update (- 1 , idx , Fetching )
114118 r , err := f .fetcher .ReadEntryBundle (ctx , idx , p )
115119 if err != nil {
116- fTree .rangeTracker .Update (- 1 , idx , FetchError )
120+ f . fsckTree .rangeTracker .Update (- 1 , idx , FetchError )
117121 return nil , err
118122 }
119- fTree .rangeTracker .Update (- 1 , idx , Fetched )
123+ f . fsckTree .rangeTracker .Update (- 1 , idx , Fetched )
120124 return r , nil
121125 }
122126
@@ -127,27 +131,27 @@ func (f *Fsck) Check(ctx context.Context) error {
127131 if err != nil {
128132 return fmt .Errorf ("error while streaming bundles: %v" , err )
129133 }
130- fTree .rangeTracker .Update (- 1 , b .RangeInfo .Index , OK )
131- if err := fTree .AppendBundle (b .RangeInfo , b .Data ); err != nil {
134+ f . fsckTree .rangeTracker .Update (- 1 , b .RangeInfo .Index , OK )
135+ if err := f . fsckTree .AppendBundle (b .RangeInfo , b .Data ); err != nil {
132136 return fmt .Errorf ("failure calling AppendBundle(%v): %v" , b .RangeInfo , err )
133137 }
134- if fTree .tree .End () >= cp .Size {
138+ if f . fsckTree .tree .End () >= cp .Size {
135139 break
136140 }
137141 }
138142
139143 // Ensure we see process any partial tiles too.
140- fTree .flushPartialTiles ()
144+ f . fsckTree .flushPartialTiles ()
141145 // Signal that there will be no more resource checking jobs coming so workers can exit when the channel is drained.
142- close (fTree .expectedResources )
146+ close (f . fsckTree .expectedResources )
143147
144148 // Wait for all the work to be done.
145149 if err := eg .Wait (); err != nil {
146150 return fmt .Errorf ("failed: %v" , err )
147151 }
148152
149153 // Finally, check that the claimed root hash matches what we calculated.
150- gotRoot , err := fTree .GetRootHash ()
154+ gotRoot , err := f . fsckTree .GetRootHash ()
151155 switch {
152156 case err != nil :
153157 return fmt .Errorf ("failed to calculate root: %v" , err )
@@ -160,19 +164,34 @@ func (f *Fsck) Check(ctx context.Context) error {
160164 return nil
161165}
162166
167+ // Status represents the current status of an ongoing fsck check.
163168type Status struct {
169+ // EntryRanges describes the status of the entrybundles in the target log.
164170 EntryRanges []Range
165- TileRanges [][]Range
171+ // TileRanges describes the status of the tiles in the target log.
172+ // The zeroth entry in the slice represents the lower-most tile level, just above the entry bundles.
173+ TileRanges [][]Range
174+
175+ // BytesFetched is the total number of bytes fetched from the target log since the last time Status() was called.
176+ BytesFetched uint64
177+ // ResourcesFetched is the total number of resources fetched from the target log since the last time Status() was called.
178+ ResourcesFetched uint64
179+ // ErrorsEncountered is the total number of errors encountered since the last time Status() was called.
180+ ErrorsEncountered uint64
166181}
167182
183+ // Status returns a struct representing the current status of the fsck operation.
168184func (f * Fsck ) Status () Status {
169185 if f .rangeTracker == nil {
170186 return Status {}
171187 }
172188 e , t := f .rangeTracker .Ranges ()
173189 r := Status {
174- EntryRanges : e ,
175- TileRanges : t ,
190+ EntryRanges : e ,
191+ TileRanges : t ,
192+ BytesFetched : f .fsckTree .fetcher .bytesFetched .Swap (0 ),
193+ ResourcesFetched : f .fsckTree .fetcher .resourcesFetched .Swap (0 ),
194+ ErrorsEncountered : f .fsckTree .fetcher .errorsEncountered .Swap (0 ),
176195 }
177196 return r
178197}
@@ -206,7 +225,7 @@ type resource struct {
206225// fsckTree represents the tree we're currently checking.
207226type fsckTree struct {
208227 // fetcher knows how to retrieve static tlog-tile resources.
209- fetcher Fetcher
228+ fetcher * countingFetcher
210229 // bundleHasher knows how to convert entry bundles into leaf hashes.
211230 bundleHasher func ([]byte ) ([][]byte , error )
212231 // tree contains the running state of the leaves we've appended so far.
@@ -332,3 +351,39 @@ func (f *fsckTree) resourceCheckWorker(ctx context.Context) func() error {
332351 return nil
333352 }
334353}
354+
355+ // countingFetcher is a Fetcher which keeps track of the total number of bytes and resources fetched.
356+ type countingFetcher struct {
357+ f Fetcher
358+ bytesFetched atomic.Uint64
359+ resourcesFetched atomic.Uint64
360+ errorsEncountered atomic.Uint64
361+ }
362+
363+ func newCountingFetcher (f Fetcher ) * countingFetcher {
364+ return & countingFetcher {
365+ f : f ,
366+ }
367+ }
368+
369+ func (c * countingFetcher ) count (r []byte , err error ) ([]byte , error ) {
370+ if err != nil {
371+ c .errorsEncountered .Add (1 )
372+ return nil , err
373+ }
374+ c .bytesFetched .Add (uint64 (len (r )))
375+ c .resourcesFetched .Add (1 )
376+ return r , nil
377+ }
378+
379+ func (c * countingFetcher ) ReadCheckpoint (ctx context.Context ) ([]byte , error ) {
380+ return c .count (c .f .ReadCheckpoint (ctx ))
381+ }
382+
383+ func (c * countingFetcher ) ReadEntryBundle (ctx context.Context , i uint64 , p uint8 ) ([]byte , error ) {
384+ return c .count (c .f .ReadEntryBundle (ctx , i , p ))
385+ }
386+
387+ func (c * countingFetcher ) ReadTile (ctx context.Context , l , i uint64 , p uint8 ) ([]byte , error ) {
388+ return c .count (c .f .ReadTile (ctx , l , i , p ))
389+ }
0 commit comments