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 }