github.com/auxten/ginkgo@v0.0.0-20220130172820-7d98ad59d232/seed/ring.go (about) 1 package seed 2 3 import ( 4 "sort" 5 "time" 6 ) 7 8 func (sd *Seed) GetBlockIndex(host Host) []uint32 { 9 //TODO: make indexes distribute evenly 10 ret := make([]uint32, sd.VNodeCount) 11 size := uint32(len(sd.Blocks)) 12 for i := uint8(0); i < sd.VNodeCount; i++ { 13 ret[i] = host.Hash(i) % size 14 } 15 // sort ret increasing order 16 sort.Slice(ret, func(i, j int) bool { 17 return ret[i] < ret[j] 18 }) 19 20 j := 1 21 n := len(ret) 22 for i := 1; i < n; i++ { 23 if ret[i] != ret[i-1] { 24 ret[j] = ret[i] 25 j++ 26 } 27 } 28 29 return ret[0:j] 30 } 31 32 func (sd *Seed) Add(host Host) { 33 now := time.Now() 34 sd.Lock() 35 defer sd.Unlock() 36 for _, h := range sd.GetBlockIndex(host) { 37 block := sd.Blocks[h] 38 if block.Hosts == nil { 39 block.Hosts = make(map[Host]time.Time) 40 } 41 block.Hosts[host] = now 42 } 43 } 44 45 func (sd *Seed) Remove(host Host) { 46 sd.Lock() 47 defer sd.Unlock() 48 for _, h := range sd.GetBlockIndex(host) { 49 block := sd.Blocks[h] 50 delete(block.Hosts, host) 51 } 52 } 53 54 func (sd *Seed) GetAllHosts() []Host { 55 hosts := make([]Host, 0, sd.VNodeCount) 56 sd.RLock() 57 defer sd.RUnlock() 58 for i := range sd.Blocks { 59 for h := range sd.Blocks[i].Hosts { 60 hosts = append(hosts, h) 61 } 62 } 63 return SortDeDup(hosts) 64 } 65 66 //LocateBlock tries to find maximum `n` different hosts for `blockId`. 67 // As the golang map is not deterministic on iteration, when multiple hosts hashed 68 // onto the same block the LocateBlock returned hosts are also not deterministic 69 // which is good for load balancing. 70 func (sd *Seed) LocateBlock(blockId int64, n int) []Host { 71 hosts := make([]Host, 0, n) 72 sd.RLock() 73 defer sd.RUnlock() 74 for i := blockId + int64(len(sd.Blocks)); i > blockId; i-- { 75 idx := i % int64(len(sd.Blocks)) 76 for h, _ := range sd.Blocks[idx].Hosts { 77 hosts = SortDeDup(append(hosts, h)) 78 if len(hosts) >= n { 79 return hosts 80 } 81 } 82 } 83 84 return hosts 85 }