2023-11-03 16:26:09 +01:00
|
|
|
package conn
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"math"
|
|
|
|
"math/rand"
|
|
|
|
"slices"
|
|
|
|
)
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// ConnCluster: splits nodes into clusters where nodes in a cluster communicate
|
2023-11-03 16:26:09 +01:00
|
|
|
// frequently and nodes outside of a cluster communicate infrequently
|
|
|
|
type ConnCluster interface {
|
2024-01-04 14:10:08 +01:00
|
|
|
// Getneighbours: get neighbours of the cluster the node is in
|
2023-11-03 16:26:09 +01:00
|
|
|
GetNeighbours(global []string, selfId string) []string
|
2024-01-04 14:10:08 +01:00
|
|
|
// GetInterCluster: get the cluster to communicate with
|
2023-11-03 16:26:09 +01:00
|
|
|
GetInterCluster(global []string, selfId string) string
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// ConnnClusterImpl: implementation of the connection cluster
|
2023-11-03 16:26:09 +01:00
|
|
|
type ConnClusterImpl struct {
|
|
|
|
clusterSize int
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// perform binary search to attain a size of a group
|
2023-11-03 16:26:09 +01:00
|
|
|
func binarySearch(global []string, selfId string, groupSize int) (int, int) {
|
|
|
|
slices.Sort(global)
|
|
|
|
|
|
|
|
lower := 0
|
|
|
|
higher := len(global) - 1
|
|
|
|
|
|
|
|
for (higher+1)-lower > groupSize {
|
2024-01-04 01:23:20 +01:00
|
|
|
mid := (lower + higher) / 2
|
|
|
|
|
2023-11-05 19:03:58 +01:00
|
|
|
if global[mid] < selfId {
|
|
|
|
lower = mid + 1
|
|
|
|
} else if global[mid] > selfId {
|
|
|
|
higher = mid - 1
|
2023-11-03 16:26:09 +01:00
|
|
|
} else {
|
2023-11-05 19:03:58 +01:00
|
|
|
break
|
2023-11-03 16:26:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 19:03:58 +01:00
|
|
|
return lower, int(math.Min(float64(lower+groupSize), float64(len(global))))
|
2023-11-03 16:26:09 +01:00
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// GetNeighbours: return the neighbours 'nearest' to you. In this implementation the
|
2023-11-03 16:26:09 +01:00
|
|
|
// neighbours aren't actually the ones nearest to you but just the ones nearest
|
|
|
|
// to you alphabetically. Perform binary search to get the total group
|
|
|
|
func (i *ConnClusterImpl) GetNeighbours(global []string, selfId string) []string {
|
|
|
|
slices.Sort(global)
|
|
|
|
|
|
|
|
lower, higher := binarySearch(global, selfId, i.clusterSize)
|
|
|
|
// slice the list to get the neighbours
|
|
|
|
return global[lower:higher]
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// GetInterCluster: get nodes not in your cluster. Every round there is a given chance
|
2023-11-03 16:26:09 +01:00
|
|
|
// you will communicate with a random node that is not in your cluster.
|
|
|
|
func (i *ConnClusterImpl) GetInterCluster(global []string, selfId string) string {
|
|
|
|
// Doesn't matter if not in it. Get index of where the node 'should' be
|
2023-12-18 23:17:46 +01:00
|
|
|
slices.Sort(global)
|
|
|
|
|
2023-11-03 16:26:09 +01:00
|
|
|
index, _ := binarySearch(global, selfId, 1)
|
|
|
|
|
2023-12-19 01:50:17 +01:00
|
|
|
randomCluster := rand.Intn(2) + 1
|
2023-11-03 16:26:09 +01:00
|
|
|
|
2023-12-19 01:50:17 +01:00
|
|
|
// cluster is considered a heap
|
|
|
|
neighbourIndex := (2*index + (randomCluster * i.clusterSize)) % len(global)
|
2023-11-03 16:26:09 +01:00
|
|
|
return global[neighbourIndex]
|
|
|
|
}
|
|
|
|
|
2024-01-04 14:10:08 +01:00
|
|
|
// NewConnCluster: instantiate a new connection cluster of a given group size.
|
2023-11-03 16:26:09 +01:00
|
|
|
func NewConnCluster(clusterSize int) (ConnCluster, error) {
|
|
|
|
log2Cluster := math.Log2(float64(clusterSize))
|
|
|
|
|
|
|
|
if float64((log2Cluster))-log2Cluster != 0 {
|
|
|
|
return nil, errors.New("cluster must be a power of 2")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ConnClusterImpl{clusterSize: clusterSize}, nil
|
|
|
|
}
|