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  }