fix(config): fix data race (#1316)

* data race

* fix values

* lock
pull/1320/head
Windfarer 3 years ago committed by GitHub
parent 9bbf4696d4
commit 6d06721fc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      config/file/file_test.go
  2. 13
      config/reader.go

@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sync"
"testing"
"time"
@ -68,14 +69,14 @@ const (
}
}`
// _testYaml = `
//Foo:
// bar :
// - {name: nihao,age: 1}
// - {name: nihao,age: 1}
//
//
//`
// _testYaml = `
//Foo:
// bar :
// - {name: nihao,age: 1}
// - {name: nihao,age: 1}
//
//
//`
)
//func TestScan(t *testing.T) {
@ -288,3 +289,35 @@ func testScan(t *testing.T, c config.Config) {
}
t.Log(conf)
}
func TestMergeDataRace(t *testing.T) {
path := filepath.Join(t.TempDir(), "test_config.json")
defer os.Remove(path)
if err := ioutil.WriteFile(path, []byte(_testJSON), 0666); err != nil {
t.Error(err)
}
c := config.New(config.WithSource(
NewSource(path),
))
wg := &sync.WaitGroup{}
wg.Add(2)
go func() {
defer wg.Done()
for i := 0; i < 100; i++ {
var conf struct{}
if err := c.Scan(&conf); err != nil {
t.Error(err)
}
}
}()
go func() {
defer wg.Done()
for i := 0; i < 100; i++ {
if err := c.Load(); err != nil {
t.Error(err)
}
}
}()
wg.Wait()
}

@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"strings"
"sync"
"github.com/imdario/mergo"
"google.golang.org/protobuf/encoding/protojson"
@ -23,17 +24,21 @@ type Reader interface {
type reader struct {
opts options
values map[string]interface{}
lock sync.Mutex
}
func newReader(opts options) Reader {
return &reader{
opts: opts,
values: make(map[string]interface{}),
lock: sync.Mutex{},
}
}
func (r *reader) Merge(kvs ...*KeyValue) error {
r.lock.Lock()
merged, err := cloneMap(r.values)
r.lock.Unlock()
if err != nil {
return err
}
@ -46,19 +51,27 @@ func (r *reader) Merge(kvs ...*KeyValue) error {
return err
}
}
r.lock.Lock()
r.values = merged
r.lock.Unlock()
return nil
}
func (r *reader) Value(path string) (Value, bool) {
r.lock.Lock()
defer r.lock.Unlock()
return readValue(r.values, path)
}
func (r *reader) Source() ([]byte, error) {
r.lock.Lock()
defer r.lock.Unlock()
return marshalJSON(convertMap(r.values))
}
func (r *reader) Resolve() error {
r.lock.Lock()
defer r.lock.Unlock()
return r.opts.resolver(r.values)
}

Loading…
Cancel
Save