Skip to content

Commit ad88741

Browse files
committed
Cache config value to optimize Get config API
1 parent 2df34b1 commit ad88741

File tree

3 files changed

+204
-42
lines changed

3 files changed

+204
-42
lines changed

archaius_test.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,14 @@ package archaius_test
33
import (
44
"bytes"
55
"fmt"
6-
"io"
7-
"os"
8-
"path/filepath"
9-
"testing"
10-
116
"github.com/go-chassis/go-archaius"
127
"github.com/go-chassis/go-archaius/event"
138
"github.com/go-chassis/openlog"
149
"github.com/stretchr/testify/assert"
10+
"io"
11+
"os"
12+
"path/filepath"
13+
"testing"
1514
)
1615

1716
type EListener struct{}
@@ -58,6 +57,8 @@ exist: true
5857
t.Run("add mem config", func(t *testing.T) {
5958
archaius.Set("age", "16")
6059
assert.Equal(t, "16", archaius.Get("age"))
60+
archaius.Set("age", "17")
61+
assert.Equal(t, "17", archaius.Get("age"))
6162
})
6263
t.Run("delete mem config", func(t *testing.T) {
6364
archaius.Delete("age")

benchmark/benchmark_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package benchmark
2+
3+
import (
4+
"github.com/go-chassis/go-archaius"
5+
"github.com/stretchr/testify/assert"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"testing"
10+
)
11+
12+
var f1Content = `
13+
age0: 1
14+
age1: 1
15+
age2: 1
16+
age3: 1
17+
age4: 1
18+
age5: 1
19+
age6: 1
20+
age7: 1
21+
age8: 1
22+
age9: 1
23+
age10: 1
24+
age11: 1
25+
age12: 1
26+
age13: 1
27+
age14: 1
28+
age15: 1
29+
age16: 1
30+
age17: 1
31+
age18: 1
32+
age19: 1
33+
age20: 1
34+
age21: 1
35+
age22: 1
36+
age23: 1
37+
age24: 1
38+
age25: 1
39+
age26: 1
40+
age27: 1
41+
age28: 1
42+
age29: 1
43+
age30: 1
44+
age31: 1
45+
age32: 1
46+
age33: 1
47+
age34: 1
48+
age35: 1
49+
age36: 1
50+
age37: 1
51+
age38: 1
52+
age39: 1
53+
age40: 1
54+
age41: 1
55+
age42: 1
56+
age43: 1
57+
age44: 1
58+
age45: 1
59+
age46: 1
60+
age47: 1
61+
age48: 1
62+
age49: 1
63+
age50: 1
64+
age51: 1
65+
age52: 1
66+
age53: 1
67+
age54: 1
68+
age55: 1
69+
age56: 1
70+
age57: 1
71+
age58: 1
72+
age59: 1
73+
age60: 1
74+
age61: 1
75+
age62: 1
76+
age63: 1
77+
age64: 1
78+
age65: 1
79+
age66: 1
80+
age67: 1
81+
age68: 1
82+
age69: 1
83+
age70: 1
84+
age71: 1
85+
age72: 1
86+
age73: 1
87+
age74: 1
88+
age75: 1
89+
age76: 1
90+
age77: 1
91+
age78: 1
92+
age79: 1
93+
age80: 1
94+
age81: 1
95+
age82: 1
96+
age83: 1
97+
age84: 1
98+
age85: 1
99+
age86: 1
100+
age87: 1
101+
age88: 1
102+
age89: 1
103+
age90: 1
104+
age91: 1
105+
age92: 1
106+
age93: 1
107+
age94: 1
108+
age95: 1
109+
age96: 1
110+
age97: 1
111+
age98: 1
112+
age99: 0
113+
`
114+
115+
func createFile(content string, name string, dir string) string {
116+
filename := filepath.Join(dir, name)
117+
f1, _ := os.Create(filename)
118+
_, _ = io.WriteString(f1, content)
119+
f1.Close()
120+
return filename
121+
}
122+
123+
func TestMain(m *testing.M) {
124+
filename := createFile(f1Content, "f1.yaml", "/tmp")
125+
defer os.Remove(filename)
126+
127+
err := archaius.Init(archaius.WithOptionalFiles([]string{filename}))
128+
if err != nil {
129+
os.Exit(-1)
130+
}
131+
os.Exit(m.Run())
132+
}
133+
134+
func BenchmarkFileSource(b *testing.B) {
135+
s := 0
136+
b.ResetTimer()
137+
138+
for i := 0; i < b.N; i++ {
139+
s += archaius.GetInt("age99", 1)
140+
}
141+
assert.Zero(b, s)
142+
}
143+
144+
func BenchmarkFileSourceParallelism(b *testing.B) {
145+
s := 0
146+
b.ResetTimer()
147+
b.SetParallelism(200)
148+
b.RunParallel(func(pb *testing.PB) {
149+
for pb.Next() {
150+
s += archaius.GetInt("age99", 1)
151+
}
152+
})
153+
assert.Zero(b, s)
154+
}

source/manager.go

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ import (
3636

3737
//errors
3838
var (
39-
ErrKeyNotExist = errors.New("key does not exist")
40-
ErrIgnoreChange = errors.New("ignore key changed")
39+
ErrKeyNotExist = errors.New("key does not exist")
40+
ErrIgnoreChange = errors.New("ignore key changed")
4141
ErrWriterInvalid = errors.New("writer is invalid")
4242
)
4343

@@ -55,6 +55,8 @@ type Manager struct {
5555
sourceMapMux sync.RWMutex
5656
Sources map[string]ConfigSource
5757

58+
ConfigValueCache sync.Map
59+
5860
ConfigurationMap sync.Map
5961

6062
dispatcher *event.Dispatcher
@@ -79,6 +81,9 @@ func (m *Manager) Cleanup() error {
7981
return err
8082
}
8183
}
84+
85+
m.ConfigValueCache = sync.Map{}
86+
8287
return nil
8388
}
8489

@@ -139,8 +144,8 @@ func (m *Manager) Marshal(w io.Writer) error {
139144
}
140145
allConfig := make(map[string]map[string]interface{})
141146
for name, source := range m.Sources {
142-
config, err := source.GetConfigurations()
143-
if err != nil {
147+
config, err := source.GetConfigurations()
148+
if err != nil {
144149
openlog.Error("get source " + name + " error " + err.Error())
145150
continue
146151
}
@@ -215,12 +220,11 @@ func (m *Manager) pullSourceConfigs(source string) error {
215220
func (m *Manager) Configs() map[string]interface{} {
216221
config := make(map[string]interface{}, 0)
217222

218-
m.ConfigurationMap.Range(func(key, value interface{}) bool {
219-
sValue := m.configValueBySource(key.(string), value.(string))
220-
if sValue == nil {
223+
m.ConfigValueCache.Range(func(key, value interface{}) bool {
224+
if value == nil {
221225
return true
222226
}
223-
config[key.(string)] = sValue
227+
config[key.(string)] = value
224228
return true
225229
})
226230

@@ -236,8 +240,8 @@ func (m *Manager) ConfigsWithSourceNames() map[string]interface{} {
236240
config := make(map[string]interface{}, 0)
237241

238242
m.ConfigurationMap.Range(func(key, value interface{}) bool {
239-
sValue := m.configValueBySource(key.(string), value.(string))
240-
if sValue == nil {
243+
sValue, ok := m.ConfigValueCache.Load(key.(string))
244+
if !ok || sValue == nil {
241245
return true
242246
}
243247
// each key stores its value and source name
@@ -317,43 +321,23 @@ func (m *Manager) IsKeyExist(key string) bool {
317321

318322
// GetConfig returns the value for a particular key from cache
319323
func (m *Manager) GetConfig(key string) interface{} {
320-
sourceName, ok := m.ConfigurationMap.Load(key)
321-
if !ok {
322-
return nil
323-
}
324-
return m.configValueBySource(key, sourceName.(string))
324+
val, _ := m.ConfigValueCache.Load(key)
325+
return val
325326
}
326327

327328
func (m *Manager) updateConfigurationMap(source ConfigSource, configs map[string]interface{}) error {
328329
for key := range configs {
329-
sourceName, ok := m.ConfigurationMap.Load(key)
330-
if !ok { // if key do not exist then add source
331-
m.ConfigurationMap.Store(key, source.GetSourceName())
332-
continue
333-
}
334-
335-
m.sourceMapMux.RLock()
336-
currentSource, ok := m.Sources[sourceName.(string)]
337-
m.sourceMapMux.RUnlock()
338-
if !ok {
339-
m.ConfigurationMap.Store(key, source.GetSourceName())
340-
continue
341-
}
342330

343-
currentSrcPriority := currentSource.GetPriority()
344-
if currentSrcPriority > source.GetPriority() { // lesser value has high priority
345-
m.ConfigurationMap.Store(key, source.GetSourceName())
331+
val, err := source.GetConfigurationByKey(key)
332+
if err != nil {
333+
return err
346334
}
347-
}
348-
349-
return nil
350-
}
351335

352-
func (m *Manager) updateConfigurationMapByDI(source ConfigSource, configs map[string]interface{}) error {
353-
for key := range configs {
354336
sourceName, ok := m.ConfigurationMap.Load(key)
355337
if !ok { // if key do not exist then add source
356338
m.ConfigurationMap.Store(key, source.GetSourceName())
339+
340+
m.ConfigValueCache.Store(key, val)
357341
continue
358342
}
359343

@@ -362,12 +346,15 @@ func (m *Manager) updateConfigurationMapByDI(source ConfigSource, configs map[st
362346
m.sourceMapMux.RUnlock()
363347
if !ok {
364348
m.ConfigurationMap.Store(key, source.GetSourceName())
349+
350+
m.ConfigValueCache.Store(key, val)
365351
continue
366352
}
367353

368354
currentSrcPriority := currentSource.GetPriority()
369355
if currentSrcPriority > source.GetPriority() { // lesser value has high priority
370356
m.ConfigurationMap.Store(key, source.GetSourceName())
357+
m.ConfigValueCache.Store(key, val)
371358
}
372359
}
373360

@@ -409,23 +396,39 @@ func (m *Manager) updateEvent(e *event.Event) error {
409396
return nil
410397
}
411398
openlog.Info("config update event received")
399+
412400
switch e.EventType {
413401
case event.Create, event.Update:
402+
414403
sourceName, ok := m.ConfigurationMap.Load(e.Key)
404+
405+
val := m.configValueBySource(e.Key, e.EventSource)
406+
415407
if !ok {
416408
m.ConfigurationMap.Store(e.Key, e.EventSource)
409+
410+
m.ConfigValueCache.Store(e.Key, val)
411+
417412
e.EventType = event.Create
418413
} else if sourceName == e.EventSource {
414+
415+
m.ConfigValueCache.Store(e.Key, val)
416+
419417
e.EventType = event.Update
420418
} else if sourceName != e.EventSource {
419+
421420
prioritySrc := m.getHighPrioritySource(sourceName.(string), e.EventSource)
421+
422422
if prioritySrc != nil && prioritySrc.GetSourceName() == sourceName {
423423
// if event generated from less priority source then ignore
424424
openlog.Info(fmt.Sprintf("the event source %s's priority is less then %s's, ignore",
425425
e.EventSource, sourceName))
426426
return ErrIgnoreChange
427427
}
428428
m.ConfigurationMap.Store(e.Key, e.EventSource)
429+
430+
m.ConfigValueCache.Store(e.Key, val)
431+
429432
e.EventType = event.Update
430433
}
431434

@@ -441,8 +444,12 @@ func (m *Manager) updateEvent(e *event.Event) error {
441444
source := m.findNextBestSource(e.Key, sourceName.(string))
442445
if source == nil {
443446
m.ConfigurationMap.Delete(e.Key)
447+
448+
m.ConfigValueCache.Delete(e.Key)
444449
} else {
445450
m.ConfigurationMap.Store(e.Key, source.GetSourceName())
451+
452+
m.ConfigValueCache.Store(e.Key, m.configValueBySource(e.Key, source.GetSourceName()))
446453
}
447454
}
448455

0 commit comments

Comments
 (0)