blob: 765bbaf06301be37e22408e0da851b32f3539e19 [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 Barbariedc5022d2018-11-19 15:21:44 -0500153 npr.Hash = npr.hashContent()
154
155 if _, exists := GetRevCache().Cache[npr.Hash]; !exists {
156 GetRevCache().Cache[npr.Hash] = npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400157 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500158 if _, exists := GetRevCache().Cache[npr.Config.Hash]; !exists {
159 GetRevCache().Cache[npr.Config.Hash] = npr.Config
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400160 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500161 npr.Config = GetRevCache().Cache[npr.Config.Hash].(*DataRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400162 }
163}
164
165func (npr *NonPersistedRevision) hashContent() string {
166 var buffer bytes.Buffer
167 var childrenKeys []string
168
169 if npr.Config != nil {
170 buffer.WriteString(npr.Config.Hash)
171 }
172
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500173 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400174 childrenKeys = append(childrenKeys, key)
175 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500176
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400177 sort.Strings(childrenKeys)
178
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500179 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400180 // Loop through sorted Children keys
181 for _, key := range childrenKeys {
182 for _, child := range npr.Children[key] {
183 if child != nil && child.GetHash() != "" {
184 buffer.WriteString(child.GetHash())
185 }
186 }
187 }
188 }
189
190 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
191}
192
193func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500194 // 1. Clone the data to avoid any concurrent access issues
195 // 2. The current rev might still be pointing to an old config
196 // thus, force the revision to get its latest value
197 latestRev := npr.GetBranch().GetLatest()
198 originalData := proto.Clone(latestRev.GetData().(proto.Message))
199
200 data := originalData
201 // Get back to the interface type
202 //data := reflect.ValueOf(originalData).Interface()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400203
204 if depth != 0 {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500205 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400206 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
207 if field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500208 for _, rev := range latestRev.GetChildren(fieldName) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400209 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400210 foundEntry := false
211 for i := 0; i < childDataHolder.Len(); i++ {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500212 cdh_if := childDataHolder.Index(i).Interface()
213 if cdh_if.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400214 foundEntry = true
215 break
216 }
217 }
218 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500219 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400220 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
221 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400222 }
223 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500224 if revs := latestRev.GetChildren(fieldName); revs != nil && len(revs) > 0 {
225 rev := latestRev.GetChildren(fieldName)[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400226 if rev != nil {
227 childData := rev.Get(depth - 1)
228 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
229 childDataHolder = reflect.ValueOf(childData)
230 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400231 }
232 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400233 }
234 // Merge child data with cloned object
235 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
236 }
237 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400238
239 result := data
240
241 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500242 // We need to send back a copy of the retrieved object
243 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400244 }
245
246 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400247}
248
249func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500250 npr.mutex.Lock()
251 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400252
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500253 if npr.Config.Data != nil && npr.Config.Data == data {
254 log.Debugw("stored-data-matches-latest", log.Fields{"stored": npr.Config.Data, "provided": data})
255 return nil
256 }
257
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500258 newRev := NonPersistedRevision{}
259 newRev.Config = NewDataRevision(npr.Root, data)
260 newRev.Hash = npr.Hash
261 newRev.Branch = branch
262
263 newRev.Children = make(map[string][]Revision)
264 for entryName, childrenEntry := range npr.Children {
265 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
266 }
267
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500268 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400269
270 return &newRev
271}
272
273func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500274 npr.mutex.Lock()
275 defer npr.mutex.Unlock()
276
277 updatedRev := npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400278
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500279 // Verify if the map contains already contains an entry matching the name value
280 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
281 if _, exists := updatedRev.Children[name]; exists {
282 // Go through all child hashes and save their index within the map
283 existChildMap := make(map[string]int)
284 for i, child := range updatedRev.Children[name] {
285 existChildMap[child.GetHash()] = i
286 }
287
288 // Identify the revisions that are not present in the existing list and add them
289 for _, newChild := range children {
290 if _, childExists := existChildMap[newChild.GetHash()]; !childExists {
291 updatedRev.Children[name] = append(updatedRev.Children[name], newChild)
292 }
293 }
294 } else {
295 // Map entry does not exist, thus just create a new entry and assign the provided revisions
296 updatedRev.Children[name] = make([]Revision, len(children))
297 copy(updatedRev.Children[name], children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500298 }
299
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500300 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
301 updatedRev.Hash = npr.Hash
302 updatedRev.Branch = branch
303 updatedRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400304
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500305 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400306}
307
308func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500309 npr.mutex.Lock()
310 defer npr.mutex.Unlock()
311
312 newRev := &NonPersistedRevision{}
313 newRev.Config = npr.Config
314 newRev.Hash = npr.Hash
315 newRev.Branch = branch
316 newRev.Children = make(map[string][]Revision)
317 for entryName, childrenEntry := range npr.Children {
318 newRev.Children[entryName] = make([]Revision, len(childrenEntry))
319 copy(newRev.Children[entryName], childrenEntry)
320 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500321 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400322
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500323 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400324}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400325
326func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500327 GetRevCache().Lock()
328 defer GetRevCache().Unlock()
329
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500330 if includeConfig {
331 delete(GetRevCache().Cache, npr.Config.Hash)
332 }
333 delete(GetRevCache().Cache, npr.Hash)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400334}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500335
336func (npr *NonPersistedRevision) LoadFromPersistence(path string, txid string) []Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500337 // stub... required by interface
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500338 return nil
339}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500340
341func (npr *NonPersistedRevision) SetupWatch(key string) {
342 // stub ... required by interface
343}