ceremonyclient/types/hypergraph/sync.go
Cassandra Heart 8dc7e0d526
v2.1.0.14 (#484)
* v2.1.0.14

* release notes
2025-12-03 23:56:34 -06:00

129 lines
2.3 KiB
Go

package hypergraph
import (
"sync"
"sync/atomic"
"time"
)
type SyncController struct {
globalSync atomic.Bool
statusMu sync.RWMutex
syncStatus map[string]*SyncInfo
maxActiveSessions int32
activeSessions atomic.Int32
}
func (s *SyncController) TryEstablishSyncSession(peerID string) bool {
if peerID == "" {
return !s.globalSync.Swap(true)
}
info := s.getOrCreate(peerID)
if info.inProgress.Swap(true) {
return false
}
if !s.incrementActiveSessions() {
info.inProgress.Store(false)
return false
}
return true
}
func (s *SyncController) EndSyncSession(peerID string) {
if peerID == "" {
s.globalSync.Store(false)
return
}
s.statusMu.RLock()
info := s.syncStatus[peerID]
s.statusMu.RUnlock()
if info != nil {
if info.inProgress.Swap(false) {
s.decrementActiveSessions()
}
}
}
func (s *SyncController) GetStatus(peerID string) (*SyncInfo, bool) {
s.statusMu.RLock()
defer s.statusMu.RUnlock()
info, ok := s.syncStatus[peerID]
return info, ok
}
func (s *SyncController) SetStatus(peerID string, info *SyncInfo) {
s.statusMu.Lock()
existing := s.syncStatus[peerID]
if existing == nil {
s.syncStatus[peerID] = info
} else {
existing.Unreachable = info.Unreachable
existing.LastSynced = info.LastSynced
}
s.statusMu.Unlock()
}
func (s *SyncController) getOrCreate(peerID string) *SyncInfo {
s.statusMu.Lock()
defer s.statusMu.Unlock()
info, ok := s.syncStatus[peerID]
if !ok {
info = &SyncInfo{}
s.syncStatus[peerID] = info
}
return info
}
type SyncInfo struct {
Unreachable bool
LastSynced time.Time
inProgress atomic.Bool
}
func NewSyncController(maxActiveSessions int) *SyncController {
var max int32
if maxActiveSessions > 0 {
max = int32(maxActiveSessions)
}
return &SyncController{
syncStatus: map[string]*SyncInfo{},
maxActiveSessions: max,
}
}
func (s *SyncController) incrementActiveSessions() bool {
if s.maxActiveSessions <= 0 {
return true
}
for {
current := s.activeSessions.Load()
if current >= s.maxActiveSessions {
return false
}
if s.activeSessions.CompareAndSwap(current, current+1) {
return true
}
}
}
func (s *SyncController) decrementActiveSessions() {
if s.maxActiveSessions <= 0 {
return
}
for {
current := s.activeSessions.Load()
if current == 0 {
return
}
if s.activeSessions.CompareAndSwap(current, current-1) {
return
}
}
}