blob: 691ea2523c6552c15e0eb4ee1498cc62bf932d1c [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
Stephane Barbariee16186c2018-09-11 10:46:34 -040019// TODO: proper error handling
20// TODO: proper logging
21
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040022import (
23 "fmt"
24 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040025 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040026 "reflect"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050027 "runtime/debug"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040028 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050029 "sync"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040030)
31
Stephane Barbariedc5022d2018-11-19 15:21:44 -050032// When a branch has no transaction id, everything gets stored in NONE
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040033const (
34 NONE string = "none"
35)
36
Stephane Barbariedc5022d2018-11-19 15:21:44 -050037// Node interface is an abstraction of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040038type Node interface {
39 MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
40
41 // CRUD functions
42 Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
43 Get(path string, hash string, depth int, deep bool, txid string) interface{}
44 Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
45 Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
46
47 MakeBranch(txid string) *Branch
48 DeleteBranch(txid string)
49 MergeBranch(txid string, dryRun bool) (Revision, error)
50
51 MakeTxBranch() string
52 DeleteTxBranch(txid string)
53 FoldTxBranch(txid string)
54
Stephane Barbariedc5022d2018-11-19 15:21:44 -050055 CreateProxy(path string, exclusive bool) *Proxy
56 GetProxy() *Proxy
Stephane Barbarie06c4a742018-10-01 11:09:32 -040057}
58
59type node struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050060 sync.RWMutex
Stephane Barbarie126101e2018-10-11 16:18:48 -040061 Root *root
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040062 Type interface{}
63 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040064 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040065 Proxy *Proxy
66 EventBus *EventBus
67 AutoPrune bool
68}
69
Stephane Barbariedc5022d2018-11-19 15:21:44 -050070// ChangeTuple holds details of modifications made to a revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -040071type ChangeTuple struct {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040072 Type CallbackType
73 PreviousData interface{}
74 LatestData interface{}
Stephane Barbarie694e2b92018-09-07 12:17:36 -040075}
76
Stephane Barbariedc5022d2018-11-19 15:21:44 -050077// NewNode creates a new instance of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040078func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
79 n := &node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040080
Stephane Barbarie126101e2018-10-11 16:18:48 -040081 n.Root = root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040082 n.Branches = make(map[string]*Branch)
83 n.Tags = make(map[string]Revision)
84 n.Proxy = nil
85 n.EventBus = nil
86 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040087
88 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040089 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040090 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040091 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050093 // FIXME: this block does not reflect the original implementation
94 // it should be checking if the provided initial_data is already a type!??!
95 // it should be checked before IsProtoMessage
Stephane Barbarieec0919b2018-09-05 14:14:29 -040096 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040097 } else {
98 // not implemented error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040099 log.Errorf("cannot process initial data - %+v", initialData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400100 }
101
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400102 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400103}
104
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500105// MakeNode creates a new node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400106func (n *node) MakeNode(data interface{}, txid string) *node {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400107 return NewNode(n.Root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400108}
109
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500110// MakeRevision create a new revision of the node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400111func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500112 return n.GetRoot().MakeRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400113}
114
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500115// makeLatest will mark the revision of a node as being the latest
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400116func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500117 branch.AddRevision(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400118
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500119 if branch.GetLatest() == nil || revision.GetHash() != branch.GetLatest().GetHash() {
120 branch.SetLatest(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400121 }
122
123 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500124 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400125 for _, change := range changeAnnouncement {
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500126 log.Debugw("invoking callback",
127 log.Fields{
Stephane Barbarieaa467942019-02-06 14:09:44 -0500128 "callbacks": n.GetProxy().getCallbacks(change.Type),
129 "type": change.Type,
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500130 "previousData": change.PreviousData,
Stephane Barbarieaa467942019-02-06 14:09:44 -0500131 "latestData": change.LatestData,
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500132 })
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500133 n.GetRoot().AddCallback(
134 n.GetProxy().InvokeCallbacks,
Stephane Barbarie126101e2018-10-11 16:18:48 -0400135 change.Type,
136 true,
137 change.PreviousData,
138 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400139 }
140 }
141
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400142 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400143 log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v",
144 change.Type,
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400145 change.PreviousData,
146 change.LatestData)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500147 n.GetRoot().AddNotificationCallback(
Stephane Barbarie126101e2018-10-11 16:18:48 -0400148 n.makeEventBus().Advertise,
149 change.Type,
150 revision.GetHash(),
151 change.PreviousData,
152 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400153 }
154 }
155}
156
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500157// Latest returns the latest revision of node with or without the transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400158func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400159 var branch *Branch
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400160
161 if len(txid) > 0 && txid[0] != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500162 if branch = n.GetBranch(txid[0]); branch != nil {
163 return branch.GetLatest()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400164 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500165 } else if branch = n.GetBranch(NONE); branch != nil {
166 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400167 }
168 return nil
169}
170
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500171// initialize prepares the content of a node along with its possible ramifications
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400172func (n *node) initialize(data interface{}, txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500173 n.Lock()
174 children := make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400175 for fieldName, field := range ChildrenFields(n.Type) {
176 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400177
178 if fieldValue.IsValid() {
179 if field.IsContainer {
180 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400181 for i := 0; i < fieldValue.Len(); i++ {
182 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400183
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500184 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
185 children[fieldName] = append(children[fieldName], rev)
186 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400187
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500188 // TODO: The following logic was ported from v1.0. Need to verify if it is required
189 //var keysSeen []string
190 //_, key := GetAttributeValue(v.Interface(), field.Key, 0)
191 //for _, k := range keysSeen {
192 // if k == key.String() {
193 // //log.Errorf("duplicate key - %s", k)
194 // }
195 //}
196 //keysSeen = append(keysSeen, key.String())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400197 }
198
199 } else {
200 for i := 0; i < fieldValue.Len(); i++ {
201 v := fieldValue.Index(i)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500202 if newNodeRev := n.MakeNode(v.Interface(), txid).Latest(); newNodeRev != nil {
203 children[fieldName] = append(children[fieldName], newNodeRev)
204 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400205 }
206 }
207 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500208 if newNodeRev := n.MakeNode(fieldValue.Interface(), txid).Latest(); newNodeRev != nil {
209 children[fieldName] = append(children[fieldName], newNodeRev)
210 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400211 }
212 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400213 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400214 }
215 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500216 n.Unlock()
217
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400218 branch := NewBranch(n, "", nil, n.AutoPrune)
219 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400220 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400221
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400222 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500223 n.SetBranch(NONE, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400224 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500225 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400226 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400227}
228
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500229// findRevByKey retrieves a specific revision from a node tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400230func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500231 n.Lock()
232 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500233
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400234 for i, rev := range revs {
235 dataValue := reflect.ValueOf(rev.GetData())
236 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
237
238 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
239
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400240 a := fmt.Sprintf("%s", fieldValue.Interface())
241 b := fmt.Sprintf("%s", value)
242 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500243 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400244 }
245 }
246
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400247 return -1, nil
248}
249
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500250// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarieaa467942019-02-06 14:09:44 -0500251func (n *node) List(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500252 log.Debugw("node-list-request", log.Fields{"path": path, "hash": hash, "depth": depth, "deep": deep, "txid": txid})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500253 if deep {
254 depth = -1
255 }
256
257 for strings.HasPrefix(path, "/") {
258 path = path[1:]
259 }
260
261 var branch *Branch
262 var rev Revision
263
264 if branch = n.GetBranch(txid); txid == "" || branch == nil {
265 branch = n.GetBranch(NONE)
266 }
267
268 if hash != "" {
269 rev = branch.GetRevision(hash)
270 } else {
271 rev = branch.GetLatest()
272 }
273
274 var result interface{}
275 var prList []interface{}
276 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
277 for _, revEntry := range pr {
278 prList = append(prList, revEntry.GetData())
279 }
280 result = prList
281 }
282
283 return result
284}
285
286// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400287func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500288 log.Debugw("node-get-request", log.Fields{"path": path, "hash": hash, "depth": depth, "deep": deep, "txid": txid})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400289 if deep {
290 depth = -1
291 }
292
293 for strings.HasPrefix(path, "/") {
294 path = path[1:]
295 }
296
297 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400298 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400299
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500300 if branch = n.GetBranch(txid); txid == "" || branch == nil {
301 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400302 }
303
304 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500305 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400306 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500307 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400308 }
309
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500310 var result interface{}
311 if result = n.getPath(rev.GetBranch().GetLatest(), path, depth);
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500312 (result == nil || reflect.ValueOf(result).IsValid() && reflect.ValueOf(result).IsNil()) && n.Root.KvStore != nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500313 // We got nothing from memory, try to pull it from persistence
314 var prList []interface{}
315 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500316 // Did we receive a single or multiple revisions?
317 if len(pr) > 1 {
318 for _, revEntry := range pr {
319 prList = append(prList, revEntry.GetData())
320 }
321 result = prList
322 } else {
323 result = pr[0].GetData()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500324 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500325 }
326 }
327
328 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400329}
330
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500331// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400332func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400333 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400334 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400335 }
336
337 partition := strings.SplitN(path, "/", 2)
338 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400339
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400340 if len(partition) < 2 {
341 path = ""
342 } else {
343 path = partition[1]
344 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400345
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400346 names := ChildrenFields(n.Type)
347 field := names[name]
348
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500349 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500350 children := make([]Revision, len(rev.GetChildren(name)))
351 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500352
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400353 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400354 if path != "" {
355 partition = strings.SplitN(path, "/", 2)
356 key := partition[0]
357 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400358 keyValue := field.KeyFromStr(key)
359 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400360 return nil
361 } else {
362 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400363 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400364 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400365 } else {
366 var response []interface{}
367 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400368 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400369 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400370 response = append(response, value)
371 }
372 return response
373 }
374 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400375 var response []interface{}
376 if path != "" {
377 // TODO: raise error
378 return response
379 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500380 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400381 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400382 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400383 response = append(response, value)
384 }
385 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400386 }
387 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500388
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500389 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500390 childNode := childRev.GetNode()
391 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400392}
393
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500394// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400395func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500396 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400397 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400398
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500399 if n.GetProxy() != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500400 log.Debugw("invoking-get-callbacks", log.Fields{"data": msg})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500401 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400402 msg = modifiedMsg
403 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400404
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400405 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500406
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400407 return msg
408}
409
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500410// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400411func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500412 log.Debugw("node-update-request", log.Fields{"path": path, "strict": strict, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500413
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400414 for strings.HasPrefix(path, "/") {
415 path = path[1:]
416 }
417
418 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400419 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500420 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500421 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400422 branch = makeBranch(n)
423 }
424
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500425 if branch.GetLatest() != nil {
426 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
427 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400428 if path == "" {
429 return n.doUpdate(branch, data, strict)
430 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400431
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500432 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400433
434 partition := strings.SplitN(path, "/", 2)
435 name := partition[0]
436
437 if len(partition) < 2 {
438 path = ""
439 } else {
440 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400441 }
442
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400443 field := ChildrenFields(n.Type)[name]
444 var children []Revision
445
Stephane Barbarieaa467942019-02-06 14:09:44 -0500446 if field == nil {
447 return n.doUpdate(branch, data, strict)
448 }
449
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400450 if field.IsContainer {
451 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400452 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400453 } else if field.Key != "" {
454 partition := strings.SplitN(path, "/", 2)
455 key := partition[0]
456 if len(partition) < 2 {
457 path = ""
458 } else {
459 path = partition[1]
460 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400461 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500462
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500463 children = make([]Revision, len(rev.GetChildren(name)))
464 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500465
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400466 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400467 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400468
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500469 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500470 // only assign in cases of non sub-folder proxies, i.e. "/"
471 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500472 childNode.Proxy = n.Proxy
473 }
474
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400475 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400476
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400477 if newChildRev.GetHash() == childRev.GetHash() {
478 if newChildRev != childRev {
479 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
480 newChildRev.ClearHash()
481 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500482 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400483 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400484
485 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500486
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400487 _newKeyType := fmt.Sprintf("%s", newKey)
488 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500489
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400490 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400491 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400492 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500493
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500494 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
495 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400496 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500497
498 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500499
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500500 branch.GetLatest().Drop(txid, false)
501 n.makeLatest(branch, updatedRev, nil)
502
Stephane Barbariea188d942018-10-16 16:43:04 -0400503 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500504
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400505 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400506 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400507 }
508 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500509 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400510 childNode := childRev.GetNode()
511 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500512 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
513 rev.Drop(txid, false)
514 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500515
Stephane Barbariea188d942018-10-16 16:43:04 -0400516 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400517 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500518
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400519 return nil
520}
521
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400522func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500523 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
524 reflect.TypeOf(data),
525 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400526
527 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
528 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400529 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400530 return nil
531 }
532
533 // TODO: validate that this actually works
534 //if n.hasChildren(data) {
535 // return nil
536 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400537
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500538 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400539 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500540 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400541 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500542
543 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400544 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400545 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400546 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400547 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500548
549 rev := branch.GetLatest().UpdateData(data, branch)
550 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400551
552 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
553 // FIXME VOL-1293 cont'd: need to figure out the required conditions otherwise we are not cleaning up entries
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500554 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400555
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500556 n.makeLatest(branch, rev, changes)
557
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400558 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400559 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500560
561 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400562}
563
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400565func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500566 log.Debugw("node-add-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500567
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400568 for strings.HasPrefix(path, "/") {
569 path = path[1:]
570 }
571 if path == "" {
572 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400573 log.Errorf("cannot add for non-container mode")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500574 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400575 }
576
577 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400578 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500579 branch = n.GetBranch(NONE)
580 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400581 branch = makeBranch(n)
582 }
583
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500584 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400585
586 partition := strings.SplitN(path, "/", 2)
587 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400588
589 if len(partition) < 2 {
590 path = ""
591 } else {
592 path = partition[1]
593 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400594
595 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500596
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400597 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400598
599 if field.IsContainer {
600 if path == "" {
601 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500602 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400603 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500604 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400605 }
606
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500607 children = make([]Revision, len(rev.GetChildren(name)))
608 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500609
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400610 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500611
Stephane Barbarie126101e2018-10-11 16:18:48 -0400612 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400613 // TODO raise error
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500614 log.Warnw("duplicate-key-found", log.Fields{"key":key.String()})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500615 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400616 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500617 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500618
619 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
620 childRev.SetHash(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500621
622 // Create watch for <component>/<key>
623 childRev.SetupWatch(childRev.GetHash())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500624
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500625 children = append(children, childRev)
626 rev = rev.UpdateChildren(name, children, branch)
627 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400628
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500629 rev.Drop(txid, false)
630 n.makeLatest(branch, rev, changes)
631
632 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400633 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500634 log.Errorf("cannot add to non-keyed container")
635
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400636 } else if field.Key != "" {
637 partition := strings.SplitN(path, "/", 2)
638 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400639 if len(partition) < 2 {
640 path = ""
641 } else {
642 path = partition[1]
643 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400644 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500645
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500646 children = make([]Revision, len(rev.GetChildren(name)))
647 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500648
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400649 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500650
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400651 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400652 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500653
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500654 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
655 childRev.SetHash(name + "/" + keyValue.(string))
656
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400657 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500658
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500659 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500660 rev.Drop(txid, false)
661 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
662
663 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400664 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400665 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400666 }
667 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400668 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400669 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500670
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400671 return nil
672}
673
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500674// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400675func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500676 log.Debugw("node-remove-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500677
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400678 for strings.HasPrefix(path, "/") {
679 path = path[1:]
680 }
681 if path == "" {
682 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400683 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400684 }
685 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400686 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500687 branch = n.GetBranch(NONE)
688 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400689 branch = makeBranch(n)
690 }
691
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500692 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400693
694 partition := strings.SplitN(path, "/", 2)
695 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400696 if len(partition) < 2 {
697 path = ""
698 } else {
699 path = partition[1]
700 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400701
702 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400703 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400704 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400705
706 if field.IsContainer {
707 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400708 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400709 } else if field.Key != "" {
710 partition := strings.SplitN(path, "/", 2)
711 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400712 if len(partition) < 2 {
713 path = ""
714 } else {
715 path = partition[1]
716 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400717 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500718 children = make([]Revision, len(rev.GetChildren(name)))
719 copy(children, rev.GetChildren(name))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400720 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400721 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400722 childNode := childRev.GetNode()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500723 if childNode.Proxy == nil {
724 childNode.Proxy = n.Proxy
725 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400726 newChildRev := childNode.Remove(path, txid, makeBranch)
727 children[idx] = newChildRev
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500728 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500729 branch.GetLatest().Drop(txid, false)
730 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500731 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400732 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500733 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
734 if n.GetProxy() != nil {
735 data := childRev.GetData()
736 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
737 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
738 } else {
739 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
740 }
741 childRev.Drop(txid, true)
742 children = append(children[:idx], children[idx+1:]...)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500743 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500744 branch.GetLatest().Drop(txid, false)
745 n.makeLatest(branch, rev, postAnnouncement)
746 return rev
747
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400748 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500749 log.Errorf("cannot add to non-keyed container")
750
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400751 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400752 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400753 }
754
755 return nil
756}
757
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400758// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
759
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500760// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400761type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400762
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500763// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400764func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500765 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400766 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500767 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400768 return branch
769}
770
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500771// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400772func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500773 n.Lock()
774 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400775 delete(n.Branches, txid)
776}
777
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400778func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400779 f := func(rev Revision) Revision {
780 childBranch := rev.GetBranch()
781
782 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400783 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400784 }
785
786 return rev
787 }
788 return f
789}
790
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500791// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400792func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500793 srcBranch := n.GetBranch(txid)
794 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400795
796 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500797 srcRev := srcBranch.GetLatest()
798 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400799
800 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
801
802 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500803 if rev != nil {
804 n.makeLatest(dstBranch, rev, changes)
805 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500806 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400807 }
808
Stephane Barbariee16186c2018-09-11 10:46:34 -0400809 // TODO: return proper error when one occurs
810 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400811}
812
813// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
814
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400815//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400816// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500817// rev1 := branch.GetHash(hash1)
818// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400819//
820// if rev1.GetHash() == rev2.GetHash() {
821// // empty patch
822// } else {
823// // translate data to json and generate patch
824// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
825// patch.
826// }
827//}
828
829// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
830
831// TODO: is tag mgmt used in the python implementation? Need to validate
832
833// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
834
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400835func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400836 for fieldName, field := range ChildrenFields(n.Type) {
837 _, fieldValue := GetAttributeValue(data, fieldName, 0)
838
839 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
840 log.Error("cannot update external children")
841 return true
842 }
843 }
844
845 return false
846}
847
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400848// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400849
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500850// CreateProxy returns a reference to a sub-tree of the data model
851func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500852 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400853}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500854
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500855func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400856 for strings.HasPrefix(path, "/") {
857 path = path[1:]
858 }
859 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500860 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400861 }
862
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500863 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400864 partition := strings.SplitN(path, "/", 2)
865 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400866 if len(partition) < 2 {
867 path = ""
868 } else {
869 path = partition[1]
870 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400871
872 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500873 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400874 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500875 //log.Error("cannot proxy a container field")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500876 newNode := n.MakeNode(reflect.New(field.ClassType.Elem()).Interface(), "")
877 return newNode.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400878 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400879 partition := strings.SplitN(path, "/", 2)
880 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400881 if len(partition) < 2 {
882 path = ""
883 } else {
884 path = partition[1]
885 }
886 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400887 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500888 children = make([]Revision, len(rev.GetChildren(name)))
889 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500890 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
891 childNode := childRev.GetNode()
892 return childNode.createProxy(path, fullPath, n, exclusive)
893 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400894 } else {
895 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400896 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400897 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500898 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400899 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500900 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400901 }
902
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500903 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400904 return nil
905}
906
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500907func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500908 n.Lock()
909 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400910 r := &root{
911 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500912 Callbacks: n.Root.GetCallbacks(),
913 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400914 DirtyNodes: n.Root.DirtyNodes,
915 KvStore: n.Root.KvStore,
916 Loading: n.Root.Loading,
917 RevisionClass: n.Root.RevisionClass,
918 }
919
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400920 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500921 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400922 } else {
923 if n.Proxy.Exclusive {
924 log.Error("node is already owned exclusively")
925 }
926 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500927
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400928 return n.Proxy
929}
930
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400931func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500932 n.Lock()
933 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400934 if n.EventBus == nil {
935 n.EventBus = NewEventBus()
936 }
937 return n.EventBus
938}
939
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500940func (n *node) SetProxy(proxy *Proxy) {
941 n.Lock()
942 defer n.Unlock()
943 n.Proxy = proxy
944}
945
946func (n *node) GetProxy() *Proxy {
947 n.Lock()
948 defer n.Unlock()
949 return n.Proxy
950}
951
952func (n *node) GetBranch(key string) *Branch {
953 n.Lock()
954 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500955
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500956 if n.Branches != nil {
957 if branch, exists := n.Branches[key]; exists {
958 return branch
959 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500960 }
961 return nil
962}
963
964func (n *node) SetBranch(key string, branch *Branch) {
965 n.Lock()
966 defer n.Unlock()
967 n.Branches[key] = branch
968}
969
970func (n *node) GetRoot() *root {
971 n.Lock()
972 defer n.Unlock()
973 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400974}