blob: cb8c9ca279fa413888f669c6d74dcbd6e2c0ae21 [file] [log] [blame]
Stephane Barbarieec0919b2018-09-05 14:14:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package model
17
18import (
19 "bytes"
20 "crypto/md5"
21 "fmt"
Stephane Barbarie126101e2018-10-11 16:18:48 -040022 "github.com/golang/protobuf/proto"
Stephane Barbarie933b09b2019-01-09 11:12:09 -050023 "github.com/opencord/voltha-go/common/log"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040024 "reflect"
25 "sort"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050026 "sync"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040027)
28
Stephane Barbariedc5022d2018-11-19 15:21:44 -050029type revCacheSingleton struct {
30 sync.RWMutex
31 Cache map[string]interface{}
32}
33
34var revCacheInstance *revCacheSingleton
35var revCacheOnce sync.Once
36
37func GetRevCache() *revCacheSingleton {
38 revCacheOnce.Do(func() {
39 revCacheInstance = &revCacheSingleton{Cache: make(map[string]interface{})}
40 })
41 return revCacheInstance
42}
Stephane Barbarieec0919b2018-09-05 14:14:29 -040043
44type NonPersistedRevision struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050045 mutex sync.RWMutex
46 Root *root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040047 Config *DataRevision
48 Children map[string][]Revision
49 Hash string
50 Branch *Branch
51 WeakRef string
52}
53
Stephane Barbariedc5022d2018-11-19 15:21:44 -050054func NewNonPersistedRevision(root *root, branch *Branch, data interface{}, children map[string][]Revision) Revision {
55 r := &NonPersistedRevision{}
56 r.Root = root
57 r.Branch = branch
58 r.Config = NewDataRevision(root, data)
59 r.Children = children
Stephane Barbariedc5022d2018-11-19 15:21:44 -050060 return r
Stephane Barbarieec0919b2018-09-05 14:14:29 -040061}
62
63func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050064 npr.mutex.Lock()
65 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040066 npr.Config = config
67}
68
69func (npr *NonPersistedRevision) GetConfig() *DataRevision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050070 npr.mutex.Lock()
71 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040072 return npr.Config
73}
74
Stephane Barbarie3cb01222019-01-16 17:15:56 -050075func (npr *NonPersistedRevision) SetAllChildren(children map[string][]Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050076 npr.mutex.Lock()
77 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040078 npr.Children = children
79}
80
Stephane Barbarie3cb01222019-01-16 17:15:56 -050081func (npr *NonPersistedRevision) SetChildren(name string, children []Revision) {
82 npr.mutex.Lock()
83 defer npr.mutex.Unlock()
84 if _, exists := npr.Children[name]; exists {
85 npr.Children[name] = children
86 }
87}
88
89func (npr *NonPersistedRevision) GetAllChildren() map[string][]Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050090 npr.mutex.Lock()
91 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040092 return npr.Children
93}
94
Stephane Barbarie3cb01222019-01-16 17:15:56 -050095func (npr *NonPersistedRevision) GetChildren(name string) []Revision {
96 npr.mutex.Lock()
97 defer npr.mutex.Unlock()
98 if _, exists := npr.Children[name]; exists {
99 return npr.Children[name]
100 }
101 return nil
102}
103
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400104func (npr *NonPersistedRevision) SetHash(hash string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500105 npr.mutex.Lock()
106 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400107 npr.Hash = hash
108}
109
110func (npr *NonPersistedRevision) GetHash() string {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500111 //npr.mutex.Lock()
112 //defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400113 return npr.Hash
114}
115
116func (npr *NonPersistedRevision) ClearHash() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500117 npr.mutex.Lock()
118 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400119 npr.Hash = ""
120}
121
122func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500123 npr.mutex.Lock()
124 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400125 npr.Branch = branch
126}
127
128func (npr *NonPersistedRevision) GetBranch() *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500129 npr.mutex.Lock()
130 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400131 return npr.Branch
132}
133
134func (npr *NonPersistedRevision) GetData() interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500135 npr.mutex.Lock()
136 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400137 if npr.Config == nil {
138 return nil
139 }
140 return npr.Config.Data
141}
142
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400143func (npr *NonPersistedRevision) GetNode() *node {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500144 npr.mutex.Lock()
145 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400146 return npr.Branch.Node
147}
148
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500149func (npr *NonPersistedRevision) Finalize(skipOnExist bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500150 GetRevCache().Lock()
151 defer GetRevCache().Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400152
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500153 if !skipOnExist {
154 npr.Hash = npr.hashContent()
155 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500156 if _, exists := GetRevCache().Cache[npr.Hash]; !exists {
157 GetRevCache().Cache[npr.Hash] = npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400158 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500159 if _, exists := GetRevCache().Cache[npr.Config.Hash]; !exists {
160 GetRevCache().Cache[npr.Config.Hash] = npr.Config
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400161 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500162 npr.Config = GetRevCache().Cache[npr.Config.Hash].(*DataRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400163 }
164}
165
166func (npr *NonPersistedRevision) hashContent() string {
167 var buffer bytes.Buffer
168 var childrenKeys []string
169
170 if npr.Config != nil {
171 buffer.WriteString(npr.Config.Hash)
172 }
173
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500174 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400175 childrenKeys = append(childrenKeys, key)
176 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500177
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400178 sort.Strings(childrenKeys)
179
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500180 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400181 // Loop through sorted Children keys
182 for _, key := range childrenKeys {
183 for _, child := range npr.Children[key] {
184 if child != nil && child.GetHash() != "" {
185 buffer.WriteString(child.GetHash())
186 }
187 }
188 }
189 }
190
191 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
192}
193
194func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500195 // 1. Clone the data to avoid any concurrent access issues
196 // 2. The current rev might still be pointing to an old config
197 // thus, force the revision to get its latest value
198 latestRev := npr.GetBranch().GetLatest()
199 originalData := proto.Clone(latestRev.GetData().(proto.Message))
200
201 data := originalData
202 // Get back to the interface type
203 //data := reflect.ValueOf(originalData).Interface()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400204
205 if depth != 0 {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500206 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400207 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
208 if field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500209 for _, rev := range latestRev.GetChildren(fieldName) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400210 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400211 foundEntry := false
212 for i := 0; i < childDataHolder.Len(); i++ {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500213 cdh_if := childDataHolder.Index(i).Interface()
214 if cdh_if.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400215 foundEntry = true
216 break
217 }
218 }
219 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500220 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400221 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
222 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400223 }
224 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500225 if revs := latestRev.GetChildren(fieldName); revs != nil && len(revs) > 0 {
226 rev := latestRev.GetChildren(fieldName)[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400227 if rev != nil {
228 childData := rev.Get(depth - 1)
229 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
230 childDataHolder = reflect.ValueOf(childData)
231 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400232 }
233 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400234 }
235 // Merge child data with cloned object
236 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
237 }
238 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400239
240 result := data
241
242 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500243 // We need to send back a copy of the retrieved object
244 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400245 }
246
247 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400248}
249
250func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500251 npr.mutex.Lock()
252 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400253
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500254 if npr.Config.Data != nil && npr.Config.hashData(npr.Root, data) == npr.Config.Hash {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500255 log.Debugw("stored-data-matches-latest", log.Fields{"stored": npr.Config.Data, "provided": data})
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500256 return npr
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500257 }
258
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500259 newRev := NonPersistedRevision{}
260 newRev.Config = NewDataRevision(npr.Root, data)
261 newRev.Hash = npr.Hash
262 newRev.Branch = branch
263
264 newRev.Children = make(map[string][]Revision)
265 for entryName, childrenEntry := range npr.Children {
266 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
267 }
268
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500269 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400270
271 return &newRev
272}
273
274func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500275 npr.mutex.Lock()
276 defer npr.mutex.Unlock()
277
278 updatedRev := npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400279
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500280 // Verify if the map contains already contains an entry matching the name value
281 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
282 if _, exists := updatedRev.Children[name]; exists {
283 // Go through all child hashes and save their index within the map
284 existChildMap := make(map[string]int)
285 for i, child := range updatedRev.Children[name] {
286 existChildMap[child.GetHash()] = i
287 }
288
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500289 for _, newChild := range children {
290 if _, childExists := existChildMap[newChild.GetHash()]; !childExists {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500291 // revision is not present in the existing list... add it
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500292 updatedRev.Children[name] = append(updatedRev.Children[name], newChild)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500293 } else {
294 // replace
295 updatedRev.Children[name][existChildMap[newChild.GetHash()]] = newChild
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500296 }
297 }
298 } else {
299 // Map entry does not exist, thus just create a new entry and assign the provided revisions
300 updatedRev.Children[name] = make([]Revision, len(children))
301 copy(updatedRev.Children[name], children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500302 }
303
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500304 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
305 updatedRev.Hash = npr.Hash
306 updatedRev.Branch = branch
307 updatedRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400308
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500309 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400310}
311
312func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500313 npr.mutex.Lock()
314 defer npr.mutex.Unlock()
315
316 newRev := &NonPersistedRevision{}
317 newRev.Config = npr.Config
318 newRev.Hash = npr.Hash
319 newRev.Branch = branch
320 newRev.Children = make(map[string][]Revision)
321 for entryName, childrenEntry := range npr.Children {
322 newRev.Children[entryName] = make([]Revision, len(childrenEntry))
323 copy(newRev.Children[entryName], childrenEntry)
324 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500325 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400326
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500327 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400328}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400329
330func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500331 GetRevCache().Lock()
332 defer GetRevCache().Unlock()
333
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500334 if includeConfig {
335 delete(GetRevCache().Cache, npr.Config.Hash)
336 }
337 delete(GetRevCache().Cache, npr.Hash)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400338}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500339
340func (npr *NonPersistedRevision) LoadFromPersistence(path string, txid string) []Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500341 // stub... required by interface
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500342 return nil
343}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500344
345func (npr *NonPersistedRevision) SetupWatch(key string) {
346 // stub ... required by interface
347}