blob: f3352169652e2670aafca8840d66622adc35f384 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27: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 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040017package model
18
19import (
20 "bytes"
21 "compress/gzip"
Stephane Barbarie260a5632019-02-26 16:12:49 -050022 "encoding/hex"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040023 "github.com/golang/protobuf/proto"
Stephane Barbarie260a5632019-02-26 16:12:49 -050024 "github.com/google/uuid"
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -040025 "github.com/opencord/voltha-go/common/log"
Stephane Barbariee0a4c792019-01-16 11:26:29 -050026 "github.com/opencord/voltha-go/db/kvstore"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027 "reflect"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050028 "runtime/debug"
Stephane Barbarie1ab43272018-12-08 21:42:13 -050029 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050030 "sync"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040031)
32
Stephane Barbariedc5022d2018-11-19 15:21:44 -050033// PersistedRevision holds information of revision meant to be saved in a persistent storage
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040034type PersistedRevision struct {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040035 Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040036 Compress bool
Stephane Barbariee0a4c792019-01-16 11:26:29 -050037
Stephane Barbarie3cb01222019-01-16 17:15:56 -050038 events chan *kvstore.Event `json:"-"`
39 kvStore *Backend `json:"-"`
40 mutex sync.RWMutex `json:"-"`
41 isStored bool
42 isWatched bool
Stephane Barbariec53a2752019-03-08 17:50:10 -050043 watchName string
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040044}
45
Stephane Barbariedc5022d2018-11-19 15:21:44 -050046// NewPersistedRevision creates a new instance of a PersistentRevision structure
Stephane Barbarieec0919b2018-09-05 14:14:29 -040047func NewPersistedRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040048 pr := &PersistedRevision{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050049 pr.kvStore = branch.Node.GetRoot().KvStore
50 pr.Revision = NewNonPersistedRevision(nil, branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040051 return pr
52}
53
Stephane Barbariedc5022d2018-11-19 15:21:44 -050054// Finalize is responsible of saving the revision in the persistent storage
Stephane Barbarie1ab43272018-12-08 21:42:13 -050055func (pr *PersistedRevision) Finalize(skipOnExist bool) {
56 pr.store(skipOnExist)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040057}
58
59type revData struct {
60 Children map[string][]string
61 Config string
62}
63
Stephane Barbarie1ab43272018-12-08 21:42:13 -050064func (pr *PersistedRevision) store(skipOnExist bool) {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -040065 if pr.GetBranch().Txid != "" {
66 return
67 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040068
Stephane Barbarie1ab43272018-12-08 21:42:13 -050069 if pair, _ := pr.kvStore.Get(pr.GetHash()); pair != nil && skipOnExist {
Stephane Barbariee0a4c792019-01-16 11:26:29 -050070 log.Debugw("revision-config-already-exists", log.Fields{"hash": pr.GetHash()})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040071 return
72 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -050073
Stephane Barbarieec0919b2018-09-05 14:14:29 -040074 if blob, err := proto.Marshal(pr.GetConfig().Data.(proto.Message)); err != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040075 // TODO report error
76 } else {
77 if pr.Compress {
78 var b bytes.Buffer
79 w := gzip.NewWriter(&b)
80 w.Write(blob)
81 w.Close()
82 blob = b.Bytes()
83 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -050084
Stephane Barbarie1ab43272018-12-08 21:42:13 -050085 if err := pr.kvStore.Put(pr.GetHash(), blob); err != nil {
Stephane Barbariee0a4c792019-01-16 11:26:29 -050086 log.Warnw("problem-storing-revision-config",
87 log.Fields{"error": err, "hash": pr.GetHash(), "data": pr.GetConfig().Data})
Stephane Barbariedc5022d2018-11-19 15:21:44 -050088 } else {
Stephane Barbariee0a4c792019-01-16 11:26:29 -050089 log.Debugw("storing-revision-config",
90 log.Fields{"hash": pr.GetHash(), "data": pr.GetConfig().Data})
Stephane Barbarie3cb01222019-01-16 17:15:56 -050091 pr.isStored = true
Stephane Barbariedc5022d2018-11-19 15:21:44 -050092 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040093 }
94}
95
Stephane Barbariee0a4c792019-01-16 11:26:29 -050096func (pr *PersistedRevision) SetupWatch(key string) {
97 if pr.events == nil {
98 pr.events = make(chan *kvstore.Event)
99
Stephane Barbariec53a2752019-03-08 17:50:10 -0500100 log.Debugw("setting-watch", log.Fields{"key": key, "revision-hash": pr.GetHash()})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500101
Stephane Barbariec53a2752019-03-08 17:50:10 -0500102 pr.watchName = key
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500103 pr.events = pr.kvStore.CreateWatch(key)
104
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500105 pr.isWatched = true
106
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500107 // Start watching
108 go pr.startWatching()
109 }
110}
111
Stephane Barbariec53a2752019-03-08 17:50:10 -0500112//func (pr *PersistedRevision) mergeWithMemory(pacBlock bool) Revision {
113// if pair, err := pr.kvStore.Get(pr.GetHash()); err != nil {
114// log.Debugw("merge-with-memory--error-occurred", log.Fields{"hash": pr.GetHash(), "error": err})
115// } else if pair == nil {
116// log.Debugw("merge-with-memory--no-data-to-merge", log.Fields{"hash": pr.GetHash()})
117// } else {
118// data := reflect.New(reflect.TypeOf(pr.GetData()).Elem()).Interface()
119//
120// if err := proto.Unmarshal(pair.Value.([]byte), data.(proto.Message)); err != nil {
121// log.Errorw("merge-with-memory--unmarshal-failed", log.Fields{"key": pr.GetHash(), "error": err})
122// } else {
123// if pr.GetNode().GetProxy() != nil && pacBlock {
124// var pac *proxyAccessControl
125// var pathLock string
126//
127// pathLock, _ = pr.GetNode().GetProxy().parseForControlledPath(pr.GetNode().GetProxy().getFullPath())
128// log.Debugw("update-in-memory--reserve-and-lock", log.Fields{"key": pr.GetHash(), "path": pathLock})
129//
130// pac = PAC().ReservePath(pr.GetNode().GetProxy().getFullPath(), pr.GetNode().GetProxy(), pathLock)
131// pac.SetProxy(pr.GetNode().GetProxy())
132// pac.lock()
133//
134// defer log.Debugw("update-in-memory--release-and-unlock", log.Fields{"key": pr.GetHash(), "path": pathLock})
135// defer pac.unlock()
136// defer PAC().ReleasePath(pathLock)
137// }
138// //Prepare the transaction
139// branch := pr.GetBranch()
140// //latest := branch.GetLatest()
141// txidBin, _ := uuid.New().MarshalBinary()
142// txid := hex.EncodeToString(txidBin)[:12]
143//
144// makeBranch := func(node *node) *Branch {
145// return node.MakeBranch(txid)
146// }
147//
148// //Apply the update in a transaction branch
149// updatedRev := pr.GetNode().Update("", data, false, txid, makeBranch)
150// updatedRev.SetHash(pr.GetHash())
151//
152// //Merge the transaction branch in memory
153// if mergedRev, _ := pr.GetNode().MergeBranch(txid, false); mergedRev != nil {
154// branch.SetLatest(mergedRev)
155// return mergedRev
156// }
157// }
158// }
159//
160// return nil
161//}
162
Stephane Barbarie260a5632019-02-26 16:12:49 -0500163func (pr *PersistedRevision) updateInMemory(data interface{}) {
Stephane Barbariec53a2752019-03-08 17:50:10 -0500164 pr.mutex.Lock()
165 defer pr.mutex.Unlock()
166
Stephane Barbarie260a5632019-02-26 16:12:49 -0500167 var pac *proxyAccessControl
168 var pathLock string
169
170 //
171 // If a proxy exists for this revision, use it to lock access to the path
172 // and prevent simultaneous updates to the object in memory
173 //
174 if pr.GetNode().GetProxy() != nil {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500175 pathLock, _ = pr.GetNode().GetProxy().parseForControlledPath(pr.GetNode().GetProxy().getFullPath())
Stephane Barbariec53a2752019-03-08 17:50:10 -0500176
177 // If the proxy already has a request in progress, then there is no need to process the watch
178 log.Debugw("update-in-memory--checking-pathlock", log.Fields{"key": pr.GetHash(), "pathLock": pathLock})
179 if PAC().IsReserved(pathLock) {
180 switch pr.GetNode().GetRoot().GetProxy().Operation {
181 case PROXY_ADD:
182 fallthrough
183 case PROXY_REMOVE:
184 fallthrough
185 case PROXY_UPDATE:
186 log.Debugw("update-in-memory--skipping", log.Fields{"key": pr.GetHash(), "path": pr.GetNode().GetProxy().getFullPath()})
187 return
188 default:
189 log.Debugw("update-in-memory--operation", log.Fields{"operation": pr.GetNode().GetRoot().GetProxy().Operation})
190 }
191 } else {
192 log.Debugw("update-in-memory--path-not-locked", log.Fields{"key": pr.GetHash(), "path": pr.GetNode().GetProxy().getFullPath()})
193 }
194
195 log.Debugw("update-in-memory--reserve-and-lock", log.Fields{"key": pr.GetHash(), "path": pathLock})
196
Stephane Barbarie260a5632019-02-26 16:12:49 -0500197 pac = PAC().ReservePath(pr.GetNode().GetProxy().getFullPath(), pr.GetNode().GetProxy(), pathLock)
198 pac.SetProxy(pr.GetNode().GetProxy())
199 pac.lock()
200
201 defer log.Debugw("update-in-memory--release-and-unlock", log.Fields{"key": pr.GetHash(), "path": pathLock})
202 defer pac.unlock()
203 defer PAC().ReleasePath(pathLock)
204 }
205
206 //
207 // Update the object in memory through a transaction
208 // This will allow for the object to be subsequently merged with any changes
209 // that might have occurred in memory
210 //
211
212 log.Debugw("update-in-memory--custom-transaction", log.Fields{"key": pr.GetHash()})
213
214 // Prepare the transaction
215 branch := pr.GetBranch()
216 latest := branch.GetLatest()
217 txidBin, _ := uuid.New().MarshalBinary()
218 txid := hex.EncodeToString(txidBin)[:12]
219
220 makeBranch := func(node *node) *Branch {
221 return node.MakeBranch(txid)
222 }
223
224 // Apply the update in a transaction branch
225 updatedRev := latest.GetNode().Update("", data, false, txid, makeBranch)
226 updatedRev.SetHash(latest.GetHash())
227
228 // Merge the transaction branch in memory
229 if mergedRev, _ := latest.GetNode().MergeBranch(txid, false); mergedRev != nil {
230 branch.SetLatest(mergedRev)
231 }
Stephane Barbarie260a5632019-02-26 16:12:49 -0500232}
233
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500234func (pr *PersistedRevision) startWatching() {
235 log.Debugw("starting-watch", log.Fields{"key": pr.GetHash()})
236
237StopWatchLoop:
238 for {
239 select {
240 case event, ok := <-pr.events:
241 if !ok {
Stephane Barbariec53a2752019-03-08 17:50:10 -0500242 log.Errorw("event-channel-failure: stopping watch loop", log.Fields{"key": pr.GetHash(), "watch": pr.watchName})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500243 break StopWatchLoop
244 }
245
Stephane Barbariec53a2752019-03-08 17:50:10 -0500246 log.Debugw("received-event", log.Fields{"type": event.EventType, "watch": pr.watchName})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500247
248 switch event.EventType {
249 case kvstore.DELETE:
Stephane Barbariec53a2752019-03-08 17:50:10 -0500250 log.Debugw("delete-from-memory", log.Fields{"key": pr.GetHash(), "watch": pr.watchName})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500251 pr.Revision.Drop("", true)
252 break StopWatchLoop
253
254 case kvstore.PUT:
Stephane Barbariec53a2752019-03-08 17:50:10 -0500255 log.Debugw("update-in-memory", log.Fields{"key": pr.GetHash(), "watch": pr.watchName})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500256
Stephane Barbariec53a2752019-03-08 17:50:10 -0500257 if dataPair, err := pr.kvStore.Get(pr.watchName); err != nil || dataPair == nil {
258 log.Errorw("update-in-memory--key-retrieval-failed", log.Fields{"key": pr.GetHash(), "watch": pr.watchName, "error": err})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500259 } else {
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500260 data := reflect.New(reflect.TypeOf(pr.GetData()).Elem())
261
262 if err := proto.Unmarshal(dataPair.Value.([]byte), data.Interface().(proto.Message)); err != nil {
Stephane Barbariec53a2752019-03-08 17:50:10 -0500263 log.Errorw("update-in-memory--unmarshal-failed", log.Fields{"key": pr.GetHash(), "watch": pr.watchName, "error": err})
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500264 } else {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500265 pr.updateInMemory(data.Interface())
Stephane Barbariedf5479f2019-01-29 22:13:00 -0500266 }
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500267 }
268
269 default:
Stephane Barbariec53a2752019-03-08 17:50:10 -0500270 log.Debugw("unhandled-event", log.Fields{"key": pr.GetHash(), "watch": pr.watchName, "type": event.EventType})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500271 }
272 }
273 }
274
Stephane Barbariec53a2752019-03-08 17:50:10 -0500275 log.Debugw("exiting-watch", log.Fields{"key": pr.GetHash(), "watch": pr.watchName})
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500276}
277
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500278func (pr *PersistedRevision) LoadFromPersistence(path string, txid string) []Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500279 log.Debugw("loading-from-persistence", log.Fields{"path": path, "txid": txid})
280
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500281 var response []Revision
282 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400283
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500284 rev = pr
285
Stephane Barbarie260a5632019-02-26 16:12:49 -0500286 if pr.kvStore != nil && path != "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500287 blobMap, _ := pr.kvStore.List(path)
288
289 partition := strings.SplitN(path, "/", 2)
290 name := partition[0]
291
292 if len(partition) < 2 {
293 path = ""
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400294 } else {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500295 path = partition[1]
296 }
297
298 field := ChildrenFields(rev.GetBranch().Node.Type)[name]
299
Stephane Barbarie260a5632019-02-26 16:12:49 -0500300 if field != nil && field.IsContainer {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500301 var children []Revision
302 children = make([]Revision, len(rev.GetChildren(name)))
303 copy(children, rev.GetChildren(name))
304 existChildMap := make(map[string]int)
305 for i, child := range rev.GetChildren(name) {
306 existChildMap[child.GetHash()] = i
307 }
308
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500309 for _, blob := range blobMap {
310 output := blob.Value.([]byte)
311
312 data := reflect.New(field.ClassType.Elem())
313
314 if err := proto.Unmarshal(output, data.Interface().(proto.Message)); err != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500315 log.Errorw(
316 "loading-from-persistence--failed-to-unmarshal",
317 log.Fields{"path": path, "txid": txid, "error": err},
318 )
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500319 } else if field.Key != "" {
320 var key reflect.Value
321 var keyValue interface{}
322 var keyStr string
323
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500324 if path == "" {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500325 // e.g. /logical_devices --> path="" name=logical_devices key=""
326 _, key = GetAttributeValue(data.Interface(), field.Key, 0)
327 keyStr = key.String()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500328
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500329 } else {
330 // e.g.
331 // /logical_devices/abcde --> path="abcde" name=logical_devices
332 // /logical_devices/abcde/image_downloads --> path="abcde/image_downloads" name=logical_devices
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500333
334 partition := strings.SplitN(path, "/", 2)
335 key := partition[0]
336 if len(partition) < 2 {
337 path = ""
338 } else {
339 path = partition[1]
340 }
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500341 keyValue = field.KeyFromStr(key)
342 keyStr = keyValue.(string)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500343
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500344 if idx, childRev := rev.GetBranch().Node.findRevByKey(children, field.Key, keyValue); childRev != nil {
345 // Key is memory, continue recursing path
Stephane Barbarie260a5632019-02-26 16:12:49 -0500346 if newChildRev := childRev.LoadFromPersistence(path, txid); newChildRev != nil {
347 children[idx] = newChildRev[0]
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500348
Stephane Barbarie260a5632019-02-26 16:12:49 -0500349 rev := rev.UpdateChildren(name, rev.GetChildren(name), rev.GetBranch())
350 rev.GetBranch().Node.makeLatest(rev.GetBranch(), rev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500351
Stephane Barbarie260a5632019-02-26 16:12:49 -0500352 response = append(response, newChildRev[0])
353 continue
354 }
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500355 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500356 }
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500357
358 childRev := rev.GetBranch().Node.MakeNode(data.Interface(), txid).Latest(txid)
359 childRev.SetHash(name + "/" + keyStr)
360
361 // Do not process a child that is already in memory
362 if _, childExists := existChildMap[childRev.GetHash()]; !childExists {
363 // Create watch for <component>/<key>
364 childRev.SetupWatch(childRev.GetHash())
365
366 children = append(children, childRev)
367 rev = rev.UpdateChildren(name, children, rev.GetBranch())
368
369 rev.GetBranch().Node.makeLatest(rev.GetBranch(), rev, nil)
370 }
371 response = append(response, childRev)
372 continue
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500373 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400374 }
375 }
376 }
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500377
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500378 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400379}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400380
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500381// UpdateData modifies the information in the data model and saves it in the persistent storage
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400382func (pr *PersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500383 log.Debugw("updating-persisted-data", log.Fields{"hash": pr.GetHash()})
384
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400385 newNPR := pr.Revision.UpdateData(data, branch)
386
387 newPR := &PersistedRevision{
388 Revision: newNPR,
389 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400390 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400391 }
392
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400393 return newPR
394}
395
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500396// UpdateChildren modifies the children of a revision and of a specific component and saves it in the persistent storage
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400397func (pr *PersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500398 log.Debugw("updating-persisted-children", log.Fields{"hash": pr.GetHash()})
399
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400400 newNPR := pr.Revision.UpdateChildren(name, children, branch)
401
402 newPR := &PersistedRevision{
403 Revision: newNPR,
404 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400405 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400406 }
407
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400408 return newPR
409}
410
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500411// UpdateAllChildren modifies the children for all components of a revision and saves it in the peristent storage
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400412func (pr *PersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500413 log.Debugw("updating-all-persisted-children", log.Fields{"hash": pr.GetHash()})
414
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400415 newNPR := pr.Revision.UpdateAllChildren(children, branch)
416
417 newPR := &PersistedRevision{
418 Revision: newNPR,
419 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400420 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400421 }
422
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400423 return newPR
424}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400425
426// Drop takes care of eliminating a revision hash that is no longer needed
427// and its associated config when required
428func (pr *PersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500429 log.Debugw("dropping-revision",
430 log.Fields{"txid": txid, "hash": pr.GetHash(), "config-hash": pr.GetConfig().Hash, "stack": string(debug.Stack())})
431
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500432 pr.mutex.Lock()
433 defer pr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400434 if pr.kvStore != nil && txid == "" {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500435 if pr.isStored {
436 if includeConfig {
437 if err := pr.kvStore.Delete(pr.GetConfig().Hash); err != nil {
438 log.Errorw("failed-to-remove-revision-config", log.Fields{"hash": pr.GetConfig().Hash, "error": err.Error()})
439 }
440 }
441
442 if err := pr.kvStore.Delete(pr.GetHash()); err != nil {
443 log.Errorw("failed-to-remove-revision", log.Fields{"hash": pr.GetHash(), "error": err.Error()})
444 } else {
445 pr.isStored = false
446 }
447
448 if pr.isWatched {
449 pr.kvStore.DeleteWatch(pr.GetHash(), pr.events)
450 pr.isWatched = false
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400451 }
452 }
453
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400454 } else {
455 if includeConfig {
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500456 log.Debugw("attempted-to-remove-transacted-revision-config", log.Fields{"hash": pr.GetConfig().Hash, "txid": txid})
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400457 }
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500458 log.Debugw("attempted-to-remove-transacted-revision", log.Fields{"hash": pr.GetHash(), "txid": txid})
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400459 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500460
461 pr.Revision.Drop(txid, includeConfig)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400462}