blob: 384caed1cca01be6c811105ae4a3c7181aa33688 [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"
Stephane Barbarieef6650d2019-07-18 12:15:09 -040020 "context"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040021 "crypto/md5"
22 "fmt"
Stephane Barbarie126101e2018-10-11 16:18:48 -040023 "github.com/golang/protobuf/proto"
Scott Baker807addd2019-10-24 15:16:21 -070024 "github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
25 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040026 "reflect"
27 "sort"
David Bainbridgebdae73c2019-10-23 17:05:41 +000028 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050029 "sync"
Stephane Barbarie802aca42019-05-21 12:19:28 -040030 "time"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040031)
32
Stephane Barbarie40fd3b22019-04-23 21:50:47 -040033// TODO: Cache logic will have to be revisited to cleanup unused entries in memory (disabled for now)
34//
Stephane Barbarie7512fc82019-05-07 12:25:46 -040035type revCacheSingleton struct {
36 sync.RWMutex
37 Cache sync.Map
38}
39
Stephane Barbarieef6650d2019-07-18 12:15:09 -040040func (s *revCacheSingleton) Get(path string) (interface{}, bool) {
41 return s.Cache.Load(path)
42}
43func (s *revCacheSingleton) Set(path string, value interface{}) {
44 s.Cache.Store(path, value)
45}
46func (s *revCacheSingleton) Delete(path string) {
47 s.Cache.Delete(path)
48}
49
Stephane Barbarie7512fc82019-05-07 12:25:46 -040050var revCacheInstance *revCacheSingleton
51var revCacheOnce sync.Once
52
53func GetRevCache() *revCacheSingleton {
54 revCacheOnce.Do(func() {
55 revCacheInstance = &revCacheSingleton{Cache: sync.Map{}}
56 })
57 return revCacheInstance
58}
Stephane Barbarieec0919b2018-09-05 14:14:29 -040059
60type NonPersistedRevision struct {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -040061 mutex sync.RWMutex
62 Root *root
63 Config *DataRevision
64 childrenLock sync.RWMutex
65 Children map[string][]Revision
66 Hash string
67 Branch *Branch
68 WeakRef string
69 Name string
Stephane Barbarie802aca42019-05-21 12:19:28 -040070 lastUpdate time.Time
Stephane Barbarieec0919b2018-09-05 14:14:29 -040071}
72
Stephane Barbariedc5022d2018-11-19 15:21:44 -050073func NewNonPersistedRevision(root *root, branch *Branch, data interface{}, children map[string][]Revision) Revision {
74 r := &NonPersistedRevision{}
75 r.Root = root
76 r.Branch = branch
77 r.Config = NewDataRevision(root, data)
78 r.Children = children
Stephane Barbarief7fc1782019-03-28 22:33:41 -040079 r.Hash = r.hashContent()
Stephane Barbariedc5022d2018-11-19 15:21:44 -050080 return r
Stephane Barbarieec0919b2018-09-05 14:14:29 -040081}
82
83func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050084 npr.mutex.Lock()
85 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040086 npr.Config = config
87}
88
89func (npr *NonPersistedRevision) GetConfig() *DataRevision {
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.Config
93}
94
Stephane Barbarie3cb01222019-01-16 17:15:56 -050095func (npr *NonPersistedRevision) SetAllChildren(children map[string][]Revision) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -040096 npr.childrenLock.Lock()
97 defer npr.childrenLock.Unlock()
98 npr.Children = make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -040099
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400100 for key, value := range children {
101 npr.Children[key] = make([]Revision, len(value))
102 copy(npr.Children[key], value)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500103 }
104}
105
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400106func (npr *NonPersistedRevision) SetChildren(name string, children []Revision) {
107 npr.childrenLock.Lock()
108 defer npr.childrenLock.Unlock()
109
110 npr.Children[name] = make([]Revision, len(children))
111 copy(npr.Children[name], children)
112}
113
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500114func (npr *NonPersistedRevision) GetAllChildren() map[string][]Revision {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400115 npr.childrenLock.Lock()
116 defer npr.childrenLock.Unlock()
117
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400118 return npr.Children
119}
120
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500121func (npr *NonPersistedRevision) GetChildren(name string) []Revision {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400122 npr.childrenLock.Lock()
123 defer npr.childrenLock.Unlock()
124
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500125 if _, exists := npr.Children[name]; exists {
126 return npr.Children[name]
127 }
128 return nil
129}
130
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400131func (npr *NonPersistedRevision) SetHash(hash string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500132 npr.mutex.Lock()
133 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400134 npr.Hash = hash
135}
136
137func (npr *NonPersistedRevision) GetHash() string {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500138 //npr.mutex.Lock()
139 //defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400140 return npr.Hash
141}
142
143func (npr *NonPersistedRevision) ClearHash() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500144 npr.mutex.Lock()
145 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400146 npr.Hash = ""
147}
148
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400149func (npr *NonPersistedRevision) GetName() string {
150 //npr.mutex.Lock()
151 //defer npr.mutex.Unlock()
152 return npr.Name
153}
154
155func (npr *NonPersistedRevision) SetName(name string) {
156 //npr.mutex.Lock()
157 //defer npr.mutex.Unlock()
158 npr.Name = name
159}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400160func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500161 npr.mutex.Lock()
162 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400163 npr.Branch = branch
164}
165
166func (npr *NonPersistedRevision) GetBranch() *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500167 npr.mutex.Lock()
168 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400169 return npr.Branch
170}
171
172func (npr *NonPersistedRevision) GetData() interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500173 npr.mutex.Lock()
174 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400175 if npr.Config == nil {
176 return nil
177 }
178 return npr.Config.Data
179}
180
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400181func (npr *NonPersistedRevision) GetNode() *node {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500182 npr.mutex.Lock()
183 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400184 return npr.Branch.Node
185}
186
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500187func (npr *NonPersistedRevision) Finalize(skipOnExist bool) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400188 npr.Hash = npr.hashContent()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400189}
190
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400191// hashContent generates a hash string based on the contents of the revision.
192// The string should be unique to avoid conflicts with other revisions
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400193func (npr *NonPersistedRevision) hashContent() string {
194 var buffer bytes.Buffer
195 var childrenKeys []string
196
197 if npr.Config != nil {
198 buffer.WriteString(npr.Config.Hash)
199 }
200
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400201 if npr.Name != "" {
202 buffer.WriteString(npr.Name)
203 }
204
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500205 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400206 childrenKeys = append(childrenKeys, key)
207 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500208
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400209 sort.Strings(childrenKeys)
210
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500211 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400212 // Loop through sorted Children keys
213 for _, key := range childrenKeys {
214 for _, child := range npr.Children[key] {
215 if child != nil && child.GetHash() != "" {
216 buffer.WriteString(child.GetHash())
217 }
218 }
219 }
220 }
221
222 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
223}
224
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400225// Get will retrieve the data for the current revision
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400226func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500227 // 1. Clone the data to avoid any concurrent access issues
228 // 2. The current rev might still be pointing to an old config
229 // thus, force the revision to get its latest value
230 latestRev := npr.GetBranch().GetLatest()
231 originalData := proto.Clone(latestRev.GetData().(proto.Message))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500232 data := originalData
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400233
234 if depth != 0 {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400235 // FIXME: Traversing the struct through reflection sometimes corrupts the data.
236 // Unlike the original python implementation, golang structs are not lazy loaded.
237 // Keeping this non-critical logic for now, but Get operations should be forced to
238 // depth=0 to avoid going through the following loop.
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500239 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400240 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
241 if field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500242 for _, rev := range latestRev.GetChildren(fieldName) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400243 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400244 foundEntry := false
245 for i := 0; i < childDataHolder.Len(); i++ {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500246 cdh_if := childDataHolder.Index(i).Interface()
247 if cdh_if.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400248 foundEntry = true
249 break
250 }
251 }
252 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500253 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400254 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
255 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400256 }
257 } else {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400258 if revs := npr.GetBranch().GetLatest().GetChildren(fieldName); revs != nil && len(revs) > 0 {
259 rev := revs[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400260 if rev != nil {
261 childData := rev.Get(depth - 1)
262 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
263 childDataHolder = reflect.ValueOf(childData)
264 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400265 }
266 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400267 }
268 // Merge child data with cloned object
269 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
270 }
271 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400272
273 result := data
274
275 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500276 // We need to send back a copy of the retrieved object
277 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400278 }
279
280 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400281}
282
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400283// UpdateData will refresh the data content of the revision
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400284func (npr *NonPersistedRevision) UpdateData(ctx context.Context, data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500285 npr.mutex.Lock()
286 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400287
David Bainbridgebdae73c2019-10-23 17:05:41 +0000288 log.Debugw("update-data", log.Fields{"hash": npr.GetHash(), "current": npr.Config.Data, "provided": data})
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400289
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400290 // Do not update the revision if data is the same
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500291 if npr.Config.Data != nil && npr.Config.hashData(npr.Root, data) == npr.Config.Hash {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500292 log.Debugw("stored-data-matches-latest", log.Fields{"stored": npr.Config.Data, "provided": data})
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500293 return npr
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500294 }
295
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400296 // Construct a new revision based on the current one
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500297 newRev := NonPersistedRevision{}
298 newRev.Config = NewDataRevision(npr.Root, data)
299 newRev.Hash = npr.Hash
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400300 newRev.Root = npr.Root
301 newRev.Name = npr.Name
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500302 newRev.Branch = branch
Stephane Barbarie802aca42019-05-21 12:19:28 -0400303 newRev.lastUpdate = npr.lastUpdate
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500304
305 newRev.Children = make(map[string][]Revision)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400306 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500307 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
308 }
309
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500310 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400311
David Bainbridgebdae73c2019-10-23 17:05:41 +0000312 log.Debugw("update-data-complete", log.Fields{"updated": newRev.Config.Data, "provided": data})
313
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400314 return &newRev
315}
316
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400317// UpdateChildren will refresh the list of children with the provided ones
318// It will carefully go through the list and ensure that no child is lost
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400319func (npr *NonPersistedRevision) UpdateChildren(ctx context.Context, name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500320 npr.mutex.Lock()
321 defer npr.mutex.Unlock()
322
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400323 // Construct a new revision based on the current one
324 updatedRev := &NonPersistedRevision{}
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500325 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
326 updatedRev.Hash = npr.Hash
327 updatedRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400328 updatedRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400329 updatedRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400330
331 updatedRev.Children = make(map[string][]Revision)
332 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
333 updatedRev.Children[entryName] = append(updatedRev.Children[entryName], childrenEntry...)
334 }
335
336 var updatedChildren []Revision
337
338 // Verify if the map contains already contains an entry matching the name value
339 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
340 if existingChildren := branch.GetLatest().GetChildren(name); existingChildren != nil {
341 // Construct a map of unique child names with the respective index value
342 // for the children in the existing revision as well as the new ones
343 existingNames := make(map[string]int)
344 newNames := make(map[string]int)
345
346 for i, newChild := range children {
347 newNames[newChild.GetName()] = i
348 }
349
350 for i, existingChild := range existingChildren {
351 existingNames[existingChild.GetName()] = i
352
353 // If an existing entry is not in the new list, add it to the updated list, so it is not forgotten
354 if _, exists := newNames[existingChild.GetName()]; !exists {
355 updatedChildren = append(updatedChildren, existingChild)
356 }
357 }
358
359 log.Debugw("existing-children-names", log.Fields{"hash": npr.GetHash(), "names": existingNames})
360
361 // Merge existing and new children
362 for _, newChild := range children {
363 nameIndex, nameExists := existingNames[newChild.GetName()]
364
365 // Does the existing list contain a child with that name?
366 if nameExists {
367 // Check if the data has changed or not
368 if existingChildren[nameIndex].GetData().(proto.Message).String() != newChild.GetData().(proto.Message).String() {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400369 log.Debugw("replacing-existing-child", log.Fields{
370 "old-hash": existingChildren[nameIndex].GetHash(),
371 "old-data": existingChildren[nameIndex].GetData(),
372 "new-hash": newChild.GetHash(),
373 "new-data": newChild.GetData(),
374 })
375
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400376 // replace entry
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400377 newChild.GetNode().SetRoot(existingChildren[nameIndex].GetNode().GetRoot())
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400378 updatedChildren = append(updatedChildren, newChild)
379 } else {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400380 log.Debugw("keeping-existing-child", log.Fields{
381 "old-hash": existingChildren[nameIndex].GetHash(),
382 "old-data": existingChildren[nameIndex].GetData(),
383 "new-hash": newChild.GetHash(),
384 "new-data": newChild.GetData(),
385 })
386
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400387 // keep existing entry
388 updatedChildren = append(updatedChildren, existingChildren[nameIndex])
389 }
390 } else {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400391 log.Debugw("adding-unknown-child", log.Fields{
392 "hash": newChild.GetHash(),
393 "data": newChild.GetData(),
394 })
395
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400396 // new entry ... just add it
397 updatedChildren = append(updatedChildren, newChild)
398 }
399 }
400
401 // Save children in new revision
402 updatedRev.SetChildren(name, updatedChildren)
403
404 updatedNames := make(map[string]int)
405 for i, updatedChild := range updatedChildren {
406 updatedNames[updatedChild.GetName()] = i
407 }
408
409 log.Debugw("updated-children-names", log.Fields{"hash": npr.GetHash(), "names": updatedNames})
410
411 } else {
412 // There are no children available, just save the provided ones
413 updatedRev.SetChildren(name, children)
414 }
415
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500416 updatedRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400417
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500418 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400419}
420
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400421// UpdateAllChildren will replace the current list of children with the provided ones
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400422func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500423 npr.mutex.Lock()
424 defer npr.mutex.Unlock()
425
Stephane Barbariec53a2752019-03-08 17:50:10 -0500426 newRev := npr
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500427 newRev.Config = npr.Config
428 newRev.Hash = npr.Hash
429 newRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400430 newRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400431 newRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400432
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500433 newRev.Children = make(map[string][]Revision)
Stephane Barbariec53a2752019-03-08 17:50:10 -0500434 for entryName, childrenEntry := range children {
435 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500436 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500437 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400438
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500439 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400440}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400441
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400442// Drop is used to indicate when a revision is no longer required
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400443func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400444 log.Debugw("dropping-revision", log.Fields{"hash": npr.GetHash(), "name": npr.GetName()})
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400445}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500446
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400447// ChildDrop will remove a child entry matching the provided parameters from the current revision
448func (npr *NonPersistedRevision) ChildDrop(childType string, childHash string) {
449 if childType != "" {
450 children := make([]Revision, len(npr.GetChildren(childType)))
451 copy(children, npr.GetChildren(childType))
452 for i, child := range children {
453 if child.GetHash() == childHash {
454 children = append(children[:i], children[i+1:]...)
455 npr.SetChildren(childType, children)
456 break
457 }
458 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500459 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400460}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500461
David Bainbridgebdae73c2019-10-23 17:05:41 +0000462/// ChildDropByName will remove a child entry matching the type and name
463func (npr *NonPersistedRevision) ChildDropByName(childName string) {
464 // Extract device type
465 parts := strings.SplitN(childName, "/", 2)
466 childType := parts[0]
467
468 if childType != "" {
469 children := make([]Revision, len(npr.GetChildren(childType)))
470 copy(children, npr.GetChildren(childType))
471 for i, child := range children {
472 if child.GetName() == childName {
473 children = append(children[:i], children[i+1:]...)
474 npr.SetChildren(childType, children)
475 break
476 }
477 }
478 }
479}
480
Stephane Barbarie802aca42019-05-21 12:19:28 -0400481func (npr *NonPersistedRevision) SetLastUpdate(ts ...time.Time) {
482 npr.mutex.Lock()
483 defer npr.mutex.Unlock()
484
485 if ts != nil && len(ts) > 0 {
486 npr.lastUpdate = ts[0]
487 } else {
488 npr.lastUpdate = time.Now()
489 }
490}
491
492func (npr *NonPersistedRevision) GetLastUpdate() time.Time {
493 npr.mutex.RLock()
494 defer npr.mutex.RUnlock()
495
496 return npr.lastUpdate
497}
498
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400499func (npr *NonPersistedRevision) LoadFromPersistence(ctx context.Context, path string, txid string, blobs map[string]*kvstore.KVPair) []Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500500 // stub... required by interface
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500501 return nil
502}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500503
504func (npr *NonPersistedRevision) SetupWatch(key string) {
505 // stub ... required by interface
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400506}
507
Stephane Barbariec92d1072019-06-07 16:21:49 -0400508func (npr *NonPersistedRevision) StorageDrop(txid string, includeConfig bool) {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400509 // stub ... required by interface
510}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400511
512func (npr *NonPersistedRevision) getVersion() int64 {
513 return -1
514}