blob: 3c39e01ffbaa3446274d562f08741ded09e1bd3d [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
Stephane Barbarief7fc1782019-03-28 22:33:41 -040052 Name string
Stephane Barbarieec0919b2018-09-05 14:14:29 -040053}
54
Stephane Barbariedc5022d2018-11-19 15:21:44 -050055func NewNonPersistedRevision(root *root, branch *Branch, data interface{}, children map[string][]Revision) Revision {
56 r := &NonPersistedRevision{}
57 r.Root = root
58 r.Branch = branch
59 r.Config = NewDataRevision(root, data)
60 r.Children = children
Stephane Barbarief7fc1782019-03-28 22:33:41 -040061 r.Hash = r.hashContent()
Stephane Barbariedc5022d2018-11-19 15:21:44 -050062 return r
Stephane Barbarieec0919b2018-09-05 14:14:29 -040063}
64
65func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050066 npr.mutex.Lock()
67 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040068 npr.Config = config
69}
70
71func (npr *NonPersistedRevision) GetConfig() *DataRevision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050072 npr.mutex.Lock()
73 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040074 return npr.Config
75}
76
Stephane Barbarie3cb01222019-01-16 17:15:56 -050077func (npr *NonPersistedRevision) SetAllChildren(children map[string][]Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050078 npr.mutex.Lock()
79 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040080 npr.Children = children
81}
82
Stephane Barbarie3cb01222019-01-16 17:15:56 -050083func (npr *NonPersistedRevision) SetChildren(name string, children []Revision) {
84 npr.mutex.Lock()
85 defer npr.mutex.Unlock()
86 if _, exists := npr.Children[name]; exists {
87 npr.Children[name] = children
88 }
89}
90
91func (npr *NonPersistedRevision) GetAllChildren() map[string][]Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050092 npr.mutex.Lock()
93 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040094 return npr.Children
95}
96
Stephane Barbarie3cb01222019-01-16 17:15:56 -050097func (npr *NonPersistedRevision) GetChildren(name string) []Revision {
98 npr.mutex.Lock()
99 defer npr.mutex.Unlock()
100 if _, exists := npr.Children[name]; exists {
101 return npr.Children[name]
102 }
103 return nil
104}
105
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400106func (npr *NonPersistedRevision) SetHash(hash string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500107 npr.mutex.Lock()
108 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400109 npr.Hash = hash
110}
111
112func (npr *NonPersistedRevision) GetHash() string {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500113 //npr.mutex.Lock()
114 //defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400115 return npr.Hash
116}
117
118func (npr *NonPersistedRevision) ClearHash() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500119 npr.mutex.Lock()
120 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400121 npr.Hash = ""
122}
123
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400124func (npr *NonPersistedRevision) GetName() string {
125 //npr.mutex.Lock()
126 //defer npr.mutex.Unlock()
127 return npr.Name
128}
129
130func (npr *NonPersistedRevision) SetName(name string) {
131 //npr.mutex.Lock()
132 //defer npr.mutex.Unlock()
133 npr.Name = name
134}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400135func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500136 npr.mutex.Lock()
137 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400138 npr.Branch = branch
139}
140
141func (npr *NonPersistedRevision) GetBranch() *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500142 npr.mutex.Lock()
143 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400144 return npr.Branch
145}
146
147func (npr *NonPersistedRevision) GetData() interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500148 npr.mutex.Lock()
149 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400150 if npr.Config == nil {
151 return nil
152 }
153 return npr.Config.Data
154}
155
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400156func (npr *NonPersistedRevision) GetNode() *node {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500157 npr.mutex.Lock()
158 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400159 return npr.Branch.Node
160}
161
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500162func (npr *NonPersistedRevision) Finalize(skipOnExist bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500163 GetRevCache().Lock()
164 defer GetRevCache().Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400165
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500166 if !skipOnExist {
167 npr.Hash = npr.hashContent()
168 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500169 if _, exists := GetRevCache().Cache[npr.Hash]; !exists {
170 GetRevCache().Cache[npr.Hash] = npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400171 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500172 if _, exists := GetRevCache().Cache[npr.Config.Hash]; !exists {
173 GetRevCache().Cache[npr.Config.Hash] = npr.Config
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400174 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500175 npr.Config = GetRevCache().Cache[npr.Config.Hash].(*DataRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400176 }
177}
178
179func (npr *NonPersistedRevision) hashContent() string {
180 var buffer bytes.Buffer
181 var childrenKeys []string
182
183 if npr.Config != nil {
184 buffer.WriteString(npr.Config.Hash)
185 }
186
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500187 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400188 childrenKeys = append(childrenKeys, key)
189 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500190
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400191 sort.Strings(childrenKeys)
192
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500193 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400194 // Loop through sorted Children keys
195 for _, key := range childrenKeys {
196 for _, child := range npr.Children[key] {
197 if child != nil && child.GetHash() != "" {
198 buffer.WriteString(child.GetHash())
199 }
200 }
201 }
202 }
203
204 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
205}
206
207func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500208 // 1. Clone the data to avoid any concurrent access issues
209 // 2. The current rev might still be pointing to an old config
210 // thus, force the revision to get its latest value
211 latestRev := npr.GetBranch().GetLatest()
212 originalData := proto.Clone(latestRev.GetData().(proto.Message))
213
214 data := originalData
215 // Get back to the interface type
216 //data := reflect.ValueOf(originalData).Interface()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400217
218 if depth != 0 {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500219 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400220 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
221 if field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500222 for _, rev := range latestRev.GetChildren(fieldName) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400223 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400224 foundEntry := false
225 for i := 0; i < childDataHolder.Len(); i++ {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500226 cdh_if := childDataHolder.Index(i).Interface()
227 if cdh_if.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400228 foundEntry = true
229 break
230 }
231 }
232 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500233 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400234 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
235 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400236 }
237 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500238 if revs := latestRev.GetChildren(fieldName); revs != nil && len(revs) > 0 {
239 rev := latestRev.GetChildren(fieldName)[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400240 if rev != nil {
241 childData := rev.Get(depth - 1)
242 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
243 childDataHolder = reflect.ValueOf(childData)
244 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400245 }
246 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400247 }
248 // Merge child data with cloned object
249 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
250 }
251 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400252
253 result := data
254
255 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500256 // We need to send back a copy of the retrieved object
257 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400258 }
259
260 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400261}
262
263func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500264 npr.mutex.Lock()
265 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400266
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500267 if npr.Config.Data != nil && npr.Config.hashData(npr.Root, data) == npr.Config.Hash {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500268 log.Debugw("stored-data-matches-latest", log.Fields{"stored": npr.Config.Data, "provided": data})
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500269 return npr
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500270 }
271
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500272 newRev := NonPersistedRevision{}
273 newRev.Config = NewDataRevision(npr.Root, data)
274 newRev.Hash = npr.Hash
275 newRev.Branch = branch
276
277 newRev.Children = make(map[string][]Revision)
278 for entryName, childrenEntry := range npr.Children {
279 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
280 }
281
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500282 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400283
284 return &newRev
285}
286
287func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500288 npr.mutex.Lock()
289 defer npr.mutex.Unlock()
290
291 updatedRev := npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400292
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500293 // Verify if the map contains already contains an entry matching the name value
294 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
295 if _, exists := updatedRev.Children[name]; exists {
296 // Go through all child hashes and save their index within the map
297 existChildMap := make(map[string]int)
298 for i, child := range updatedRev.Children[name] {
299 existChildMap[child.GetHash()] = i
300 }
301
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500302 for _, newChild := range children {
303 if _, childExists := existChildMap[newChild.GetHash()]; !childExists {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500304 // revision is not present in the existing list... add it
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500305 updatedRev.Children[name] = append(updatedRev.Children[name], newChild)
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500306 } else {
307 // replace
308 updatedRev.Children[name][existChildMap[newChild.GetHash()]] = newChild
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500309 }
310 }
311 } else {
312 // Map entry does not exist, thus just create a new entry and assign the provided revisions
313 updatedRev.Children[name] = make([]Revision, len(children))
314 copy(updatedRev.Children[name], children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500315 }
316
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500317 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
318 updatedRev.Hash = npr.Hash
319 updatedRev.Branch = branch
320 updatedRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400321
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500322 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400323}
324
325func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500326 npr.mutex.Lock()
327 defer npr.mutex.Unlock()
328
Stephane Barbariec53a2752019-03-08 17:50:10 -0500329 newRev := npr
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500330 newRev.Config = npr.Config
331 newRev.Hash = npr.Hash
332 newRev.Branch = branch
333 newRev.Children = make(map[string][]Revision)
Stephane Barbariec53a2752019-03-08 17:50:10 -0500334 for entryName, childrenEntry := range children {
335 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500336 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500337 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400338
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500339 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400340}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400341
342func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500343 GetRevCache().Lock()
344 defer GetRevCache().Unlock()
345
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500346 if includeConfig {
347 delete(GetRevCache().Cache, npr.Config.Hash)
348 }
349 delete(GetRevCache().Cache, npr.Hash)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400350}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500351
352func (npr *NonPersistedRevision) LoadFromPersistence(path string, txid string) []Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500353 // stub... required by interface
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500354 return nil
355}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500356
357func (npr *NonPersistedRevision) SetupWatch(key string) {
358 // stub ... required by interface
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400359}
360
361func (pr *NonPersistedRevision) StorageDrop(txid string, includeConfig bool) {
362 // stub ... required by interface
363}