gitee.com/lh-her-team/common@v1.5.1/shardingbirdsnest/sharding_birdnest.go (about)

     1  // Package shardingbirdsnest bird's nest
     2  package shardingbirdsnest
     3  
     4  import (
     5  	"errors"
     6  	"path/filepath"
     7  	"time"
     8  
     9  	"go.uber.org/atomic"
    10  
    11  	bn "gitee.com/lh-her-team/common/birdsnest"
    12  )
    13  
    14  const (
    15  	// Filepath sharding path
    16  	Filepath = "sharding"
    17  )
    18  
    19  var (
    20  	// ErrAddsTimeout adds timeout error
    21  	ErrAddsTimeout = errors.New("add multiple key timeout")
    22  	// ErrCannotModifyTheNestConfiguration cannot modify the nest configuration
    23  	ErrCannotModifyTheNestConfiguration = errors.New("when historical data exists, you cannot modify the nest " +
    24  		"configuration")
    25  )
    26  
    27  // ShardingBirdsNest Sharding bird's nest implement
    28  type ShardingBirdsNest struct {
    29  	// bn bird's nest collections
    30  	bn []bn.BirdsNest
    31  	// config sharding bird's nest configuration
    32  	config *ShardingBirdsNestConfig
    33  	// height current height
    34  	height uint64
    35  	// preHeight pre height
    36  	preHeight *atomic.Uint64
    37  	// sharding algorithm
    38  	algorithm ShardingAlgorithm
    39  	// log logger
    40  	log bn.Logger
    41  	// serializeC serialize channel
    42  	serializeC chan serializeSignal
    43  	// exitC exit channel TODO exit -> context.Context
    44  	exitC chan struct{}
    45  	// snapshot
    46  	snapshot *bn.WalSnapshot
    47  }
    48  
    49  // NewShardingBirdsNest new sharding bird's nest implement
    50  func NewShardingBirdsNest(config *ShardingBirdsNestConfig, exitC chan struct{}, strategy bn.Strategy,
    51  	alg ShardingAlgorithm, logger bn.Logger) (*ShardingBirdsNest, error) {
    52  	// eg: data/org1/tx_filter/chain1/sharding
    53  	join := filepath.Join(config.Snapshot.Path, config.ChainId)
    54  	snapshot, err := bn.NewWalSnapshot(join, Filepath, -1)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	// sharding bird's nest
    59  	s := &ShardingBirdsNest{
    60  		algorithm:  alg,
    61  		exitC:      exitC,
    62  		config:     config,
    63  		snapshot:   snapshot,
    64  		log:        logger,
    65  		preHeight:  atomic.NewUint64(0),
    66  		serializeC: make(chan serializeSignal),
    67  	}
    68  	// deserialize snapshot
    69  	err = s.Deserialize()
    70  	if err != nil {
    71  		if err != ErrCannotModifyTheNestConfiguration {
    72  			return nil, err
    73  		}
    74  	}
    75  	// init bird's nest collections
    76  	birdsNests := make([]bn.BirdsNest, config.Length)
    77  	for i := 0; i < int(config.Length); i++ {
    78  		var birdsNest bn.BirdsNest
    79  		// new bird's nest by number
    80  		birdsNest, err = bn.NewBirdsNestByNumber(config.Birdsnest, exitC, strategy, logger, i+1)
    81  		if err != nil {
    82  			if err != bn.ErrCannotModifyTheNestConfiguration {
    83  				return nil, err
    84  			}
    85  		}
    86  		birdsNests[i] = birdsNest
    87  	}
    88  	s.bn = birdsNests
    89  	return s, err
    90  }
    91  
    92  // GetHeight get current height
    93  func (s *ShardingBirdsNest) GetHeight() uint64 {
    94  	// returned height
    95  	return s.height
    96  }
    97  
    98  // SetHeight set current height
    99  func (s *ShardingBirdsNest) SetHeight(height uint64) {
   100  	s.height = height
   101  	s.serializeHeight(height)
   102  	// all bird's nest set current height
   103  	for _, nest := range s.bn {
   104  		nest.SetHeight(height)
   105  	}
   106  }
   107  
   108  // AddsAndSetHeight Adds and SetHeight
   109  func (s *ShardingBirdsNest) AddsAndSetHeight(keys []bn.Key, height uint64) (result error) {
   110  	// add to sharding bird's nest
   111  	err := s.Adds(keys)
   112  	if err != nil {
   113  		return err
   114  	}
   115  	s.SetHeight(height)
   116  	return nil
   117  }
   118  
   119  // Adds add keys
   120  func (s *ShardingBirdsNest) Adds(keys []bn.Key) (err error) {
   121  	var (
   122  		// sharding algorithm
   123  		sharding = s.algorithm.DoSharding(keys)
   124  		// finish channel
   125  		finishC = make(chan int)
   126  		// running task
   127  		runningTask int
   128  		// Timeout
   129  		timeout = time.After(time.Duration(s.config.Timeout) * time.Second)
   130  	)
   131  	for i := 0; i < len(sharding); i++ {
   132  		if sharding[i] == nil {
   133  			continue
   134  		}
   135  		runningTask++
   136  		// execute adds
   137  		go func(i int, values []bn.Key) {
   138  			defer func() { finishC <- i }()
   139  			err = s.bn[i].Adds(values)
   140  		}(i, sharding[i])
   141  	}
   142  	for {
   143  		select {
   144  		case <-timeout: // timeout
   145  			return ErrAddsTimeout
   146  		case <-finishC: // task finish
   147  			if err != nil {
   148  				return
   149  			}
   150  			runningTask--
   151  			if runningTask <= 0 {
   152  				// overall
   153  				return
   154  			}
   155  		}
   156  	}
   157  }
   158  
   159  // Add key
   160  func (s *ShardingBirdsNest) Add(key bn.Key) error {
   161  	if key == nil || key.Len() == 0 {
   162  		return bn.ErrKeyCannotBeEmpty
   163  	}
   164  	// do sharding once
   165  	index := s.algorithm.DoShardingOnce(key)
   166  	// add to bird's nest
   167  	err := s.bn[index].Add(key)
   168  	if err != nil {
   169  		return err
   170  	}
   171  	return nil
   172  }
   173  
   174  // Contains bn.Key
   175  func (s *ShardingBirdsNest) Contains(key bn.Key, rules ...bn.RuleType) (bool, error) {
   176  	// if the key is empty returned error
   177  	if key == nil || key.Len() == 0 {
   178  		return false, bn.ErrKeyCannotBeEmpty
   179  	}
   180  	// do sharding once
   181  	index := s.algorithm.DoShardingOnce(key)
   182  	// contains
   183  	contains, err := s.bn[index].Contains(key, rules...)
   184  	if err != nil {
   185  		return false, err
   186  	}
   187  	return contains, nil
   188  }
   189  
   190  // ValidateRule validate key rule
   191  func (s *ShardingBirdsNest) ValidateRule(key bn.Key, rules ...bn.RuleType) error {
   192  	// if the key is empty returned error
   193  	if key == nil || key.Len() == 0 {
   194  		return bn.ErrKeyCannotBeEmpty
   195  	}
   196  	// TODO Although each Bird's Nest is independent, the rules are consistent, so there is no need for sharding and 0
   197  	// is used by default; If Bird's Nest rules are inconsistent for each shard in the future, open the following code
   198  	// index := s.algorithm.DoShardingOnce(key)
   199  	// err := s.bn[index].ValidateRule(key, rules...)
   200  	err := s.bn[0].ValidateRule(key, rules...)
   201  	if err != nil {
   202  		return err
   203  	}
   204  	return nil
   205  }
   206  
   207  // Info print sharding bird's nest info
   208  func (s *ShardingBirdsNest) Info() []uint64 {
   209  	// not implement
   210  	return nil
   211  }
   212  
   213  // Infos print sharding bird's nest info
   214  // index 0 sharding index
   215  // index 0 height
   216  // index 1 cuckoo size
   217  // index 2 current index
   218  // index 3 total cuckoo size
   219  // index 4 total space occupied by cuckoo
   220  func (s *ShardingBirdsNest) Infos() [][]uint64 {
   221  	infos := make([][]uint64, s.config.Length)
   222  	for i, birdsNest := range s.bn {
   223  		infos[i] = birdsNest.Info()
   224  	}
   225  	return infos
   226  }