mirror of
https://github.com/spf13/viper
synced 2025-05-10 22:27:18 +00:00
Viper map lock (#8)
* Add RWMutex protecting viper maps * Update README
This commit is contained in:
parent
a762f8a704
commit
bf1cf5d900
2 changed files with 32 additions and 2 deletions
|
@ -1,4 +1,8 @@
|
||||||
> ## Viper v2 feedback
|
# Fork of spf13/viper that makes it safe for concurrent access
|
||||||
|
|
||||||
|
Forked from version 1.9.0 of `spf13/viper`. Adds an `RWMutex` to the `viper` struct that is used to protect reads and writes to the struct's internal maps. This should stop some our servers' intermittent crashing.
|
||||||
|
|
||||||
|
> > ## Viper v2 feedback
|
||||||
> Viper is heading towards v2 and we would love to hear what _**you**_ would like to see in it. Share your thoughts here: https://forms.gle/R6faU74qPRPAzchZ9
|
> Viper is heading towards v2 and we would love to hear what _**you**_ would like to see in it. Share your thoughts here: https://forms.gle/R6faU74qPRPAzchZ9
|
||||||
>
|
>
|
||||||
> **Thank you!**
|
> **Thank you!**
|
||||||
|
|
28
viper.go
28
viper.go
|
@ -223,6 +223,8 @@ type Viper struct {
|
||||||
// TODO: should probably be protected with a mutex
|
// TODO: should probably be protected with a mutex
|
||||||
encoderRegistry *encoding.EncoderRegistry
|
encoderRegistry *encoding.EncoderRegistry
|
||||||
decoderRegistry *encoding.DecoderRegistry
|
decoderRegistry *encoding.DecoderRegistry
|
||||||
|
|
||||||
|
mapLock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns an initialized Viper instance.
|
// New returns an initialized Viper instance.
|
||||||
|
@ -243,6 +245,8 @@ func New() *Viper {
|
||||||
v.typeByDefValue = false
|
v.typeByDefValue = false
|
||||||
v.logger = jwwLogger{}
|
v.logger = jwwLogger{}
|
||||||
|
|
||||||
|
v.mapLock = sync.RWMutex{}
|
||||||
|
|
||||||
v.resetEncoding()
|
v.resetEncoding()
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
@ -658,7 +662,9 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v.mapLock.RLock()
|
||||||
next, ok := source[path[0]]
|
next, ok := source[path[0]]
|
||||||
|
v.mapLock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
// Fast path
|
// Fast path
|
||||||
if len(path) == 1 {
|
if len(path) == 1 {
|
||||||
|
@ -763,7 +769,9 @@ func (v *Viper) searchMapWithPathPrefixes(
|
||||||
pathIndex int,
|
pathIndex int,
|
||||||
path []string,
|
path []string,
|
||||||
) interface{} {
|
) interface{} {
|
||||||
|
v.mapLock.RLock()
|
||||||
next, ok := sourceMap[prefixKey]
|
next, ok := sourceMap[prefixKey]
|
||||||
|
v.mapLock.RUnlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -832,7 +840,10 @@ func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
|
||||||
var parentKey string
|
var parentKey string
|
||||||
for i := 1; i < len(path); i++ {
|
for i := 1; i < len(path); i++ {
|
||||||
parentKey = strings.Join(path[0:i], v.keyDelim)
|
parentKey = strings.Join(path[0:i], v.keyDelim)
|
||||||
if _, ok := m[parentKey]; ok {
|
v.mapLock.RLock()
|
||||||
|
_, ok := m[parentKey]
|
||||||
|
v.mapLock.RUnlock()
|
||||||
|
if ok {
|
||||||
return parentKey
|
return parentKey
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1456,9 +1467,13 @@ func (v *Viper) RegisterAlias(alias string, key string) {
|
||||||
func (v *Viper) registerAlias(alias string, key string) {
|
func (v *Viper) registerAlias(alias string, key string) {
|
||||||
alias = strings.ToLower(alias)
|
alias = strings.ToLower(alias)
|
||||||
if alias != key && alias != v.realKey(key) {
|
if alias != key && alias != v.realKey(key) {
|
||||||
|
v.mapLock.RLock()
|
||||||
_, exists := v.aliases[alias]
|
_, exists := v.aliases[alias]
|
||||||
|
v.mapLock.RUnlock()
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
|
v.mapLock.Lock()
|
||||||
|
|
||||||
// if we alias something that exists in one of the maps to another
|
// if we alias something that exists in one of the maps to another
|
||||||
// name, we'll never be able to get that value using the original
|
// name, we'll never be able to get that value using the original
|
||||||
// name, so move the config value to the new realkey.
|
// name, so move the config value to the new realkey.
|
||||||
|
@ -1479,6 +1494,8 @@ func (v *Viper) registerAlias(alias string, key string) {
|
||||||
v.override[key] = val
|
v.override[key] = val
|
||||||
}
|
}
|
||||||
v.aliases[alias] = key
|
v.aliases[alias] = key
|
||||||
|
|
||||||
|
v.mapLock.Unlock()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
v.logger.Warn("creating circular reference alias", "alias", alias, "key", key, "real_key", v.realKey(key))
|
v.logger.Warn("creating circular reference alias", "alias", alias, "key", key, "real_key", v.realKey(key))
|
||||||
|
@ -1523,7 +1540,9 @@ func (v *Viper) SetDefault(key string, value interface{}) {
|
||||||
deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
|
deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
|
||||||
|
|
||||||
// set innermost value
|
// set innermost value
|
||||||
|
v.mapLock.Lock()
|
||||||
deepestMap[lastKey] = value
|
deepestMap[lastKey] = value
|
||||||
|
v.mapLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets the value for the key in the override register.
|
// Set sets the value for the key in the override register.
|
||||||
|
@ -1542,7 +1561,9 @@ func (v *Viper) Set(key string, value interface{}) {
|
||||||
deepestMap := deepSearch(v.override, path[0:len(path)-1])
|
deepestMap := deepSearch(v.override, path[0:len(path)-1])
|
||||||
|
|
||||||
// set innermost value
|
// set innermost value
|
||||||
|
v.mapLock.Lock()
|
||||||
deepestMap[lastKey] = value
|
deepestMap[lastKey] = value
|
||||||
|
v.mapLock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadInConfig will discover and load the configuration file from disk
|
// ReadInConfig will discover and load the configuration file from disk
|
||||||
|
@ -1627,8 +1648,10 @@ func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
|
||||||
if v.config == nil {
|
if v.config == nil {
|
||||||
v.config = make(map[string]interface{})
|
v.config = make(map[string]interface{})
|
||||||
}
|
}
|
||||||
|
v.mapLock.Lock()
|
||||||
insensitiviseMap(cfg)
|
insensitiviseMap(cfg)
|
||||||
mergeMaps(cfg, v.config, nil)
|
mergeMaps(cfg, v.config, nil)
|
||||||
|
v.mapLock.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1716,6 +1739,9 @@ func unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
|
||||||
|
v.mapLock.Lock()
|
||||||
|
defer v.mapLock.Unlock()
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.ReadFrom(in)
|
buf.ReadFrom(in)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue