blob: a8073c737411e06a17b1d81d1b7f2cb10c1ccd05 [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 */
npujar9a30c702019-11-14 17:06:39 +053016
Stephane Barbarieec0919b2018-09-05 14:14:29 -040017package model
18
19import (
20 "bytes"
Stephane Barbarieef6650d2019-07-18 12:15:09 -040021 "context"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040022 "crypto/md5"
23 "fmt"
24 "reflect"
25 "sort"
David Bainbridgebdae73c2019-10-23 17:05:41 +000026 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050027 "sync"
Stephane Barbarie802aca42019-05-21 12:19:28 -040028 "time"
npujar9a30c702019-11-14 17:06:39 +053029
30 "github.com/golang/protobuf/proto"
serkant.uluderya2ae470f2020-01-21 11:13:09 -080031 "github.com/opencord/voltha-lib-go/v3/pkg/db/kvstore"
32 "github.com/opencord/voltha-lib-go/v3/pkg/log"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040033)
34
Stephane Barbarie40fd3b22019-04-23 21:50:47 -040035// TODO: Cache logic will have to be revisited to cleanup unused entries in memory (disabled for now)
36//
Stephane Barbarie7512fc82019-05-07 12:25:46 -040037type revCacheSingleton struct {
38 sync.RWMutex
39 Cache sync.Map
40}
41
Stephane Barbarieef6650d2019-07-18 12:15:09 -040042func (s *revCacheSingleton) Get(path string) (interface{}, bool) {
43 return s.Cache.Load(path)
44}
45func (s *revCacheSingleton) Set(path string, value interface{}) {
46 s.Cache.Store(path, value)
47}
48func (s *revCacheSingleton) Delete(path string) {
49 s.Cache.Delete(path)
50}
51
Stephane Barbarie7512fc82019-05-07 12:25:46 -040052var revCacheInstance *revCacheSingleton
53var revCacheOnce sync.Once
54
npujar9a30c702019-11-14 17:06:39 +053055func getRevCache() *revCacheSingleton {
Stephane Barbarie7512fc82019-05-07 12:25:46 -040056 revCacheOnce.Do(func() {
57 revCacheInstance = &revCacheSingleton{Cache: sync.Map{}}
58 })
59 return revCacheInstance
60}
Stephane Barbarieec0919b2018-09-05 14:14:29 -040061
npujar9a30c702019-11-14 17:06:39 +053062// NonPersistedRevision -
Stephane Barbarieec0919b2018-09-05 14:14:29 -040063type NonPersistedRevision struct {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -040064 mutex sync.RWMutex
65 Root *root
66 Config *DataRevision
67 childrenLock sync.RWMutex
68 Children map[string][]Revision
69 Hash string
70 Branch *Branch
71 WeakRef string
72 Name string
Stephane Barbarie802aca42019-05-21 12:19:28 -040073 lastUpdate time.Time
Stephane Barbarieec0919b2018-09-05 14:14:29 -040074}
75
npujar9a30c702019-11-14 17:06:39 +053076// NewNonPersistedRevision -
Stephane Barbariedc5022d2018-11-19 15:21:44 -050077func NewNonPersistedRevision(root *root, branch *Branch, data interface{}, children map[string][]Revision) Revision {
78 r := &NonPersistedRevision{}
79 r.Root = root
80 r.Branch = branch
81 r.Config = NewDataRevision(root, data)
82 r.Children = children
Stephane Barbarief7fc1782019-03-28 22:33:41 -040083 r.Hash = r.hashContent()
Stephane Barbariedc5022d2018-11-19 15:21:44 -050084 return r
Stephane Barbarieec0919b2018-09-05 14:14:29 -040085}
86
npujar9a30c702019-11-14 17:06:39 +053087// SetConfig -
Stephane Barbarieec0919b2018-09-05 14:14:29 -040088func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050089 npr.mutex.Lock()
90 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040091 npr.Config = config
92}
93
npujar9a30c702019-11-14 17:06:39 +053094// GetConfig -
Stephane Barbarieec0919b2018-09-05 14:14:29 -040095func (npr *NonPersistedRevision) GetConfig() *DataRevision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050096 npr.mutex.Lock()
97 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040098 return npr.Config
99}
100
npujar9a30c702019-11-14 17:06:39 +0530101// SetAllChildren -
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500102func (npr *NonPersistedRevision) SetAllChildren(children map[string][]Revision) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400103 npr.childrenLock.Lock()
104 defer npr.childrenLock.Unlock()
105 npr.Children = make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400106
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400107 for key, value := range children {
108 npr.Children[key] = make([]Revision, len(value))
109 copy(npr.Children[key], value)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500110 }
111}
112
npujar9a30c702019-11-14 17:06:39 +0530113// SetChildren -
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400114func (npr *NonPersistedRevision) SetChildren(name string, children []Revision) {
115 npr.childrenLock.Lock()
116 defer npr.childrenLock.Unlock()
117
118 npr.Children[name] = make([]Revision, len(children))
119 copy(npr.Children[name], children)
120}
121
npujar9a30c702019-11-14 17:06:39 +0530122// GetAllChildren -
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500123func (npr *NonPersistedRevision) GetAllChildren() map[string][]Revision {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400124 npr.childrenLock.Lock()
125 defer npr.childrenLock.Unlock()
126
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400127 return npr.Children
128}
129
npujar9a30c702019-11-14 17:06:39 +0530130// GetChildren -
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500131func (npr *NonPersistedRevision) GetChildren(name string) []Revision {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400132 npr.childrenLock.Lock()
133 defer npr.childrenLock.Unlock()
134
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500135 if _, exists := npr.Children[name]; exists {
136 return npr.Children[name]
137 }
138 return nil
139}
140
npujar9a30c702019-11-14 17:06:39 +0530141// SetHash -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400142func (npr *NonPersistedRevision) SetHash(hash string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500143 npr.mutex.Lock()
144 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400145 npr.Hash = hash
146}
147
npujar9a30c702019-11-14 17:06:39 +0530148// GetHash -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400149func (npr *NonPersistedRevision) GetHash() string {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500150 //npr.mutex.Lock()
151 //defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400152 return npr.Hash
153}
154
npujar9a30c702019-11-14 17:06:39 +0530155// ClearHash -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400156func (npr *NonPersistedRevision) ClearHash() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500157 npr.mutex.Lock()
158 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400159 npr.Hash = ""
160}
161
npujar9a30c702019-11-14 17:06:39 +0530162// GetName -
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400163func (npr *NonPersistedRevision) GetName() string {
164 //npr.mutex.Lock()
165 //defer npr.mutex.Unlock()
166 return npr.Name
167}
168
npujar9a30c702019-11-14 17:06:39 +0530169// SetName -
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400170func (npr *NonPersistedRevision) SetName(name string) {
171 //npr.mutex.Lock()
172 //defer npr.mutex.Unlock()
173 npr.Name = name
174}
npujar9a30c702019-11-14 17:06:39 +0530175
176// SetBranch -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400177func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500178 npr.mutex.Lock()
179 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400180 npr.Branch = branch
181}
182
npujar9a30c702019-11-14 17:06:39 +0530183// GetBranch -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400184func (npr *NonPersistedRevision) GetBranch() *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500185 npr.mutex.Lock()
186 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400187 return npr.Branch
188}
189
npujar9a30c702019-11-14 17:06:39 +0530190// GetData -
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400191func (npr *NonPersistedRevision) GetData() interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500192 npr.mutex.Lock()
193 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400194 if npr.Config == nil {
195 return nil
196 }
197 return npr.Config.Data
198}
199
npujar9a30c702019-11-14 17:06:39 +0530200func (npr *NonPersistedRevision) getNode() *node {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500201 npr.mutex.Lock()
202 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400203 return npr.Branch.Node
204}
205
npujar9a30c702019-11-14 17:06:39 +0530206// Finalize -
npujar467fe752020-01-16 20:17:45 +0530207func (npr *NonPersistedRevision) Finalize(ctx context.Context, skipOnExist bool) {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400208 npr.Hash = npr.hashContent()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400209}
210
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400211// hashContent generates a hash string based on the contents of the revision.
212// The string should be unique to avoid conflicts with other revisions
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400213func (npr *NonPersistedRevision) hashContent() string {
214 var buffer bytes.Buffer
215 var childrenKeys []string
216
217 if npr.Config != nil {
218 buffer.WriteString(npr.Config.Hash)
219 }
220
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400221 if npr.Name != "" {
222 buffer.WriteString(npr.Name)
223 }
224
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500225 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400226 childrenKeys = append(childrenKeys, key)
227 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500228
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400229 sort.Strings(childrenKeys)
230
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500231 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400232 // Loop through sorted Children keys
233 for _, key := range childrenKeys {
234 for _, child := range npr.Children[key] {
235 if child != nil && child.GetHash() != "" {
236 buffer.WriteString(child.GetHash())
237 }
238 }
239 }
240 }
241
242 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
243}
244
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400245// Get will retrieve the data for the current revision
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400246func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500247 // 1. Clone the data to avoid any concurrent access issues
248 // 2. The current rev might still be pointing to an old config
249 // thus, force the revision to get its latest value
250 latestRev := npr.GetBranch().GetLatest()
251 originalData := proto.Clone(latestRev.GetData().(proto.Message))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500252 data := originalData
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400253
254 if depth != 0 {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400255 // FIXME: Traversing the struct through reflection sometimes corrupts the data.
256 // Unlike the original python implementation, golang structs are not lazy loaded.
257 // Keeping this non-critical logic for now, but Get operations should be forced to
258 // depth=0 to avoid going through the following loop.
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500259 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400260 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
261 if field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500262 for _, rev := range latestRev.GetChildren(fieldName) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400263 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400264 foundEntry := false
265 for i := 0; i < childDataHolder.Len(); i++ {
npujar9a30c702019-11-14 17:06:39 +0530266 cdhIf := childDataHolder.Index(i).Interface()
267 if cdhIf.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400268 foundEntry = true
269 break
270 }
271 }
272 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500273 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400274 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
275 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400276 }
277 } else {
npujar9a30c702019-11-14 17:06:39 +0530278 if revs := npr.GetBranch().GetLatest().GetChildren(fieldName); len(revs) > 0 {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400279 rev := revs[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400280 if rev != nil {
281 childData := rev.Get(depth - 1)
282 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
283 childDataHolder = reflect.ValueOf(childData)
284 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400285 }
286 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400287 }
288 // Merge child data with cloned object
289 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
290 }
291 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400292
293 result := data
294
295 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500296 // We need to send back a copy of the retrieved object
297 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400298 }
299
300 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400301}
302
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400303// UpdateData will refresh the data content of the revision
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400304func (npr *NonPersistedRevision) UpdateData(ctx context.Context, data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500305 npr.mutex.Lock()
306 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400307
David Bainbridgebdae73c2019-10-23 17:05:41 +0000308 log.Debugw("update-data", log.Fields{"hash": npr.GetHash(), "current": npr.Config.Data, "provided": data})
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400309
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400310 // Construct a new revision based on the current one
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500311 newRev := NonPersistedRevision{}
312 newRev.Config = NewDataRevision(npr.Root, data)
313 newRev.Hash = npr.Hash
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400314 newRev.Root = npr.Root
315 newRev.Name = npr.Name
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500316 newRev.Branch = branch
Stephane Barbarie802aca42019-05-21 12:19:28 -0400317 newRev.lastUpdate = npr.lastUpdate
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500318
319 newRev.Children = make(map[string][]Revision)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400320 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500321 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
322 }
323
npujar467fe752020-01-16 20:17:45 +0530324 newRev.Finalize(ctx, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400325
David Bainbridgebdae73c2019-10-23 17:05:41 +0000326 log.Debugw("update-data-complete", log.Fields{"updated": newRev.Config.Data, "provided": data})
327
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400328 return &newRev
329}
330
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400331// UpdateChildren will refresh the list of children with the provided ones
332// It will carefully go through the list and ensure that no child is lost
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400333func (npr *NonPersistedRevision) UpdateChildren(ctx context.Context, name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500334 npr.mutex.Lock()
335 defer npr.mutex.Unlock()
336
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400337 // Construct a new revision based on the current one
338 updatedRev := &NonPersistedRevision{}
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500339 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
340 updatedRev.Hash = npr.Hash
341 updatedRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400342 updatedRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400343 updatedRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400344
345 updatedRev.Children = make(map[string][]Revision)
346 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
347 updatedRev.Children[entryName] = append(updatedRev.Children[entryName], childrenEntry...)
348 }
349
350 var updatedChildren []Revision
351
352 // Verify if the map contains already contains an entry matching the name value
353 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
354 if existingChildren := branch.GetLatest().GetChildren(name); existingChildren != nil {
355 // Construct a map of unique child names with the respective index value
356 // for the children in the existing revision as well as the new ones
357 existingNames := make(map[string]int)
358 newNames := make(map[string]int)
359
360 for i, newChild := range children {
361 newNames[newChild.GetName()] = i
362 }
363
364 for i, existingChild := range existingChildren {
365 existingNames[existingChild.GetName()] = i
366
367 // If an existing entry is not in the new list, add it to the updated list, so it is not forgotten
368 if _, exists := newNames[existingChild.GetName()]; !exists {
369 updatedChildren = append(updatedChildren, existingChild)
370 }
371 }
372
373 log.Debugw("existing-children-names", log.Fields{"hash": npr.GetHash(), "names": existingNames})
374
375 // Merge existing and new children
376 for _, newChild := range children {
377 nameIndex, nameExists := existingNames[newChild.GetName()]
378
379 // Does the existing list contain a child with that name?
380 if nameExists {
khenaidoo67b22152020-03-02 16:01:25 -0500381 // This function is invoked only when the data has actually changed (current Core usage). Therefore,
382 // we need to avoid an expensive deep proto.message comparison and treat the data as an update
383 newChild.getNode().SetRoot(existingChildren[nameIndex].getNode().GetRoot())
384 updatedChildren = append(updatedChildren, newChild)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400385 } else {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400386 log.Debugw("adding-unknown-child", log.Fields{
387 "hash": newChild.GetHash(),
388 "data": newChild.GetData(),
389 })
390
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400391 // new entry ... just add it
392 updatedChildren = append(updatedChildren, newChild)
393 }
394 }
395
396 // Save children in new revision
397 updatedRev.SetChildren(name, updatedChildren)
398
399 updatedNames := make(map[string]int)
400 for i, updatedChild := range updatedChildren {
401 updatedNames[updatedChild.GetName()] = i
402 }
403
404 log.Debugw("updated-children-names", log.Fields{"hash": npr.GetHash(), "names": updatedNames})
405
406 } else {
407 // There are no children available, just save the provided ones
408 updatedRev.SetChildren(name, children)
409 }
410
npujar467fe752020-01-16 20:17:45 +0530411 updatedRev.Finalize(ctx, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400412
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500413 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400414}
415
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400416// UpdateAllChildren will replace the current list of children with the provided ones
npujar467fe752020-01-16 20:17:45 +0530417func (npr *NonPersistedRevision) UpdateAllChildren(ctx context.Context, children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500418 npr.mutex.Lock()
419 defer npr.mutex.Unlock()
420
Stephane Barbariec53a2752019-03-08 17:50:10 -0500421 newRev := npr
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500422 newRev.Config = npr.Config
423 newRev.Hash = npr.Hash
424 newRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400425 newRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400426 newRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400427
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500428 newRev.Children = make(map[string][]Revision)
Stephane Barbariec53a2752019-03-08 17:50:10 -0500429 for entryName, childrenEntry := range children {
430 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500431 }
npujar467fe752020-01-16 20:17:45 +0530432 newRev.Finalize(ctx, false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400433
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500434 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400435}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400436
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400437// Drop is used to indicate when a revision is no longer required
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400438func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400439 log.Debugw("dropping-revision", log.Fields{"hash": npr.GetHash(), "name": npr.GetName()})
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400440}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500441
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400442// ChildDrop will remove a child entry matching the provided parameters from the current revision
443func (npr *NonPersistedRevision) ChildDrop(childType string, childHash string) {
444 if childType != "" {
445 children := make([]Revision, len(npr.GetChildren(childType)))
446 copy(children, npr.GetChildren(childType))
447 for i, child := range children {
448 if child.GetHash() == childHash {
449 children = append(children[:i], children[i+1:]...)
450 npr.SetChildren(childType, children)
451 break
452 }
453 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500454 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400455}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500456
npujar9a30c702019-11-14 17:06:39 +0530457// ChildDropByName will remove a child entry matching the type and name
David Bainbridgebdae73c2019-10-23 17:05:41 +0000458func (npr *NonPersistedRevision) ChildDropByName(childName string) {
459 // Extract device type
460 parts := strings.SplitN(childName, "/", 2)
461 childType := parts[0]
462
463 if childType != "" {
464 children := make([]Revision, len(npr.GetChildren(childType)))
465 copy(children, npr.GetChildren(childType))
466 for i, child := range children {
467 if child.GetName() == childName {
468 children = append(children[:i], children[i+1:]...)
469 npr.SetChildren(childType, children)
470 break
471 }
472 }
473 }
474}
475
npujar9a30c702019-11-14 17:06:39 +0530476// SetLastUpdate -
Stephane Barbarie802aca42019-05-21 12:19:28 -0400477func (npr *NonPersistedRevision) SetLastUpdate(ts ...time.Time) {
478 npr.mutex.Lock()
479 defer npr.mutex.Unlock()
480
npujar9a30c702019-11-14 17:06:39 +0530481 if len(ts) > 0 {
Stephane Barbarie802aca42019-05-21 12:19:28 -0400482 npr.lastUpdate = ts[0]
483 } else {
484 npr.lastUpdate = time.Now()
485 }
486}
487
npujar9a30c702019-11-14 17:06:39 +0530488// GetLastUpdate -
Stephane Barbarie802aca42019-05-21 12:19:28 -0400489func (npr *NonPersistedRevision) GetLastUpdate() time.Time {
490 npr.mutex.RLock()
491 defer npr.mutex.RUnlock()
492
493 return npr.lastUpdate
494}
495
Thomas Lee Se5a44012019-11-07 20:32:24 +0530496func (npr *NonPersistedRevision) LoadFromPersistence(ctx context.Context, path string, txid string, blobs map[string]*kvstore.KVPair) ([]Revision, error) {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500497 // stub... required by interface
Thomas Lee Se5a44012019-11-07 20:32:24 +0530498 return nil, nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500499}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500500
npujar9a30c702019-11-14 17:06:39 +0530501// SetupWatch -
npujar467fe752020-01-16 20:17:45 +0530502func (npr *NonPersistedRevision) SetupWatch(ctx context.Context, key string) {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500503 // stub ... required by interface
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400504}
505
npujar9a30c702019-11-14 17:06:39 +0530506// StorageDrop -
npujar467fe752020-01-16 20:17:45 +0530507func (npr *NonPersistedRevision) StorageDrop(ctx context.Context, txid string, includeConfig bool) {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400508 // stub ... required by interface
509}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400510
511func (npr *NonPersistedRevision) getVersion() int64 {
512 return -1
513}