proxy-pool/internal/config/store.go
youfak bc94f4dbf1
Some checks are pending
ci / proto (push) Waiting to run
ci / test (ubuntu-latest) (push) Waiting to run
ci / test (windows-latest) (push) Waiting to run
ci / race (push) Waiting to run
ci / integration (push) Waiting to run
feat: publish gateway routing snapshots
2026-07-31 15:29:10 +08:00

76 lines
1.8 KiB
Go

package config
import (
"errors"
"sync/atomic"
)
var ErrInvalidStore = errors.New("invalid configuration store")
// Store publishes complete validated configurations with one atomic pointer swap.
type Store struct {
current atomic.Pointer[publishedConfiguration]
}
type publishedConfiguration struct {
value Config
revision uint64
}
func NewStore(initial *Config) (*Store, error) {
if err := Validate(initial); err != nil {
return nil, errors.Join(ErrInvalidStore, err)
}
store := &Store{}
store.current.Store(&publishedConfiguration{value: cloneConfig(*initial)})
return store, nil
}
func (store *Store) Current() *Config {
configuration, _ := store.Snapshot()
return configuration
}
// Snapshot returns a detached configuration and its revision from the same
// atomic publication. Callers that depend on both must not read them
// separately through Current and Revision.
func (store *Store) Snapshot() (*Config, uint64) {
if store == nil {
return nil, 0
}
published := store.current.Load()
if published == nil {
return nil, 0
}
cloned := cloneConfig(published.value)
return &cloned, published.revision
}
func (store *Store) Revision() uint64 {
if store == nil {
return 0
}
published := store.current.Load()
if published == nil {
return 0
}
return published.revision
}
// PublishRevision publishes only a strictly newer authoritative revision.
func (store *Store) PublishRevision(configuration *Config, revision uint64) bool {
if store == nil || configuration == nil || revision == 0 {
return false
}
for {
current := store.current.Load()
if current != nil && revision <= current.revision {
return false
}
next := &publishedConfiguration{value: cloneConfig(*configuration), revision: revision}
if store.current.CompareAndSwap(current, next) {
return true
}
}
}