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  }