mirror of
https://github.com/tim-beatham/smegmesh.git
synced 2024-12-12 17:41:08 +01:00
Added clustering and clean up
This commit is contained in:
parent
e2c6db3a4f
commit
d17dce3b1e
73
pkg/conn/cluster.go
Normal file
73
pkg/conn/cluster.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package conn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConnCluster splits nodes into clusters where nodes in a cluster communicate
|
||||||
|
// frequently and nodes outside of a cluster communicate infrequently
|
||||||
|
type ConnCluster interface {
|
||||||
|
GetNeighbours(global []string, selfId string) []string
|
||||||
|
GetInterCluster(global []string, selfId string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnClusterImpl struct {
|
||||||
|
clusterSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
func binarySearch(global []string, selfId string, groupSize int) (int, int) {
|
||||||
|
slices.Sort(global)
|
||||||
|
|
||||||
|
lower := 0
|
||||||
|
higher := len(global) - 1
|
||||||
|
mid := lower + (lower+higher)/2
|
||||||
|
|
||||||
|
for (higher+1)-lower > groupSize {
|
||||||
|
if global[mid] <= selfId {
|
||||||
|
lower = mid
|
||||||
|
} else {
|
||||||
|
higher = mid
|
||||||
|
}
|
||||||
|
|
||||||
|
mid = lower + (lower+higher)/2
|
||||||
|
}
|
||||||
|
|
||||||
|
return lower, higher + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNeighbours return the neighbours 'nearest' to you. In this implementation the
|
||||||
|
// 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]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInterCluster get nodes not in your cluster. Every round there is a given chance
|
||||||
|
// 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
|
||||||
|
index, _ := binarySearch(global, selfId, 1)
|
||||||
|
numClusters := math.Ceil(float64(len(global)) / float64(i.clusterSize))
|
||||||
|
|
||||||
|
randomCluster := rand.Intn(int(numClusters)-1) + 1
|
||||||
|
|
||||||
|
neighbourIndex := (index + randomCluster) % len(global)
|
||||||
|
return global[neighbourIndex]
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
84
pkg/conn/window.go
Normal file
84
pkg/conn/window.go
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
package conn
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ConnectionWindow maintains a sliding window of connections between users
|
||||||
|
type ConnectionWindow interface {
|
||||||
|
// GetWindow is a list of connections to choose from
|
||||||
|
GetWindow() []string
|
||||||
|
// SlideConnection removes a node from the window and adds a random node
|
||||||
|
// not already in the window. connList represents the list of possible
|
||||||
|
// connections to choose from
|
||||||
|
SlideConnection(connList []string) error
|
||||||
|
// PushConneciton is used when connection list less than window size.
|
||||||
|
PutConnection(conn []string) error
|
||||||
|
// IsFull returns true if the window is full. In which case we must slide the window
|
||||||
|
IsFull() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectionWindowImpl struct {
|
||||||
|
window []string
|
||||||
|
windowSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetWindow gets the current list of active connections in
|
||||||
|
// the window
|
||||||
|
func (c *ConnectionWindowImpl) GetWindow() []string {
|
||||||
|
return c.window
|
||||||
|
}
|
||||||
|
|
||||||
|
// SlideConnection slides the connection window by one shuffling items
|
||||||
|
// in the windows
|
||||||
|
func (c *ConnectionWindowImpl) SlideConnection(connList []string) error {
|
||||||
|
// If the number of peer connections is less than the length of the window
|
||||||
|
// then exit early. Can't slide the window it should contain all nodes!
|
||||||
|
if len(c.window) < c.windowSize {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
filter := func(node string) bool {
|
||||||
|
return !slices.Contains(c.window, node)
|
||||||
|
}
|
||||||
|
|
||||||
|
pool := lib.Filter(connList, filter)
|
||||||
|
newNode := lib.RandomSubsetOfLength(pool, 1)
|
||||||
|
|
||||||
|
if len(newNode) == 0 {
|
||||||
|
return errors.New("could not slide window")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(c.window) - 1; i >= 1; i-- {
|
||||||
|
c.window[i] = c.window[i-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
c.window[0] = newNode[0]
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutConnection put random connections in the connection
|
||||||
|
func (c *ConnectionWindowImpl) PutConnection(connList []string) error {
|
||||||
|
if len(c.window) >= c.windowSize {
|
||||||
|
return errors.New("cannot place connection. Window full need to slide")
|
||||||
|
}
|
||||||
|
|
||||||
|
c.window = lib.RandomSubsetOfLength(connList, c.windowSize)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ConnectionWindowImpl) IsFull() bool {
|
||||||
|
return len(c.window) >= c.windowSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConnectionWindow(windowLength int) ConnectionWindow {
|
||||||
|
window := &ConnectionWindowImpl{
|
||||||
|
window: make([]string, 0),
|
||||||
|
windowSize: windowLength,
|
||||||
|
}
|
||||||
|
|
||||||
|
return window
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user