76 lines
1.8 KiB
Go
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
|
|
}
|
|
}
|
|
}
|