blob: 67848ebfa7211dbc7e90289851c3f7286fbb726c [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{
128 "callbacks": n.GetProxy().getCallbacks(change.Type),
129 "type":change.Type,
130 "previousData": change.PreviousData,
131 "latestData": change.LatestData,
132 })
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 Barbarie06c4a742018-10-01 11:09:32 -0400251func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400252 if deep {
253 depth = -1
254 }
255
256 for strings.HasPrefix(path, "/") {
257 path = path[1:]
258 }
259
260 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400261 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400262
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500263 if branch = n.GetBranch(txid); txid == "" || branch == nil {
264 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400265 }
266
267 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500268 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400269 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500270 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400271 }
272
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500273 var result interface{}
274 if result = n.getPath(rev.GetBranch().GetLatest(), path, depth);
275 reflect.ValueOf(result).IsValid() && reflect.ValueOf(result).IsNil() && n.Root.KvStore != nil {
276 // We got nothing from memory, try to pull it from persistence
277 var prList []interface{}
278 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
279 for _, revEntry := range pr {
280 prList = append(prList, revEntry.GetData())
281 }
282 result = prList
283 }
284 }
285
286 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400287}
288
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500289// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400290func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400291 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400292 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400293 }
294
295 partition := strings.SplitN(path, "/", 2)
296 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400297
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400298 if len(partition) < 2 {
299 path = ""
300 } else {
301 path = partition[1]
302 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400303
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400304 names := ChildrenFields(n.Type)
305 field := names[name]
306
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500307 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500308 children := make([]Revision, len(rev.GetChildren(name)))
309 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500310
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400311 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400312 if path != "" {
313 partition = strings.SplitN(path, "/", 2)
314 key := partition[0]
315 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400316 keyValue := field.KeyFromStr(key)
317 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400318 return nil
319 } else {
320 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400321 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400322 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400323 } else {
324 var response []interface{}
325 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400326 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400327 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400328 response = append(response, value)
329 }
330 return response
331 }
332 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400333 var response []interface{}
334 if path != "" {
335 // TODO: raise error
336 return response
337 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500338 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400339 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400340 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400341 response = append(response, value)
342 }
343 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400344 }
345 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500346
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500347 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500348 childNode := childRev.GetNode()
349 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400350}
351
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500352// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400353func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500354 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400355 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400356
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500357 if n.GetProxy() != nil {
358 log.Debug("invoking proxy GET Callbacks : %+v", msg)
359 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400360 msg = modifiedMsg
361 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400362
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400363 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500364
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400365 return msg
366}
367
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500368// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400369func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400370 for strings.HasPrefix(path, "/") {
371 path = path[1:]
372 }
373
374 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400375 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500376 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500377 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400378 branch = makeBranch(n)
379 }
380
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500381 if branch.GetLatest() != nil {
382 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
383 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400384 if path == "" {
385 return n.doUpdate(branch, data, strict)
386 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400387
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500388 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400389
390 partition := strings.SplitN(path, "/", 2)
391 name := partition[0]
392
393 if len(partition) < 2 {
394 path = ""
395 } else {
396 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400397 }
398
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400399 field := ChildrenFields(n.Type)[name]
400 var children []Revision
401
402 if field.IsContainer {
403 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400404 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400405 } else if field.Key != "" {
406 partition := strings.SplitN(path, "/", 2)
407 key := partition[0]
408 if len(partition) < 2 {
409 path = ""
410 } else {
411 path = partition[1]
412 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400413 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500414
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500415 children = make([]Revision, len(rev.GetChildren(name)))
416 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500417
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400418 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400419 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400420
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500421 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500422 // only assign in cases of non sub-folder proxies, i.e. "/"
423 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500424 childNode.Proxy = n.Proxy
425 }
426
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400427 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400428
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400429 if newChildRev.GetHash() == childRev.GetHash() {
430 if newChildRev != childRev {
431 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
432 newChildRev.ClearHash()
433 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500434 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400435 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400436
437 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500438
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400439 _newKeyType := fmt.Sprintf("%s", newKey)
440 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500441
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400442 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400443 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400444 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500445
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500446 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
447 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400448 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500449
450 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500451
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500452 branch.GetLatest().Drop(txid, false)
453 n.makeLatest(branch, updatedRev, nil)
454
Stephane Barbariea188d942018-10-16 16:43:04 -0400455 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500456
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400457 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400458 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400459 }
460 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500461 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400462 childNode := childRev.GetNode()
463 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500464 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
465 rev.Drop(txid, false)
466 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500467
Stephane Barbariea188d942018-10-16 16:43:04 -0400468 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400469 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500470
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400471 return nil
472}
473
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400474func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500475 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
476 reflect.TypeOf(data),
477 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400478
479 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
480 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400481 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400482 return nil
483 }
484
485 // TODO: validate that this actually works
486 //if n.hasChildren(data) {
487 // return nil
488 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400489
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500490 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400491 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500492 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400493 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500494
495 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400496 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400497 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400498 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400499 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500500
501 rev := branch.GetLatest().UpdateData(data, branch)
502 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400503
504 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
505 // 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 -0500506 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400507
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500508 n.makeLatest(branch, rev, changes)
509
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400510 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400511 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500512
513 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400514}
515
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500516// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400517func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400518 for strings.HasPrefix(path, "/") {
519 path = path[1:]
520 }
521 if path == "" {
522 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400523 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400524 }
525
526 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400527 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500528 branch = n.GetBranch(NONE)
529 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400530 branch = makeBranch(n)
531 }
532
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500533 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400534
535 partition := strings.SplitN(path, "/", 2)
536 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400537
538 if len(partition) < 2 {
539 path = ""
540 } else {
541 path = partition[1]
542 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400543
544 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500545
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400546 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400547
548 if field.IsContainer {
549 if path == "" {
550 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500551 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400552 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500553 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400554 }
555
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500556 children = make([]Revision, len(rev.GetChildren(name)))
557 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500558
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400559 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500560
Stephane Barbarie126101e2018-10-11 16:18:48 -0400561 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400562 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400563 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400565 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500566 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500567
568 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
569 childRev.SetHash(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500570
571 // Create watch for <component>/<key>
572 childRev.SetupWatch(childRev.GetHash())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500573
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500574 children = append(children, childRev)
575 rev = rev.UpdateChildren(name, children, branch)
576 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400577
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500578 rev.Drop(txid, false)
579 n.makeLatest(branch, rev, changes)
580
581 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400582 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500583 log.Errorf("cannot add to non-keyed container")
584
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400585 } else if field.Key != "" {
586 partition := strings.SplitN(path, "/", 2)
587 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400588 if len(partition) < 2 {
589 path = ""
590 } else {
591 path = partition[1]
592 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400593 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500594
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500595 children = make([]Revision, len(rev.GetChildren(name)))
596 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500597
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400598 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500599
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400600 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400601 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500602
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500603 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
604 childRev.SetHash(name + "/" + keyValue.(string))
605
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400606 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500607
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500608 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500609 rev.Drop(txid, false)
610 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
611
612 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400613 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400614 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400615 }
616 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400617 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400618 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500619
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400620 return nil
621}
622
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500623// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400624func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400625 for strings.HasPrefix(path, "/") {
626 path = path[1:]
627 }
628 if path == "" {
629 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400630 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400631 }
632 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400633 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500634 branch = n.GetBranch(NONE)
635 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400636 branch = makeBranch(n)
637 }
638
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500639 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400640
641 partition := strings.SplitN(path, "/", 2)
642 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400643 if len(partition) < 2 {
644 path = ""
645 } else {
646 path = partition[1]
647 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400648
649 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400650 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400651 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400652
653 if field.IsContainer {
654 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400655 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400656 } else if field.Key != "" {
657 partition := strings.SplitN(path, "/", 2)
658 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400659 if len(partition) < 2 {
660 path = ""
661 } else {
662 path = partition[1]
663 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400664 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500665 children = make([]Revision, len(rev.GetChildren(name)))
666 copy(children, rev.GetChildren(name))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400667 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400668 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400669 childNode := childRev.GetNode()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500670 if childNode.Proxy == nil {
671 childNode.Proxy = n.Proxy
672 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400673 newChildRev := childNode.Remove(path, txid, makeBranch)
674 children[idx] = newChildRev
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500675 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500676 branch.GetLatest().Drop(txid, false)
677 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500678 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400679 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500680 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
681 if n.GetProxy() != nil {
682 data := childRev.GetData()
683 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
684 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
685 } else {
686 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
687 }
688 childRev.Drop(txid, true)
689 children = append(children[:idx], children[idx+1:]...)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500690 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500691 branch.GetLatest().Drop(txid, false)
692 n.makeLatest(branch, rev, postAnnouncement)
693 return rev
694
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400695 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500696 log.Errorf("cannot add to non-keyed container")
697
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400698 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400699 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400700 }
701
702 return nil
703}
704
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400705// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
706
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500707// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400708type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400709
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500710// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400711func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500712 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400713 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500714 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400715 return branch
716}
717
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500718// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400719func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500720 n.Lock()
721 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400722 delete(n.Branches, txid)
723}
724
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400725func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400726 f := func(rev Revision) Revision {
727 childBranch := rev.GetBranch()
728
729 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400730 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400731 }
732
733 return rev
734 }
735 return f
736}
737
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500738// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400739func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500740 srcBranch := n.GetBranch(txid)
741 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400742
743 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500744 srcRev := srcBranch.GetLatest()
745 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400746
747 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
748
749 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500750 if rev != nil {
751 n.makeLatest(dstBranch, rev, changes)
752 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500753 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400754 }
755
Stephane Barbariee16186c2018-09-11 10:46:34 -0400756 // TODO: return proper error when one occurs
757 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400758}
759
760// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
761
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400762//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400763// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500764// rev1 := branch.GetHash(hash1)
765// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400766//
767// if rev1.GetHash() == rev2.GetHash() {
768// // empty patch
769// } else {
770// // translate data to json and generate patch
771// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
772// patch.
773// }
774//}
775
776// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
777
778// TODO: is tag mgmt used in the python implementation? Need to validate
779
780// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
781
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400782func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400783 for fieldName, field := range ChildrenFields(n.Type) {
784 _, fieldValue := GetAttributeValue(data, fieldName, 0)
785
786 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
787 log.Error("cannot update external children")
788 return true
789 }
790 }
791
792 return false
793}
794
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400795// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400796
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500797// CreateProxy returns a reference to a sub-tree of the data model
798func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500799 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400800}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500801
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500802func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400803 for strings.HasPrefix(path, "/") {
804 path = path[1:]
805 }
806 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500807 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400808 }
809
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500810 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400811 partition := strings.SplitN(path, "/", 2)
812 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400813 if len(partition) < 2 {
814 path = ""
815 } else {
816 path = partition[1]
817 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400818
819 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500820 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400821 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500822 //log.Error("cannot proxy a container field")
823 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400824 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400825 partition := strings.SplitN(path, "/", 2)
826 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400827 if len(partition) < 2 {
828 path = ""
829 } else {
830 path = partition[1]
831 }
832 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400833 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500834 children = make([]Revision, len(rev.GetChildren(name)))
835 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500836 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
837 childNode := childRev.GetNode()
838 return childNode.createProxy(path, fullPath, n, exclusive)
839 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400840 } else {
841 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400842 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400843 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500844 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400845 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500846 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400847 }
848
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500849 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400850 return nil
851}
852
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500853func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500854 n.Lock()
855 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400856 r := &root{
857 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500858 Callbacks: n.Root.GetCallbacks(),
859 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400860 DirtyNodes: n.Root.DirtyNodes,
861 KvStore: n.Root.KvStore,
862 Loading: n.Root.Loading,
863 RevisionClass: n.Root.RevisionClass,
864 }
865
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400866 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500867 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400868 } else {
869 if n.Proxy.Exclusive {
870 log.Error("node is already owned exclusively")
871 }
872 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500873
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400874 return n.Proxy
875}
876
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400877func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500878 n.Lock()
879 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400880 if n.EventBus == nil {
881 n.EventBus = NewEventBus()
882 }
883 return n.EventBus
884}
885
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500886func (n *node) SetProxy(proxy *Proxy) {
887 n.Lock()
888 defer n.Unlock()
889 n.Proxy = proxy
890}
891
892func (n *node) GetProxy() *Proxy {
893 n.Lock()
894 defer n.Unlock()
895 return n.Proxy
896}
897
898func (n *node) GetBranch(key string) *Branch {
899 n.Lock()
900 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500901
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500902 if n.Branches != nil {
903 if branch, exists := n.Branches[key]; exists {
904 return branch
905 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500906 }
907 return nil
908}
909
910func (n *node) SetBranch(key string, branch *Branch) {
911 n.Lock()
912 defer n.Unlock()
913 n.Branches[key] = branch
914}
915
916func (n *node) GetRoot() *root {
917 n.Lock()
918 defer n.Unlock()
919 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400920}