-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconcurrent_dot_map.go
145 lines (135 loc) · 3.24 KB
/
concurrent_dot_map.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package dotmap
import (
"strings"
"sync"
)
type ConcurrentMap struct {
mlock *sync.RWMutex // safely Allow Multiple Readers
data Map
}
func New() *ConcurrentMap{
return &ConcurrentMap{
mlock: new(sync.RWMutex),
data: map[string]interface{}{},
}
}
/*
concurrent safe set of a key on the map
*/
func (mm *ConcurrentMap) Set(key string, value interface{}){
mm.mlock.Lock()
mm.data.Set(key, value)
mm.mlock.Unlock()
}
/*
Resets map content data
*/
func (mm *ConcurrentMap) Reset(data map[string]interface{}) {
mm.mlock.Lock()
mm.data = data
mm.mlock.Unlock()
}
/*
concurrent safe of key readings from the map
*/
func (mm *ConcurrentMap) Get(key string) (interface{}, bool) {
mm.mlock.RLock()
r, ok := mm.data.Get(key)
mm.mlock.RUnlock()
return r, ok
}
/*
concurrent safe marshal function that serializes dotmap to requested format
*/
func (mm *ConcurrentMap) Bytes(marshal func(v interface{}) ([]byte, error)) ([]byte, error) {
mm.mlock.RLock()
defer mm.mlock.RUnlock()
return mm.data.Bytes(marshal)
}
/*
Updates internal configuration map key with given value
*/
func UpdateDotMap(mm *ConcurrentMap, key []string, value string) error {
if len(key) > 1 {
//searching for composite-key in map tree
var cont = true
var i = 0
var item = &mm.data
for i = 0; i < len(key)-1 && cont; i++ {
k := key[i]
//searching for composite-key in map tree
item, cont = item.GetChild(k)
}
if item == nil {
// if the child tree is not complete, build it and set leaf value
//lastValidKey := key[i-1]
//composite-key full child tree not found. creating it from last valid key
mm.CreateChain(key, i-1, value)
}
if item != nil {
// if the child tree is complete, just set the leaf child value
//updating composite-key in map tree with value
item.Set(key[len(key)-1], value)
}
} else {
//updating single-key in map tree
mm.Set(key[0], value)
}
return nil
}
/*
Reads internal configuration map key with given value
*/
func GetDotMap(mm *ConcurrentMap, k string) (interface{}, bool) {
key := strings.Split(k, ".")
if len(key) > 1 {
//searching for composite-key in map tree
var cont = true
var i = 0
var item = &mm.data
for i = 0; i < len(key)-1 && cont; i++ {
k := key[i]
//searching for composite-key in map tree
item, cont = item.GetChild(k)
}
if item != nil {
// if the child tree is complete, just set the leaf child value
//updating composite-key in map tree with value
return item.Get(key[len(key)-1])
}
return nil, false
}
return mm.Get(key[0])
}
/*
Creates a new key chain for non existing keys
*/
func (mm *ConcurrentMap) CreateChain(key []string, lastValid int, value interface{}) {
mm.mlock.RLock()
// 1 fetch last valid child
var item *Map
for i := 0; i < lastValid; i++ {
k := key[i]
//searching for child in map tree
item, _ = mm.data.GetChild(k)
}
mm.mlock.RUnlock()
if item == nil {
item = &Map{}
mm.Set(key[0], item)
lastValid++
}
// 2 from last valid child, create missing childs
mm.mlock.Lock()
last := len(key)-1
for i := lastValid; i < last; i++ {
k := key[i]
//creating new child in map tree
lastChild := &Map{}
(*item)[k] = lastChild
item = lastChild
}
// once created full chain, set the value of the leaf item
(*item)[key[last]]=value
mm.mlock.Unlock()
}