github.com/koko1123/flow-go-1@v0.29.6/cmd/util/ledger/reporters/atree_reporter.go (about) 1 package reporters 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 goRuntime "runtime" 8 "sync" 9 10 "github.com/onflow/atree" 11 12 fvmState "github.com/koko1123/flow-go-1/fvm/state" 13 "github.com/koko1123/flow-go-1/ledger" 14 15 "github.com/rs/zerolog" 16 "github.com/schollz/progressbar/v3" 17 ) 18 19 // AtreeReporter iterates payloads and generates payload and atree stats. 20 type AtreeReporter struct { 21 Log zerolog.Logger 22 RWF ReportWriterFactory 23 } 24 25 var _ ledger.Reporter = &AtreeReporter{} 26 27 func (r *AtreeReporter) Name() string { 28 return "Atree Reporter" 29 } 30 31 func (r *AtreeReporter) Report(payloads []ledger.Payload, commit ledger.State) error { 32 rwa := r.RWF.ReportWriter("atree_report") 33 defer rwa.Close() 34 35 progress := progressbar.Default(int64(len(payloads)), "Processing:") 36 37 workerCount := goRuntime.NumCPU() / 2 38 if workerCount == 0 { 39 workerCount = 1 40 } 41 42 jobs := make(chan *ledger.Payload, workerCount) 43 44 results := make(chan payloadStats, workerCount) 45 defer close(results) 46 47 // create multiple workers to process payloads concurrently 48 wg := &sync.WaitGroup{} 49 wg.Add(workerCount) 50 51 for i := 0; i < workerCount; i++ { 52 go func() { 53 defer wg.Done() 54 55 var stats payloadStats 56 for p := range jobs { 57 err := stats.process(p) 58 if err != nil { 59 k, keyErr := p.Key() 60 if keyErr != nil { 61 r.Log.Err(keyErr).Msg("failed to get payload key") 62 } else { 63 r.Log.Err(err).Msgf("failed to process payload %s", k.String()) 64 } 65 } 66 } 67 results <- stats 68 }() 69 } 70 71 // produce jobs for workers to process 72 for i := 0; i < len(payloads); i++ { 73 jobs <- &payloads[i] 74 75 err := progress.Add(1) 76 if err != nil { 77 panic(fmt.Errorf("progress.Add(1): %w", err)) 78 } 79 } 80 close(jobs) 81 82 // wait until all jobs are done 83 wg.Wait() 84 85 err := progress.Finish() 86 if err != nil { 87 panic(fmt.Errorf("progress.Finish(): %w", err)) 88 } 89 90 // aggregate all payload stats 91 var stats payloadStats 92 for i := 0; i < workerCount; i++ { 93 r := <-results 94 stats.add(&r) 95 } 96 97 rwa.Write(stats) 98 99 return nil 100 } 101 102 type payloadType uint 103 104 const ( 105 unknownPayloadType payloadType = iota 106 fvmPayloadType 107 storagePayloadType 108 slabPayloadType 109 ) 110 111 func getPayloadType(p *ledger.Payload) (payloadType, error) { 112 k, err := p.Key() 113 if err != nil { 114 return unknownPayloadType, err 115 } 116 if len(k.KeyParts) < 2 { 117 return unknownPayloadType, nil 118 } 119 if fvmState.IsFVMStateKey( 120 string(k.KeyParts[0].Value), 121 string(k.KeyParts[1].Value), 122 ) { 123 return fvmPayloadType, nil 124 } 125 if bytes.HasPrefix(k.KeyParts[1].Value, []byte(atree.LedgerBaseStorageSlabPrefix)) { 126 return slabPayloadType, nil 127 } 128 return storagePayloadType, nil 129 } 130 131 type slabPayloadStats struct { 132 SlabArrayMetaCount uint 133 SlabArrayDataCount uint 134 SlabMapMetaCount uint 135 SlabMapDataCount uint 136 SlabMapExternalCollisionCount uint 137 SlabStorableCount uint 138 SlabMapCollisionGroupCount uint 139 140 SlabMapCollisionCounts []uint 141 } 142 143 type payloadStats struct { 144 FVMPayloadCount uint 145 StoragePayloadCount uint 146 SlabPayloadCount uint 147 slabPayloadStats 148 } 149 150 func (s *payloadStats) add(s1 *payloadStats) { 151 s.FVMPayloadCount += s1.FVMPayloadCount 152 s.StoragePayloadCount += s1.StoragePayloadCount 153 s.SlabPayloadCount += s1.SlabPayloadCount 154 s.SlabArrayMetaCount += s1.SlabArrayMetaCount 155 s.SlabArrayDataCount += s1.SlabArrayDataCount 156 s.SlabMapMetaCount += s1.SlabMapMetaCount 157 s.SlabMapDataCount += s1.SlabMapDataCount 158 s.SlabMapExternalCollisionCount += s1.SlabMapExternalCollisionCount 159 s.SlabStorableCount += s1.SlabStorableCount 160 s.SlabMapCollisionGroupCount += s1.SlabMapCollisionGroupCount 161 162 if len(s1.SlabMapCollisionCounts) > 0 { 163 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, s1.SlabMapCollisionCounts...) 164 } 165 } 166 167 func (s *payloadStats) process(p *ledger.Payload) error { 168 pt, err := getPayloadType(p) 169 if err != nil { 170 return err 171 } 172 switch pt { 173 case unknownPayloadType: 174 return fmt.Errorf("unknown payload: %s", p.String()) 175 case fvmPayloadType: 176 s.FVMPayloadCount++ 177 case storagePayloadType: 178 s.StoragePayloadCount++ 179 case slabPayloadType: 180 s.SlabPayloadCount++ 181 } 182 183 if pt != slabPayloadType { 184 return nil 185 } 186 187 if len(p.Value()) < versionAndFlagSize { 188 return errors.New("data is too short") 189 } 190 191 flag := p.Value()[flagIndex] 192 193 switch dataType := getSlabType(flag); dataType { 194 case slabArray: 195 switch arrayDataType := getSlabArrayType(flag); arrayDataType { 196 case slabArrayData: 197 s.SlabArrayDataCount++ 198 199 case slabArrayMeta: 200 s.SlabArrayMetaCount++ 201 202 default: 203 return fmt.Errorf("slab array has invalid flag 0x%x", flag) 204 } 205 206 case slabMap: 207 switch mapDataType := getSlabMapType(flag); mapDataType { 208 case slabMapData: 209 _, collisionGroupCount, err := getCollisionGroupCountFromSlabMapData(p.Value()) 210 if err != nil { 211 return err 212 } 213 if collisionGroupCount > 0 { 214 _, inlineCollisionCount, err := getInlineCollisionCountsFromSlabMapData(p.Value()) 215 if err != nil { 216 return err 217 } 218 if len(inlineCollisionCount) > 0 { 219 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, inlineCollisionCount...) 220 } 221 } 222 s.SlabMapCollisionGroupCount += collisionGroupCount 223 s.SlabMapDataCount++ 224 225 case slabMapCollisionGroup: 226 elements, err := parseSlabMapData(p.Value()) 227 if err != nil { 228 return err 229 } 230 _, rawElements, err := parseRawElements(elements, decMode) 231 if err != nil { 232 return err 233 } 234 if len(rawElements) > 0 { 235 s.SlabMapCollisionCounts = append(s.SlabMapCollisionCounts, uint(len(rawElements))) 236 } 237 s.SlabMapExternalCollisionCount++ 238 239 case slabMapMeta: 240 s.SlabMapMetaCount++ 241 242 default: 243 return fmt.Errorf("slab map has invalid flag 0x%x", flag) 244 } 245 246 case slabStorable: 247 s.SlabStorableCount++ 248 249 default: 250 return fmt.Errorf("slab data has invalid flag 0x%x", flag) 251 } 252 253 return nil 254 }