Skip to content
This repository has been archived by the owner on Dec 15, 2020. It is now read-only.

Commit

Permalink
fix: use monotonic counter for tracking config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
aeneasr committed Nov 18, 2020
1 parent 8cc0271 commit d8c0100
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 26 deletions.
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ require (
github.com/spf13/pflag v1.0.3
github.com/stretchr/testify v1.4.0
github.com/subosito/gotenv v1.2.0
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 // indirect
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 // indirect
golang.org/x/text v0.3.2 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
Expand Down
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,9 @@ github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSfrPzImPoVxuomtbT2nk=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
23 changes: 13 additions & 10 deletions viper.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"reflect"
"strings"
"sync"
"sync/atomic"
"time"

"github.com/dgraph-io/ristretto"
Expand Down Expand Up @@ -196,7 +197,7 @@ type Viper struct {
configFile string
configType string
configPermissions os.FileMode
configChangedAt time.Time
configVersion uint32
envPrefix string

automaticEnvApplied bool
Expand Down Expand Up @@ -232,7 +233,7 @@ func New() *Viper {
v := new(Viper)
v.keyDelim = "."
v.configName = "config"
v.configChangedAt = time.Now()
v.configVersion = 1
v.configPermissions = os.FileMode(0644)
v.fs = afero.NewOsFs()
v.config = make(map[string]interface{})
Expand Down Expand Up @@ -516,13 +517,15 @@ func (v *Viper) ConfigFileUsed() string {
return v.configFile
}

// ConfigChangeAt returns the time of the last config change.
func ConfigChangeAt() time.Time { return v.ConfigChangeAt() }
func (v *Viper) ConfigChangeAt() time.Time {
// ConfigChanges returns number of changes to the config.
// The number of changes increases each time
// the configuration is changed or reloaded.
func ConfigChanges() uint32 { return v.ConfigVersion() }
func (v *Viper) ConfigVersion() uint32 {
v.lock.RLock()
defer v.lock.RUnlock()

return v.configChangedAt
return v.configVersion
}

// AddConfigPath adds a path for Viper to search for the config file in.
Expand Down Expand Up @@ -1532,7 +1535,7 @@ func (v *Viper) ReadInConfig() error {
v.lock.Lock()
v.cache.Clear()
v.config = config
v.configChangedAt = time.Now()
atomic.AddUint32(&v.configVersion, 1)
v.lock.Unlock()

return nil
Expand All @@ -1545,7 +1548,7 @@ func (v *Viper) SetRawConfig(config map[string]interface{}) {
defer v.lock.Unlock()
insensitiviseMap(config)
v.config = config
v.configChangedAt = time.Now()
atomic.AddUint32(&v.configVersion, 1)
v.cache.Clear()
}

Expand Down Expand Up @@ -1578,7 +1581,7 @@ func (v *Viper) ReadConfig(in io.Reader) error {
defer v.lock.Unlock()
v.cache.Clear()
v.config = make(map[string]interface{})
v.configChangedAt = time.Now()
atomic.AddUint32(&v.configVersion, 1)
return v.unmarshalReader(in, v.config)
}

Expand All @@ -1603,7 +1606,7 @@ func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
}
insensitiviseMap(cfg)
mergeMaps(cfg, v.config, nil)
v.configChangedAt = time.Now()
atomic.AddUint32(&v.configVersion, 1)
v.lock.Unlock()
return nil
}
Expand Down
20 changes: 9 additions & 11 deletions viper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2273,39 +2273,37 @@ func TestConfigChangedAt(t *testing.T) {
t.Run("read config", func(t *testing.T) {
Reset()
SetConfigType("yml")
changedAt := ConfigChangeAt()
changedAt := ConfigChanges()

require.NoError(t, ReadConfig(bytes.NewBufferString(`foo: bar`)))

// Check that changedAt is different to initial
firstRead := ConfigChangeAt()
assert.NotEqual(t, changedAt.UnixNano(), firstRead.UnixNano())
assert.Equal(t, changedAt, ConfigChanges()-1)

require.NoError(t, ReadConfig(bytes.NewBufferString(`foo: baz`)))

// Check that changedAt is different to last read
assert.NotEqual(t, firstRead.UnixNano(), ConfigChangeAt().UnixNano())
assert.Equal(t, changedAt, ConfigChanges()-2)
})

t.Run("merge config", func(t *testing.T) {
Reset()
SetConfigType("yml")
changedAt := ConfigChangeAt()
changedAt := ConfigChanges()

if err := v.ReadConfig(bytes.NewBuffer(yamlMergeExampleTgt)); err != nil {
t.Fatal(err)
}

// Check that changedAt is different to initial
firstRead := ConfigChangeAt()
assert.NotEqual(t, changedAt.UnixNano(), firstRead.UnixNano())
firstRead := ConfigChanges()
assert.NotEqual(t, changedAt, firstRead)

if err := v.MergeConfig(bytes.NewBuffer(yamlMergeExampleSrc)); err != nil {
t.Fatal(err)
}

// Check that changedAt is different to last read
assert.NotEqual(t, firstRead.UnixNano(), ConfigChangeAt().UnixNano())
assert.NotEqual(t, firstRead, ConfigChanges())
})

t.Run("watch file", func(t *testing.T) {
Expand All @@ -2316,7 +2314,7 @@ func TestConfigChangedAt(t *testing.T) {

// given a `config.yaml` file being watched
v, configFile, cleanup := newViperWithConfigFile(t)
changedAt := v.ConfigChangeAt()
changedAt := v.ConfigVersion()
defer cleanup()

_, err := os.Stat(configFile)
Expand All @@ -2337,7 +2335,7 @@ func TestConfigChangedAt(t *testing.T) {
require.Nil(t, err)

// Check that changedAt is different
assert.NotEqual(t, changedAt.UnixNano(), v.ConfigChangeAt().UnixNano())
assert.NotEqual(t, changedAt, v.ConfigVersion())
})
}

Expand Down

0 comments on commit d8c0100

Please sign in to comment.