blob: a3e6ea71b84f043515546488462efa2929c56223 [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 Barbarie4a2564d2018-07-26 11:02:58 -040016package model
17
Stephane Barbariee16186c2018-09-11 10:46:34 -040018// TODO: proper error handling
19// TODO: proper logging
20
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040021import (
22 "fmt"
23 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040024 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040025 "reflect"
26 "strings"
27)
28
29const (
30 NONE string = "none"
31)
32
Stephane Barbarie06c4a742018-10-01 11:09:32 -040033type Node interface {
34 MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
35
36 // CRUD functions
37 Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
38 Get(path string, hash string, depth int, deep bool, txid string) interface{}
39 Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
40 Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
41
42 MakeBranch(txid string) *Branch
43 DeleteBranch(txid string)
44 MergeBranch(txid string, dryRun bool) (Revision, error)
45
46 MakeTxBranch() string
47 DeleteTxBranch(txid string)
48 FoldTxBranch(txid string)
49
50 GetProxy(path string, exclusive bool) *Proxy
Stephane Barbarie126101e2018-10-11 16:18:48 -040051
52 ExecuteCallbacks()
53 AddCallback(callback CallbackFunction, args ...interface{})
54 AddNotificationCallback(callback CallbackFunction, args ...interface{})
Stephane Barbarie06c4a742018-10-01 11:09:32 -040055}
56
57type node struct {
Stephane Barbarie126101e2018-10-11 16:18:48 -040058 Root *root
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040059 Type interface{}
60 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040061 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040062 Proxy *Proxy
63 EventBus *EventBus
64 AutoPrune bool
65}
66
Stephane Barbarie694e2b92018-09-07 12:17:36 -040067type ChangeTuple struct {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040068 Type CallbackType
69 PreviousData interface{}
70 LatestData interface{}
Stephane Barbarie694e2b92018-09-07 12:17:36 -040071}
72
Stephane Barbarie06c4a742018-10-01 11:09:32 -040073func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
74 n := &node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040075
Stephane Barbarie126101e2018-10-11 16:18:48 -040076 n.Root = root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040077 n.Branches = make(map[string]*Branch)
78 n.Tags = make(map[string]Revision)
79 n.Proxy = nil
80 n.EventBus = nil
81 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040082
83 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040084 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040085 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040086 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040087 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040088 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040089 } else {
90 // not implemented error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040091 log.Errorf("cannot process initial data - %+v", initialData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 }
93
Stephane Barbarieec0919b2018-09-05 14:14:29 -040094 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040095}
96
Stephane Barbarie06c4a742018-10-01 11:09:32 -040097func (n *node) MakeNode(data interface{}, txid string) *node {
Stephane Barbarie126101e2018-10-11 16:18:48 -040098 return NewNode(n.Root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099}
100
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400101func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400102 if n.Root.RevisionClass.(reflect.Type) == reflect.TypeOf(PersistedRevision{}) {
103 return NewPersistedRevision(branch, data, children)
104 }
105
106 return NewNonPersistedRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400107}
108
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400109func (n *node) MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
110 n.makeLatest(branch, revision, changeAnnouncement)
111}
112func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400113 if _, ok := branch.Revisions[revision.GetHash()]; !ok {
114 branch.Revisions[revision.GetHash()] = revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400115 }
116
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400117 if branch.Latest == nil || revision.GetHash() != branch.Latest.GetHash() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400118 branch.Latest = revision
119 }
120
121 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400122 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400123 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400124 log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v",
125 change.Type,
126 change.PreviousData,
127 change.LatestData)
128 n.Root.AddCallback(
129 n.Proxy.InvokeCallbacks,
130 change.Type,
131 true,
132 change.PreviousData,
133 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400134 }
135 }
136
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400137 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400138 log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v",
139 change.Type,
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400140 change.PreviousData,
141 change.LatestData)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400142 n.Root.AddNotificationCallback(
143 n.makeEventBus().Advertise,
144 change.Type,
145 revision.GetHash(),
146 change.PreviousData,
147 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400148 }
149 }
150}
151
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400152func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400153 var branch *Branch
154 var exists bool
155
156 if len(txid) > 0 && txid[0] != "" {
157 if branch, exists = n.Branches[txid[0]]; exists {
158 return branch.Latest
159 }
160 } else if branch, exists = n.Branches[NONE]; exists {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400161 return branch.Latest
162 }
163 return nil
164}
165
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400166func (n *node) GetHash(hash string) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400167 return n.Branches[NONE].Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400168}
169
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400170func (n *node) initialize(data interface{}, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400171 var children map[string][]Revision
172 children = make(map[string][]Revision)
173 for fieldName, field := range ChildrenFields(n.Type) {
174 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400175
176 if fieldValue.IsValid() {
177 if field.IsContainer {
178 if field.Key != "" {
179 var keysSeen []string
180
181 for i := 0; i < fieldValue.Len(); i++ {
182 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400183
184 rev := n.MakeNode(v.Interface(), txid).Latest(txid)
185
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400186 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400187 for _, k := range keysSeen {
188 if k == key.String() {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400189 log.Errorf("duplicate key - %s", k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400190 }
191 }
192 children[fieldName] = append(children[fieldName], rev)
193 keysSeen = append(keysSeen, key.String())
194 }
195
196 } else {
197 for i := 0; i < fieldValue.Len(); i++ {
198 v := fieldValue.Index(i)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400199 children[fieldName] = append(children[fieldName], n.MakeNode(v.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400200 }
201 }
202 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400203 children[fieldName] = append(children[fieldName], n.MakeNode(fieldValue.Interface(), txid).Latest())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400204 }
205 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400206 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400207 }
208 }
209 // FIXME: ClearField??? No such method in go protos. Reset?
210 //data.ClearField(field_name)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400211 branch := NewBranch(n, "", nil, n.AutoPrune)
212 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400213 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400214
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400215 if txid == "" {
216 n.Branches[NONE] = branch
217 } else {
218 n.Branches[txid] = branch
219 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400220}
221
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400222func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
223 for i, rev := range revs {
224 dataValue := reflect.ValueOf(rev.GetData())
225 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
226
227 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
228
Stephane Barbarie126101e2018-10-11 16:18:48 -0400229 //log.Debugf("fieldValue: %+v, type: %+v, value: %+v", fieldValue.Interface(), fieldValue.Type(), value)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400230 a := fmt.Sprintf("%s", fieldValue.Interface())
231 b := fmt.Sprintf("%s", value)
232 if a == b {
233 return i, rev
234 }
235 }
236
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400237 log.Errorf("key %s=%s not found", keyName, value)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400238
239 return -1, nil
240}
241
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400242//
243// Get operation
244//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400245func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400246 if deep {
247 depth = -1
248 }
249
250 for strings.HasPrefix(path, "/") {
251 path = path[1:]
252 }
253
254 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400255 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400256
257 // FIXME: should empty txid be cleaned up?
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400258 if branch = n.Branches[txid]; txid == "" || branch == nil {
259 branch = n.Branches[NONE]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400260 }
261
262 if hash != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400263 rev = branch.Revisions[hash]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400264 } else {
265 rev = branch.Latest
266 }
267
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400268 return n.getPath(rev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400269}
270
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400271func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400272 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400273 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400274 }
275
276 partition := strings.SplitN(path, "/", 2)
277 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400278
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400279 if len(partition) < 2 {
280 path = ""
281 } else {
282 path = partition[1]
283 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400284
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400285 names := ChildrenFields(n.Type)
286 field := names[name]
287
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400288 if field.IsContainer {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400289 if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400290 children := rev.GetChildren()[name]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400291 if path != "" {
292 partition = strings.SplitN(path, "/", 2)
293 key := partition[0]
294 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400295 keyValue := field.KeyFromStr(key)
296 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400297 return nil
298 } else {
299 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400300 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400301 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400302 } else {
303 var response []interface{}
304 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400305 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400306 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400307 response = append(response, value)
308 }
309 return response
310 }
311 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400312 var response []interface{}
313 if path != "" {
314 // TODO: raise error
315 return response
316 }
317 for _, childRev := range rev.GetChildren()[name] {
318 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400319 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400320 response = append(response, value)
321 }
322 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400323 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400324 } else {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400325 childRev := rev.GetChildren()[name][0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400326 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400327 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400328 }
329 return nil
330}
331
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400332func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400333 msg := rev.Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400334 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400335
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400336 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400337 log.Debug("invoking proxy GET Callbacks")
Stephane Barbariea188d942018-10-16 16:43:04 -0400338 if modifiedMsg = n.Proxy.InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
339 msg = modifiedMsg
340 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400341
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400342 }
343 return msg
344}
345
346//
347// Update operation
348//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400349func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400350 // FIXME: is this required ... a bit overkill to take out a "/"
351 for strings.HasPrefix(path, "/") {
352 path = path[1:]
353 }
354
355 var branch *Branch
356 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400357 if txid == "" {
358 branch = n.Branches[NONE]
359 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 branch = makeBranch(n)
361 }
362
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400363 log.Debugf("Branch data : %+v, Passed data: %+v", branch.Latest.GetData(), data)
364
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400365 if path == "" {
366 return n.doUpdate(branch, data, strict)
367 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400368
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400369 // TODO missing some code here...
370 rev := branch.Latest
371
372 partition := strings.SplitN(path, "/", 2)
373 name := partition[0]
374
375 if len(partition) < 2 {
376 path = ""
377 } else {
378 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400379 }
380
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400381 field := ChildrenFields(n.Type)[name]
382 var children []Revision
383
384 if field.IsContainer {
385 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400386 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400387 } else if field.Key != "" {
388 partition := strings.SplitN(path, "/", 2)
389 key := partition[0]
390 if len(partition) < 2 {
391 path = ""
392 } else {
393 path = partition[1]
394 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400395 keyValue := field.KeyFromStr(key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400396 // TODO. Est-ce que le copy ne fonctionne pas? dois-je plutôt faire un clone de chaque item?
397 for _, v := range rev.GetChildren()[name] {
398 revCopy := reflect.ValueOf(v).Interface().(Revision)
399 children = append(children, revCopy)
400 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400401 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400402 childNode := childRev.GetNode()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400403 childNode.Proxy = n.Proxy
Stephane Barbariea188d942018-10-16 16:43:04 -0400404
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400405 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400406
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400407 if newChildRev.GetHash() == childRev.GetHash() {
408 if newChildRev != childRev {
409 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
410 newChildRev.ClearHash()
411 }
412 return branch.Latest
413 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400414
415 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
416 log.Debugf("newKey is %s", newKey.Interface())
417 _newKeyType := fmt.Sprintf("%s", newKey)
418 _keyValueType := fmt.Sprintf("%s", keyValue)
419 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400420 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400421 }
422 children[idx] = newChildRev
423 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400424 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400425 n.Root.MakeLatest(branch, rev, nil)
426 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400427 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400428 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400429 }
430 } else {
431 childRev := rev.GetChildren()[name][0]
432 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400433 childNode.Proxy = n.Proxy
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400434 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
435 rev = rev.UpdateChildren(name, []Revision{newChildRev}, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400436 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400437 n.Root.MakeLatest(branch, rev, nil)
438 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439 }
440 return nil
441}
442
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400443func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400444 log.Debugf("Comparing types - expected: %+v, actual: %+v", reflect.ValueOf(n.Type).Type(), reflect.TypeOf(data))
445
446 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
447 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400448 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400449 return nil
450 }
451
452 // TODO: validate that this actually works
453 //if n.hasChildren(data) {
454 // return nil
455 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400456
457 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400458 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400459 n.Proxy.InvokeCallbacks(PRE_UPDATE, false, branch.Latest.GetData(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400460 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400461 if !reflect.DeepEqual(branch.Latest.GetData(), data) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400462 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400463 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400464 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400465 }
466 rev := branch.Latest.UpdateData(data, branch)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400467 changes := []ChangeTuple{{POST_UPDATE, branch.Latest.GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400468
469 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
470 // FIXME VOL-1293 cont'd: need to figure out the required conditions otherwise we are not cleaning up entries
471 //branch.Latest.Drop(branch.Txid, true)
472
473 n.Root.Proxy = n.Proxy
474 n.Root.MakeLatest(branch, rev, changes)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400475 return rev
476 } else {
477 return branch.Latest
478 }
479}
480
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400481//
482// Add operation
483//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400484func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400485 for strings.HasPrefix(path, "/") {
486 path = path[1:]
487 }
488 if path == "" {
489 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400490 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400491 }
492
493 var branch *Branch
494 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400495 if txid == "" {
496 branch = n.Branches[NONE]
497 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400498 branch = makeBranch(n)
499 }
500
501 rev := branch.Latest
502
503 partition := strings.SplitN(path, "/", 2)
504 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400505
506 if len(partition) < 2 {
507 path = ""
508 } else {
509 path = partition[1]
510 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400511
512 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400513 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400514
515 if field.IsContainer {
516 if path == "" {
517 if field.Key != "" {
518 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400519 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400520 n.Proxy.InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400521 }
522
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400523 for _, v := range rev.GetChildren()[name] {
524 revCopy := reflect.ValueOf(v).Interface().(Revision)
525 children = append(children, revCopy)
526 }
527 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400528 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400529 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400530 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbarie126101e2018-10-11 16:18:48 -0400531 } else {
532 childRev := n.MakeNode(data, txid).Latest(txid)
533 children = append(children, childRev)
534 rev := rev.UpdateChildren(name, children, branch)
535 changes := []ChangeTuple{{POST_ADD, nil, rev.GetData()}}
536 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400537 n.Root.MakeLatest(branch, rev, changes)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400538 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400539 }
540
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400541 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400542 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400543 }
544 } else if field.Key != "" {
545 partition := strings.SplitN(path, "/", 2)
546 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400547 if len(partition) < 2 {
548 path = ""
549 } else {
550 path = partition[1]
551 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400552 keyValue := field.KeyFromStr(key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400553 copy(children, rev.GetChildren()[name])
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400554 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400555 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400556 newChildRev := childNode.Add(path, data, txid, makeBranch)
557 children[idx] = newChildRev
558 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400559 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400560 n.Root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400561 return rev
562 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400563 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400564 }
565 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400566 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400567 }
568 return nil
569}
570
571//
572// Remove operation
573//
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400574func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400575 for strings.HasPrefix(path, "/") {
576 path = path[1:]
577 }
578 if path == "" {
579 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400580 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400581 }
582 var branch *Branch
583 var ok bool
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400584 if txid == "" {
585 branch = n.Branches[NONE]
586 } else if branch, ok = n.Branches[txid]; !ok {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400587 branch = makeBranch(n)
588 }
589
590 rev := branch.Latest
591
592 partition := strings.SplitN(path, "/", 2)
593 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400594 if len(partition) < 2 {
595 path = ""
596 } else {
597 path = partition[1]
598 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400599
600 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400601 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400602 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400603
604 if field.IsContainer {
605 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400606 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400607 } else if field.Key != "" {
608 partition := strings.SplitN(path, "/", 2)
609 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400610 if len(partition) < 2 {
611 path = ""
612 } else {
613 path = partition[1]
614 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400615 keyValue := field.KeyFromStr(key)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400616 if path != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400617 for _, v := range rev.GetChildren()[name] {
618 newV := reflect.ValueOf(v).Interface().(Revision)
619 children = append(children, newV)
620 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400621 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400622 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400623 newChildRev := childNode.Remove(path, txid, makeBranch)
624 children[idx] = newChildRev
625 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400626 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400627 n.Root.MakeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400628 return rev
629 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400630 for _, v := range rev.GetChildren()[name] {
631 newV := reflect.ValueOf(v).Interface().(Revision)
632 children = append(children, newV)
633 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400634 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400635 if n.Proxy != nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400636 data := childRev.GetData()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400637 n.Proxy.InvokeCallbacks(PRE_REMOVE, false, data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400638 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400639 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400640 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400641 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400642 childRev.Drop(txid, true)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400643 children = append(children[:idx], children[idx+1:]...)
644 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400645 branch.Latest.Drop(txid, false)
Stephane Barbariea188d942018-10-16 16:43:04 -0400646 n.Root.MakeLatest(branch, rev, postAnnouncement)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400647 return rev
648 }
649 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400650 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400651 }
652 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400653 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400654 }
655
656 return nil
657}
658
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400659// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
660
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400661type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400662
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400663func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400664 branchPoint := n.Branches[NONE].Latest
665 branch := NewBranch(n, txid, branchPoint, true)
666 n.Branches[txid] = branch
667 return branch
668}
669
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400670func (n *node) DeleteBranch(txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400671 delete(n.Branches, txid)
672}
673
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400674func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400675 f := func(rev Revision) Revision {
676 childBranch := rev.GetBranch()
677
678 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400679 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400680 }
681
682 return rev
683 }
684 return f
685}
686
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400687func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400688 srcBranch := n.Branches[txid]
689 dstBranch := n.Branches[NONE]
690
691 forkRev := srcBranch.Origin
692 srcRev := srcBranch.Latest
693 dstRev := dstBranch.Latest
694
695 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
696
697 if !dryRun {
Stephane Barbariea188d942018-10-16 16:43:04 -0400698 n.Root.MakeLatest(dstBranch, rev, changes)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400699 delete(n.Branches, txid)
700 }
701
Stephane Barbariee16186c2018-09-11 10:46:34 -0400702 // TODO: return proper error when one occurs
703 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400704}
705
706// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
707
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400708//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400709// branch := n.Branches[txid]
710// rev1 := branch.get(hash1)
711// rev2 := branch.get(hash2)
712//
713// if rev1.GetHash() == rev2.GetHash() {
714// // empty patch
715// } else {
716// // translate data to json and generate patch
717// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
718// patch.
719// }
720//}
721
722// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
723
724// TODO: is tag mgmt used in the python implementation? Need to validate
725
726// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
727
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400728func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400729 for fieldName, field := range ChildrenFields(n.Type) {
730 _, fieldValue := GetAttributeValue(data, fieldName, 0)
731
732 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
733 log.Error("cannot update external children")
734 return true
735 }
736 }
737
738 return false
739}
740
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400741// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400742
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400743func (n *node) GetProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400744 //r := NewRoot(n.Type, n.KvStore)
745 //r.node = n
746 //r.KvStore = n.KvStore
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400747
Stephane Barbarie126101e2018-10-11 16:18:48 -0400748 return n.getProxy(path, path, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400749}
Stephane Barbarie126101e2018-10-11 16:18:48 -0400750func (n *node) getProxy(path string, fullPath string, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400751 for strings.HasPrefix(path, "/") {
752 path = path[1:]
753 }
754 if path == "" {
Stephane Barbariea188d942018-10-16 16:43:04 -0400755 return n.makeProxy(path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400756 }
757
758 rev := n.Branches[NONE].Latest
759 partition := strings.SplitN(path, "/", 2)
760 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400761 if len(partition) < 2 {
762 path = ""
763 } else {
764 path = partition[1]
765 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400766
767 field := ChildrenFields(n.Type)[name]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400768 if field != nil && field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400769 if path == "" {
770 log.Error("cannot proxy a container field")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400771 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400772 partition := strings.SplitN(path, "/", 2)
773 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400774 if len(partition) < 2 {
775 path = ""
776 } else {
777 path = partition[1]
778 }
779 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400780 var children []Revision
781 for _, v := range rev.GetChildren()[name] {
782 newV := reflect.ValueOf(v).Interface().(Revision)
783 children = append(children, newV)
784 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400785 _, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400786 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400787
Stephane Barbarie126101e2018-10-11 16:18:48 -0400788 return childNode.getProxy(path, fullPath, exclusive)
789 } else {
790 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400791 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400792 } else {
793 childRev := rev.GetChildren()[name][0]
794 childNode := childRev.GetNode()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400795 return childNode.getProxy(path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400796 }
797
798 return nil
799}
800
Stephane Barbariea188d942018-10-16 16:43:04 -0400801func (n *node) makeProxy(path string, fullPath string, exclusive bool) *Proxy {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400802 r := &root{
803 node: n,
804 Callbacks: n.Root.Callbacks,
805 NotificationCallbacks: n.Root.NotificationCallbacks,
806 DirtyNodes: n.Root.DirtyNodes,
807 KvStore: n.Root.KvStore,
808 Loading: n.Root.Loading,
809 RevisionClass: n.Root.RevisionClass,
810 }
811
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400812 if n.Proxy == nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400813 n.Proxy = NewProxy(r, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400814 } else {
815 if n.Proxy.Exclusive {
816 log.Error("node is already owned exclusively")
817 }
818 }
819 return n.Proxy
820}
821
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400822func (n *node) makeEventBus() *EventBus {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400823 if n.EventBus == nil {
824 n.EventBus = NewEventBus()
825 }
826 return n.EventBus
827}
828
829// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
830
Stephane Barbarie126101e2018-10-11 16:18:48 -0400831func (n *node) LoadLatest(hash string) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400832 branch := NewBranch(n, "", nil, n.AutoPrune)
833 pr := &PersistedRevision{}
Stephane Barbarie126101e2018-10-11 16:18:48 -0400834 rev := pr.Load(branch, n.Root.KvStore, n.Type, hash)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400835 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400836 n.Branches[NONE] = branch
837}
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400838
Stephane Barbarie126101e2018-10-11 16:18:48 -0400839func (n *node) ExecuteCallbacks() {
840 n.Root.ExecuteCallbacks()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400841}