blob: 7ea441700b802c83b7aa02dba41e07db82bfdd58 [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 != "" {
181 var keysSeen []string
182
183 for i := 0; i < fieldValue.Len(); i++ {
184 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400185
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500186 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
187 children[fieldName] = append(children[fieldName], rev)
188 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400189
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400190 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400191 for _, k := range keysSeen {
192 if k == key.String() {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400193 log.Errorf("duplicate key - %s", k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400194 }
195 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400196 keysSeen = append(keysSeen, key.String())
197 }
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{} {
252 log.Debugw("node-list-request", log.Fields{"path": path, "hash": hash, "depth":depth, "deep":deep, "txid":txid})
253 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 Barbarieaa467942019-02-06 14:09:44 -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);
312 reflect.ValueOf(result).IsValid() && reflect.ValueOf(result).IsNil() && n.Root.KvStore != nil {
313 // We got nothing from memory, try to pull it from persistence
314 var prList []interface{}
315 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
316 for _, revEntry := range pr {
317 prList = append(prList, revEntry.GetData())
318 }
319 result = prList
320 }
321 }
322
323 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400324}
325
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500326// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400327func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400328 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400329 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400330 }
331
332 partition := strings.SplitN(path, "/", 2)
333 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400334
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400335 if len(partition) < 2 {
336 path = ""
337 } else {
338 path = partition[1]
339 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400340
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400341 names := ChildrenFields(n.Type)
342 field := names[name]
343
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500344 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500345 children := make([]Revision, len(rev.GetChildren(name)))
346 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500347
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400348 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400349 if path != "" {
350 partition = strings.SplitN(path, "/", 2)
351 key := partition[0]
352 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400353 keyValue := field.KeyFromStr(key)
354 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400355 return nil
356 } else {
357 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400358 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400359 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 } else {
361 var response []interface{}
362 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400363 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400364 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400365 response = append(response, value)
366 }
367 return response
368 }
369 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400370 var response []interface{}
371 if path != "" {
372 // TODO: raise error
373 return response
374 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500375 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400376 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400377 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400378 response = append(response, value)
379 }
380 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400381 }
382 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500383
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500384 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500385 childNode := childRev.GetNode()
386 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400387}
388
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500389// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400390func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500391 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400392 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400393
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500394 if n.GetProxy() != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500395 log.Debugw("invoking-get-callbacks", log.Fields{"data": msg})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500396 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400397 msg = modifiedMsg
398 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400399
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400400 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500401
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400402 return msg
403}
404
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500405// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400406func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500407 log.Debugw("node-update-request", log.Fields{"path": path, "strict": strict, "txid":txid, "makeBranch": makeBranch})
408
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400409 for strings.HasPrefix(path, "/") {
410 path = path[1:]
411 }
412
413 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400414 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500415 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500416 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400417 branch = makeBranch(n)
418 }
419
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500420 if branch.GetLatest() != nil {
421 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
422 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400423 if path == "" {
424 return n.doUpdate(branch, data, strict)
425 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400426
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500427 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400428
429 partition := strings.SplitN(path, "/", 2)
430 name := partition[0]
431
432 if len(partition) < 2 {
433 path = ""
434 } else {
435 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400436 }
437
Stephane Barbarieaa467942019-02-06 14:09:44 -0500438
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439 field := ChildrenFields(n.Type)[name]
440 var children []Revision
441
Stephane Barbarieaa467942019-02-06 14:09:44 -0500442 if field == nil {
443 return n.doUpdate(branch, data, strict)
444 }
445
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400446 if field.IsContainer {
447 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400448 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400449 } else if field.Key != "" {
450 partition := strings.SplitN(path, "/", 2)
451 key := partition[0]
452 if len(partition) < 2 {
453 path = ""
454 } else {
455 path = partition[1]
456 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400457 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500458
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500459 children = make([]Revision, len(rev.GetChildren(name)))
460 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500461
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400462 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400463 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400464
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500465 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500466 // only assign in cases of non sub-folder proxies, i.e. "/"
467 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500468 childNode.Proxy = n.Proxy
469 }
470
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400471 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400472
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400473 if newChildRev.GetHash() == childRev.GetHash() {
474 if newChildRev != childRev {
475 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
476 newChildRev.ClearHash()
477 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500478 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400479 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400480
481 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500482
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400483 _newKeyType := fmt.Sprintf("%s", newKey)
484 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500485
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400486 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400487 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400488 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500489
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500490 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
491 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400492 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500493
494 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500495
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500496 branch.GetLatest().Drop(txid, false)
497 n.makeLatest(branch, updatedRev, nil)
498
Stephane Barbariea188d942018-10-16 16:43:04 -0400499 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500500
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400501 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400502 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400503 }
504 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500505 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400506 childNode := childRev.GetNode()
507 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500508 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
509 rev.Drop(txid, false)
510 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500511
Stephane Barbariea188d942018-10-16 16:43:04 -0400512 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400513 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500514
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400515 return nil
516}
517
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400518func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500519 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
520 reflect.TypeOf(data),
521 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400522
523 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
524 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400525 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400526 return nil
527 }
528
529 // TODO: validate that this actually works
530 //if n.hasChildren(data) {
531 // return nil
532 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400533
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500534 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400535 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500536 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400537 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500538
539 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400540 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400541 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400542 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400543 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500544
545 rev := branch.GetLatest().UpdateData(data, branch)
546 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400547
548 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
549 // 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 -0500550 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400551
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500552 n.makeLatest(branch, rev, changes)
553
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400554 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400555 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500556
557 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400558}
559
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500560// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400561func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500562 log.Debugw("node-add-request", log.Fields{"path": path, "txid":txid, "makeBranch": makeBranch})
563
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400564 for strings.HasPrefix(path, "/") {
565 path = path[1:]
566 }
567 if path == "" {
568 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400569 log.Errorf("cannot add for non-container mode")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500570 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400571 }
572
573 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400574 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500575 branch = n.GetBranch(NONE)
576 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400577 branch = makeBranch(n)
578 }
579
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500580 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400581
582 partition := strings.SplitN(path, "/", 2)
583 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400584
585 if len(partition) < 2 {
586 path = ""
587 } else {
588 path = partition[1]
589 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400590
591 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500592
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400593 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400594
595 if field.IsContainer {
596 if path == "" {
597 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500598 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400599 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500600 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400601 }
602
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500603 children = make([]Revision, len(rev.GetChildren(name)))
604 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500605
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400606 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500607
Stephane Barbarie126101e2018-10-11 16:18:48 -0400608 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400609 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400610 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500611 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400612 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500613 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500614
615 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
616 childRev.SetHash(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500617
618 // Create watch for <component>/<key>
619 childRev.SetupWatch(childRev.GetHash())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500620
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500621 children = append(children, childRev)
622 rev = rev.UpdateChildren(name, children, branch)
623 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400624
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500625 rev.Drop(txid, false)
626 n.makeLatest(branch, rev, changes)
627
628 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400629 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500630 log.Errorf("cannot add to non-keyed container")
631
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400632 } else if field.Key != "" {
633 partition := strings.SplitN(path, "/", 2)
634 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400635 if len(partition) < 2 {
636 path = ""
637 } else {
638 path = partition[1]
639 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400640 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500641
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500642 children = make([]Revision, len(rev.GetChildren(name)))
643 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500644
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400645 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500646
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400647 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400648 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500649
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500650 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
651 childRev.SetHash(name + "/" + keyValue.(string))
652
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400653 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500654
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500655 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500656 rev.Drop(txid, false)
657 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
658
659 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400660 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400661 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400662 }
663 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400664 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400665 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500666
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400667 return nil
668}
669
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500670// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400671func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500672 log.Debugw("node-remove-request", log.Fields{"path": path, "txid":txid, "makeBranch": makeBranch})
673
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400674 for strings.HasPrefix(path, "/") {
675 path = path[1:]
676 }
677 if path == "" {
678 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400679 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400680 }
681 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400682 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500683 branch = n.GetBranch(NONE)
684 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400685 branch = makeBranch(n)
686 }
687
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500688 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400689
690 partition := strings.SplitN(path, "/", 2)
691 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400692 if len(partition) < 2 {
693 path = ""
694 } else {
695 path = partition[1]
696 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400697
698 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400699 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400700 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400701
702 if field.IsContainer {
703 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400704 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400705 } else if field.Key != "" {
706 partition := strings.SplitN(path, "/", 2)
707 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400708 if len(partition) < 2 {
709 path = ""
710 } else {
711 path = partition[1]
712 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400713 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500714 children = make([]Revision, len(rev.GetChildren(name)))
715 copy(children, rev.GetChildren(name))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400716 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400717 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400718 childNode := childRev.GetNode()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500719 if childNode.Proxy == nil {
720 childNode.Proxy = n.Proxy
721 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400722 newChildRev := childNode.Remove(path, txid, makeBranch)
723 children[idx] = newChildRev
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500724 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500725 branch.GetLatest().Drop(txid, false)
726 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500727 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400728 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500729 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
730 if n.GetProxy() != nil {
731 data := childRev.GetData()
732 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
733 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
734 } else {
735 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
736 }
737 childRev.Drop(txid, true)
738 children = append(children[:idx], children[idx+1:]...)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500739 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500740 branch.GetLatest().Drop(txid, false)
741 n.makeLatest(branch, rev, postAnnouncement)
742 return rev
743
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400744 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500745 log.Errorf("cannot add to non-keyed container")
746
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400747 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400748 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400749 }
750
751 return nil
752}
753
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400754// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
755
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500756// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400757type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400758
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500759// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400760func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500761 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400762 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500763 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400764 return branch
765}
766
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500767// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400768func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500769 n.Lock()
770 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400771 delete(n.Branches, txid)
772}
773
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400774func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400775 f := func(rev Revision) Revision {
776 childBranch := rev.GetBranch()
777
778 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400779 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400780 }
781
782 return rev
783 }
784 return f
785}
786
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500787// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400788func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500789 srcBranch := n.GetBranch(txid)
790 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400791
792 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500793 srcRev := srcBranch.GetLatest()
794 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400795
796 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
797
798 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500799 if rev != nil {
800 n.makeLatest(dstBranch, rev, changes)
801 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500802 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400803 }
804
Stephane Barbariee16186c2018-09-11 10:46:34 -0400805 // TODO: return proper error when one occurs
806 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400807}
808
809// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
810
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400811//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400812// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500813// rev1 := branch.GetHash(hash1)
814// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400815//
816// if rev1.GetHash() == rev2.GetHash() {
817// // empty patch
818// } else {
819// // translate data to json and generate patch
820// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
821// patch.
822// }
823//}
824
825// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
826
827// TODO: is tag mgmt used in the python implementation? Need to validate
828
829// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
830
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400831func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400832 for fieldName, field := range ChildrenFields(n.Type) {
833 _, fieldValue := GetAttributeValue(data, fieldName, 0)
834
835 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
836 log.Error("cannot update external children")
837 return true
838 }
839 }
840
841 return false
842}
843
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400844// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400845
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500846// CreateProxy returns a reference to a sub-tree of the data model
847func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500848 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400849}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500850
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500851func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400852 for strings.HasPrefix(path, "/") {
853 path = path[1:]
854 }
855 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500856 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400857 }
858
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500859 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400860 partition := strings.SplitN(path, "/", 2)
861 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400862 if len(partition) < 2 {
863 path = ""
864 } else {
865 path = partition[1]
866 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400867
868 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500869 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400870 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500871 //log.Error("cannot proxy a container field")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500872 newNode := n.MakeNode(reflect.New(field.ClassType.Elem()).Interface(), "")
873 return newNode.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400874 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400875 partition := strings.SplitN(path, "/", 2)
876 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400877 if len(partition) < 2 {
878 path = ""
879 } else {
880 path = partition[1]
881 }
882 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400883 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500884 children = make([]Revision, len(rev.GetChildren(name)))
885 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500886 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
887 childNode := childRev.GetNode()
888 return childNode.createProxy(path, fullPath, n, exclusive)
889 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400890 } else {
891 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400892 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400893 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500894 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400895 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500896 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400897 }
898
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500899 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400900 return nil
901}
902
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500903func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500904 n.Lock()
905 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400906 r := &root{
907 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500908 Callbacks: n.Root.GetCallbacks(),
909 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400910 DirtyNodes: n.Root.DirtyNodes,
911 KvStore: n.Root.KvStore,
912 Loading: n.Root.Loading,
913 RevisionClass: n.Root.RevisionClass,
914 }
915
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400916 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500917 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400918 } else {
919 if n.Proxy.Exclusive {
920 log.Error("node is already owned exclusively")
921 }
922 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500923
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400924 return n.Proxy
925}
926
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400927func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500928 n.Lock()
929 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400930 if n.EventBus == nil {
931 n.EventBus = NewEventBus()
932 }
933 return n.EventBus
934}
935
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500936func (n *node) SetProxy(proxy *Proxy) {
937 n.Lock()
938 defer n.Unlock()
939 n.Proxy = proxy
940}
941
942func (n *node) GetProxy() *Proxy {
943 n.Lock()
944 defer n.Unlock()
945 return n.Proxy
946}
947
948func (n *node) GetBranch(key string) *Branch {
949 n.Lock()
950 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500951
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500952 if n.Branches != nil {
953 if branch, exists := n.Branches[key]; exists {
954 return branch
955 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500956 }
957 return nil
958}
959
960func (n *node) SetBranch(key string, branch *Branch) {
961 n.Lock()
962 defer n.Unlock()
963 n.Branches[key] = branch
964}
965
966func (n *node) GetRoot() *root {
967 n.Lock()
968 defer n.Unlock()
969 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400970}