github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/topicsdb/thread_pool.go (about)

     1  package topicsdb
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/unicornultrafoundation/go-helios/native/idx"
     8  	"github.com/unicornultrafoundation/go-u2u/common"
     9  	"github.com/unicornultrafoundation/go-u2u/core/types"
    10  
    11  	"github.com/unicornultrafoundation/go-u2u/utils/dbutil/threads"
    12  )
    13  
    14  // withThreadPool wraps the index and limits its threads in use
    15  type withThreadPool struct {
    16  	*index
    17  }
    18  
    19  // FindInBlocks returns all log records of block range by pattern. 1st pattern element is an address.
    20  func (tt *withThreadPool) FindInBlocks(ctx context.Context, from, to idx.Block, pattern [][]common.Hash) (logs []*types.Log, err error) {
    21  	err = tt.ForEachInBlocks(
    22  		ctx,
    23  		from, to,
    24  		pattern,
    25  		func(l *types.Log) bool {
    26  			logs = append(logs, l)
    27  			return true
    28  		})
    29  
    30  	return
    31  }
    32  
    33  // ForEachInBlocks matches log records of block range by pattern. 1st pattern element is an address.
    34  func (tt *withThreadPool) ForEachInBlocks(ctx context.Context, from, to idx.Block, pattern [][]common.Hash, onLog func(*types.Log) (gonext bool)) error {
    35  	if 0 < to && to < from {
    36  		return nil
    37  	}
    38  
    39  	if ctx == nil {
    40  		ctx = context.Background()
    41  	}
    42  
    43  	pattern, err := limitPattern(pattern)
    44  	if err != nil {
    45  		return err
    46  	}
    47  
    48  	onMatched := func(rec *logrec) (gonext bool, err error) {
    49  		rec.fetch(tt.table.Logrec)
    50  		if rec.err != nil {
    51  			err = rec.err
    52  			return
    53  		}
    54  		gonext = onLog(rec.result)
    55  		return
    56  	}
    57  
    58  	splitby := 0
    59  	parallels := 0
    60  	for i := range pattern {
    61  		parallels += len(pattern[i])
    62  		if len(pattern[splitby]) < len(pattern[i]) {
    63  			splitby = i
    64  		}
    65  	}
    66  	rest := pattern[splitby]
    67  	parallels -= len(rest)
    68  
    69  	if parallels >= threads.GlobalPool.Cap() {
    70  		return ErrTooBigTopics
    71  	}
    72  
    73  	for len(rest) > 0 {
    74  		got, release := threads.GlobalPool.Lock(parallels + len(rest))
    75  		if got <= parallels {
    76  			release(got)
    77  			select {
    78  			case <-time.After(time.Millisecond):
    79  				continue
    80  			case <-ctx.Done():
    81  				return ctx.Err()
    82  			}
    83  		}
    84  
    85  		onDbIterator := func() {
    86  			release(1)
    87  		}
    88  
    89  		pattern[splitby] = rest[:got-parallels]
    90  		rest = rest[got-parallels:]
    91  		err = tt.searchParallel(ctx, pattern, uint64(from), uint64(to), onMatched, onDbIterator)
    92  		if err != nil {
    93  			return err
    94  		}
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func min(a, b int) int {
   101  	if a < b {
   102  		return a
   103  	}
   104  	return b
   105  }