smegmesh/pkg/sync/syncer.go

137 lines
2.9 KiB
Go
Raw Normal View History

2023-10-10 21:14:40 +02:00
package sync
import (
"errors"
2023-11-03 16:24:18 +01:00
"math/rand"
2023-10-23 19:13:08 +02:00
"sync"
"time"
2023-11-03 16:24:18 +01:00
"github.com/tim-beatham/wgmesh/pkg/conf"
"github.com/tim-beatham/wgmesh/pkg/conn"
"github.com/tim-beatham/wgmesh/pkg/lib"
logging "github.com/tim-beatham/wgmesh/pkg/log"
"github.com/tim-beatham/wgmesh/pkg/mesh"
)
2023-10-10 21:14:40 +02:00
// Syncer: picks random nodes from the mesh
type Syncer interface {
Sync(meshId string) error
SyncMeshes() error
}
type SyncerImpl struct {
2023-11-05 19:03:58 +01:00
manager mesh.MeshManager
2023-11-03 16:24:18 +01:00
requester SyncRequester
infectionCount int
syncCount int
cluster conn.ConnCluster
conf *conf.WgMeshConfiguration
2023-10-10 21:14:40 +02:00
}
// Sync: Sync random nodes
func (s *SyncerImpl) Sync(meshId string) error {
logging.Log.WriteInfof("UPDATING WG CONF")
s.manager.ApplyConfig()
if !s.manager.HasChanges(meshId) && s.infectionCount == 0 {
logging.Log.WriteInfof("No changes for %s", meshId)
return nil
}
2023-11-03 16:24:18 +01:00
theMesh := s.manager.GetMesh(meshId)
2023-11-03 16:24:18 +01:00
if theMesh == nil {
return errors.New("the provided mesh does not exist")
}
2023-11-03 16:24:18 +01:00
snapshot, err := theMesh.GetMesh()
if err != nil {
return err
}
nodes := snapshot.GetNodes()
if len(nodes) <= 1 {
return nil
}
2023-11-05 19:03:58 +01:00
self, err := s.manager.GetSelf(meshId)
if err != nil {
return err
}
excludedNodes := map[string]struct{}{
2023-11-05 19:03:58 +01:00
self.GetHostEndpoint(): {},
}
meshNodes := lib.MapValuesWithExclude(nodes, excludedNodes)
2023-11-03 16:24:18 +01:00
getNames := func(node mesh.MeshNode) string {
return node.GetHostEndpoint()
}
nodeNames := lib.Map(meshNodes, getNames)
2023-11-05 19:03:58 +01:00
neighbours := s.cluster.GetNeighbours(nodeNames, self.GetHostEndpoint())
2023-11-03 16:24:18 +01:00
randomSubset := lib.RandomSubsetOfLength(neighbours, s.conf.BranchRate)
for _, node := range randomSubset {
logging.Log.WriteInfof("Random node: %s", node)
}
before := time.Now()
2023-11-03 16:24:18 +01:00
if len(meshNodes) > s.conf.ClusterSize && rand.Float64() < s.conf.InterClusterChance {
logging.Log.WriteInfof("Sending to random cluster")
2023-11-05 19:03:58 +01:00
interCluster := s.cluster.GetInterCluster(nodeNames, self.GetHostEndpoint())
2023-11-03 16:24:18 +01:00
randomSubset = append(randomSubset, interCluster)
}
2023-10-23 19:13:08 +02:00
var waitGroup sync.WaitGroup
2023-11-03 16:24:18 +01:00
for index := range randomSubset {
2023-10-23 19:13:08 +02:00
waitGroup.Add(1)
2023-11-03 16:24:18 +01:00
go func(i int) error {
2023-10-23 19:13:08 +02:00
defer waitGroup.Done()
2023-11-03 16:24:18 +01:00
err := s.requester.SyncMesh(meshId, randomSubset[i])
return err
2023-11-03 16:24:18 +01:00
}(index)
}
2023-10-23 19:13:08 +02:00
waitGroup.Wait()
2023-11-03 16:24:18 +01:00
s.syncCount++
logging.Log.WriteInfof("SYNC TIME: %v", time.Now().Sub(before))
2023-11-03 16:24:18 +01:00
logging.Log.WriteInfof("SYNC COUNT: %d", s.syncCount)
2023-11-03 16:24:18 +01:00
s.infectionCount = ((s.conf.InfectionCount + s.infectionCount - 1) % s.conf.InfectionCount)
2023-10-10 21:14:40 +02:00
return nil
}
// SyncMeshes: Sync all meshes
2023-10-10 21:14:40 +02:00
func (s *SyncerImpl) SyncMeshes() error {
2023-11-05 19:03:58 +01:00
for meshId, _ := range s.manager.GetMeshes() {
err := s.Sync(meshId)
if err != nil {
return err
}
}
return nil
2023-10-10 21:14:40 +02:00
}
2023-11-05 19:03:58 +01:00
func NewSyncer(m mesh.MeshManager, conf *conf.WgMeshConfiguration, r SyncRequester) Syncer {
2023-11-03 16:24:18 +01:00
cluster, _ := conn.NewConnCluster(conf.ClusterSize)
return &SyncerImpl{
manager: m,
conf: conf,
requester: r,
infectionCount: 0,
syncCount: 0,
cluster: cluster}
}