blob: b7962172db98e21528fdf5b029f7ef45f31bd122 [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"
31 "github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
32 "github.com/opencord/voltha-lib-go/v2/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 -
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500207func (npr *NonPersistedRevision) Finalize(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 // Do not update the revision if data is the same
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500311 if npr.Config.Data != nil && npr.Config.hashData(npr.Root, data) == npr.Config.Hash {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500312 log.Debugw("stored-data-matches-latest", log.Fields{"stored": npr.Config.Data, "provided": data})
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500313 return npr
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500314 }
315
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400316 // Construct a new revision based on the current one
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500317 newRev := NonPersistedRevision{}
318 newRev.Config = NewDataRevision(npr.Root, data)
319 newRev.Hash = npr.Hash
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400320 newRev.Root = npr.Root
321 newRev.Name = npr.Name
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500322 newRev.Branch = branch
Stephane Barbarie802aca42019-05-21 12:19:28 -0400323 newRev.lastUpdate = npr.lastUpdate
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500324
325 newRev.Children = make(map[string][]Revision)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400326 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500327 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
328 }
329
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500330 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400331
David Bainbridgebdae73c2019-10-23 17:05:41 +0000332 log.Debugw("update-data-complete", log.Fields{"updated": newRev.Config.Data, "provided": data})
333
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400334 return &newRev
335}
336
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400337// UpdateChildren will refresh the list of children with the provided ones
338// It will carefully go through the list and ensure that no child is lost
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400339func (npr *NonPersistedRevision) UpdateChildren(ctx context.Context, name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500340 npr.mutex.Lock()
341 defer npr.mutex.Unlock()
342
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400343 // Construct a new revision based on the current one
344 updatedRev := &NonPersistedRevision{}
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500345 updatedRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
346 updatedRev.Hash = npr.Hash
347 updatedRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400348 updatedRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400349 updatedRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400350
351 updatedRev.Children = make(map[string][]Revision)
352 for entryName, childrenEntry := range branch.GetLatest().GetAllChildren() {
353 updatedRev.Children[entryName] = append(updatedRev.Children[entryName], childrenEntry...)
354 }
355
356 var updatedChildren []Revision
357
358 // Verify if the map contains already contains an entry matching the name value
359 // If so, we need to retain the contents of that entry and merge them with the provided children revision list
360 if existingChildren := branch.GetLatest().GetChildren(name); existingChildren != nil {
361 // Construct a map of unique child names with the respective index value
362 // for the children in the existing revision as well as the new ones
363 existingNames := make(map[string]int)
364 newNames := make(map[string]int)
365
366 for i, newChild := range children {
367 newNames[newChild.GetName()] = i
368 }
369
370 for i, existingChild := range existingChildren {
371 existingNames[existingChild.GetName()] = i
372
373 // If an existing entry is not in the new list, add it to the updated list, so it is not forgotten
374 if _, exists := newNames[existingChild.GetName()]; !exists {
375 updatedChildren = append(updatedChildren, existingChild)
376 }
377 }
378
379 log.Debugw("existing-children-names", log.Fields{"hash": npr.GetHash(), "names": existingNames})
380
381 // Merge existing and new children
382 for _, newChild := range children {
383 nameIndex, nameExists := existingNames[newChild.GetName()]
384
385 // Does the existing list contain a child with that name?
386 if nameExists {
387 // Check if the data has changed or not
388 if existingChildren[nameIndex].GetData().(proto.Message).String() != newChild.GetData().(proto.Message).String() {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400389 log.Debugw("replacing-existing-child", log.Fields{
390 "old-hash": existingChildren[nameIndex].GetHash(),
391 "old-data": existingChildren[nameIndex].GetData(),
392 "new-hash": newChild.GetHash(),
393 "new-data": newChild.GetData(),
394 })
395
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400396 // replace entry
npujar9a30c702019-11-14 17:06:39 +0530397 newChild.getNode().SetRoot(existingChildren[nameIndex].getNode().GetRoot())
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400398 updatedChildren = append(updatedChildren, newChild)
399 } else {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400400 log.Debugw("keeping-existing-child", log.Fields{
401 "old-hash": existingChildren[nameIndex].GetHash(),
402 "old-data": existingChildren[nameIndex].GetData(),
403 "new-hash": newChild.GetHash(),
404 "new-data": newChild.GetData(),
405 })
406
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400407 // keep existing entry
408 updatedChildren = append(updatedChildren, existingChildren[nameIndex])
409 }
410 } else {
Stephane Barbariec92d1072019-06-07 16:21:49 -0400411 log.Debugw("adding-unknown-child", log.Fields{
412 "hash": newChild.GetHash(),
413 "data": newChild.GetData(),
414 })
415
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400416 // new entry ... just add it
417 updatedChildren = append(updatedChildren, newChild)
418 }
419 }
420
421 // Save children in new revision
422 updatedRev.SetChildren(name, updatedChildren)
423
424 updatedNames := make(map[string]int)
425 for i, updatedChild := range updatedChildren {
426 updatedNames[updatedChild.GetName()] = i
427 }
428
429 log.Debugw("updated-children-names", log.Fields{"hash": npr.GetHash(), "names": updatedNames})
430
431 } else {
432 // There are no children available, just save the provided ones
433 updatedRev.SetChildren(name, children)
434 }
435
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500436 updatedRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400437
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500438 return updatedRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439}
440
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400441// UpdateAllChildren will replace the current list of children with the provided ones
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400442func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500443 npr.mutex.Lock()
444 defer npr.mutex.Unlock()
445
Stephane Barbariec53a2752019-03-08 17:50:10 -0500446 newRev := npr
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500447 newRev.Config = npr.Config
448 newRev.Hash = npr.Hash
449 newRev.Branch = branch
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400450 newRev.Name = npr.Name
Stephane Barbarie802aca42019-05-21 12:19:28 -0400451 newRev.lastUpdate = npr.lastUpdate
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400452
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500453 newRev.Children = make(map[string][]Revision)
Stephane Barbariec53a2752019-03-08 17:50:10 -0500454 for entryName, childrenEntry := range children {
455 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500456 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500457 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400458
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500459 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400460}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400461
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400462// Drop is used to indicate when a revision is no longer required
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400463func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400464 log.Debugw("dropping-revision", log.Fields{"hash": npr.GetHash(), "name": npr.GetName()})
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400465}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500466
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400467// ChildDrop will remove a child entry matching the provided parameters from the current revision
468func (npr *NonPersistedRevision) ChildDrop(childType string, childHash string) {
469 if childType != "" {
470 children := make([]Revision, len(npr.GetChildren(childType)))
471 copy(children, npr.GetChildren(childType))
472 for i, child := range children {
473 if child.GetHash() == childHash {
474 children = append(children[:i], children[i+1:]...)
475 npr.SetChildren(childType, children)
476 break
477 }
478 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500479 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400480}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500481
npujar9a30c702019-11-14 17:06:39 +0530482// ChildDropByName will remove a child entry matching the type and name
David Bainbridgebdae73c2019-10-23 17:05:41 +0000483func (npr *NonPersistedRevision) ChildDropByName(childName string) {
484 // Extract device type
485 parts := strings.SplitN(childName, "/", 2)
486 childType := parts[0]
487
488 if childType != "" {
489 children := make([]Revision, len(npr.GetChildren(childType)))
490 copy(children, npr.GetChildren(childType))
491 for i, child := range children {
492 if child.GetName() == childName {
493 children = append(children[:i], children[i+1:]...)
494 npr.SetChildren(childType, children)
495 break
496 }
497 }
498 }
499}
500
npujar9a30c702019-11-14 17:06:39 +0530501// SetLastUpdate -
Stephane Barbarie802aca42019-05-21 12:19:28 -0400502func (npr *NonPersistedRevision) SetLastUpdate(ts ...time.Time) {
503 npr.mutex.Lock()
504 defer npr.mutex.Unlock()
505
npujar9a30c702019-11-14 17:06:39 +0530506 if len(ts) > 0 {
Stephane Barbarie802aca42019-05-21 12:19:28 -0400507 npr.lastUpdate = ts[0]
508 } else {
509 npr.lastUpdate = time.Now()
510 }
511}
512
npujar9a30c702019-11-14 17:06:39 +0530513// GetLastUpdate -
Stephane Barbarie802aca42019-05-21 12:19:28 -0400514func (npr *NonPersistedRevision) GetLastUpdate() time.Time {
515 npr.mutex.RLock()
516 defer npr.mutex.RUnlock()
517
518 return npr.lastUpdate
519}
520
Thomas Lee Se5a44012019-11-07 20:32:24 +0530521func (npr *NonPersistedRevision) LoadFromPersistence(ctx context.Context, path string, txid string, blobs map[string]*kvstore.KVPair) ([]Revision, error) {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500522 // stub... required by interface
Thomas Lee Se5a44012019-11-07 20:32:24 +0530523 return nil, nil
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500524}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500525
npujar9a30c702019-11-14 17:06:39 +0530526// SetupWatch -
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500527func (npr *NonPersistedRevision) SetupWatch(key string) {
528 // stub ... required by interface
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400529}
530
npujar9a30c702019-11-14 17:06:39 +0530531// StorageDrop -
Stephane Barbariec92d1072019-06-07 16:21:49 -0400532func (npr *NonPersistedRevision) StorageDrop(txid string, includeConfig bool) {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400533 // stub ... required by interface
534}
Stephane Barbarieef6650d2019-07-18 12:15:09 -0400535
536func (npr *NonPersistedRevision) getVersion() int64 {
537 return -1
538}