blob: 55b0eb7dc8e4f221e44e3869d5fae36bb937f26a [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 Barbarie126101e2018-10-11 16:18:48 -0400126 log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v",
127 change.Type,
128 change.PreviousData,
129 change.LatestData)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500130 n.GetRoot().AddCallback(
131 n.GetProxy().InvokeCallbacks,
Stephane Barbarie126101e2018-10-11 16:18:48 -0400132 change.Type,
133 true,
134 change.PreviousData,
135 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400136 }
137 }
138
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400139 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400140 log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v",
141 change.Type,
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400142 change.PreviousData,
143 change.LatestData)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500144 n.GetRoot().AddNotificationCallback(
Stephane Barbarie126101e2018-10-11 16:18:48 -0400145 n.makeEventBus().Advertise,
146 change.Type,
147 revision.GetHash(),
148 change.PreviousData,
149 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400150 }
151 }
152}
153
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500154// Latest returns the latest revision of node with or without the transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400155func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400156 var branch *Branch
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400157
158 if len(txid) > 0 && txid[0] != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500159 if branch = n.GetBranch(txid[0]); branch != nil {
160 return branch.GetLatest()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400161 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500162 } else if branch = n.GetBranch(NONE); branch != nil {
163 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400164 }
165 return nil
166}
167
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500168// initialize prepares the content of a node along with its possible ramifications
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400169func (n *node) initialize(data interface{}, txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500170 n.Lock()
171 children := make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400172 for fieldName, field := range ChildrenFields(n.Type) {
173 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400174
175 if fieldValue.IsValid() {
176 if field.IsContainer {
177 if field.Key != "" {
178 var keysSeen []string
179
180 for i := 0; i < fieldValue.Len(); i++ {
181 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400182
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500183 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
184 children[fieldName] = append(children[fieldName], rev)
185 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400186
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400187 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400188 for _, k := range keysSeen {
189 if k == key.String() {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400190 log.Errorf("duplicate key - %s", k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400191 }
192 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400193 keysSeen = append(keysSeen, key.String())
194 }
195
196 } else {
197 for i := 0; i < fieldValue.Len(); i++ {
198 v := fieldValue.Index(i)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500199 if newNodeRev := n.MakeNode(v.Interface(), txid).Latest(); newNodeRev != nil {
200 children[fieldName] = append(children[fieldName], newNodeRev)
201 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400202 }
203 }
204 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500205 if newNodeRev := n.MakeNode(fieldValue.Interface(), txid).Latest(); newNodeRev != nil {
206 children[fieldName] = append(children[fieldName], newNodeRev)
207 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400208 }
209 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400210 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400211 }
212 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500213 n.Unlock()
214
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400215 branch := NewBranch(n, "", nil, n.AutoPrune)
216 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400217 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400218
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400219 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500220 n.SetBranch(NONE, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400221 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500222 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400223 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400224}
225
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500226// findRevByKey retrieves a specific revision from a node tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400227func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500228 n.Lock()
229 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500230
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400231 for i, rev := range revs {
232 dataValue := reflect.ValueOf(rev.GetData())
233 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
234
235 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
236
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400237 a := fmt.Sprintf("%s", fieldValue.Interface())
238 b := fmt.Sprintf("%s", value)
239 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500240 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400241 }
242 }
243
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400244 return -1, nil
245}
246
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500247// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400248func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400249 if deep {
250 depth = -1
251 }
252
253 for strings.HasPrefix(path, "/") {
254 path = path[1:]
255 }
256
257 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400258 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400259
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500260 if branch = n.GetBranch(txid); txid == "" || branch == nil {
261 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400262 }
263
264 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500265 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400266 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500267 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400268 }
269
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500270 var result interface{}
271 if result = n.getPath(rev.GetBranch().GetLatest(), path, depth);
272 reflect.ValueOf(result).IsValid() && reflect.ValueOf(result).IsNil() && n.Root.KvStore != nil {
273 // We got nothing from memory, try to pull it from persistence
274 var prList []interface{}
275 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
276 for _, revEntry := range pr {
277 prList = append(prList, revEntry.GetData())
278 }
279 result = prList
280 }
281 }
282
283 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400284}
285
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500286// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400287func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400288 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400289 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400290 }
291
292 partition := strings.SplitN(path, "/", 2)
293 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400294
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400295 if len(partition) < 2 {
296 path = ""
297 } else {
298 path = partition[1]
299 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400300
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400301 names := ChildrenFields(n.Type)
302 field := names[name]
303
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500304 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500305 children := make([]Revision, len(rev.GetChildren(name)))
306 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500307
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400308 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400309 if path != "" {
310 partition = strings.SplitN(path, "/", 2)
311 key := partition[0]
312 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400313 keyValue := field.KeyFromStr(key)
314 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400315 return nil
316 } else {
317 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400318 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400319 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400320 } else {
321 var response []interface{}
322 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400323 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400324 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400325 response = append(response, value)
326 }
327 return response
328 }
329 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400330 var response []interface{}
331 if path != "" {
332 // TODO: raise error
333 return response
334 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500335 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400336 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400337 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400338 response = append(response, value)
339 }
340 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400341 }
342 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500343
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500344 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500345 childNode := childRev.GetNode()
346 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400347}
348
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500349// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400350func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500351 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400352 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400353
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500354 if n.GetProxy() != nil {
355 log.Debug("invoking proxy GET Callbacks : %+v", msg)
356 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400357 msg = modifiedMsg
358 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400359
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500361
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400362 return msg
363}
364
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500365// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400366func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400367 for strings.HasPrefix(path, "/") {
368 path = path[1:]
369 }
370
371 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400372 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500373 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500374 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400375 branch = makeBranch(n)
376 }
377
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500378 if branch.GetLatest() != nil {
379 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
380 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400381 if path == "" {
382 return n.doUpdate(branch, data, strict)
383 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400384
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500385 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400386
387 partition := strings.SplitN(path, "/", 2)
388 name := partition[0]
389
390 if len(partition) < 2 {
391 path = ""
392 } else {
393 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400394 }
395
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400396 field := ChildrenFields(n.Type)[name]
397 var children []Revision
398
399 if field.IsContainer {
400 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400401 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400402 } else if field.Key != "" {
403 partition := strings.SplitN(path, "/", 2)
404 key := partition[0]
405 if len(partition) < 2 {
406 path = ""
407 } else {
408 path = partition[1]
409 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400410 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500411
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500412 children = make([]Revision, len(rev.GetChildren(name)))
413 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500414
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400415 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400416 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400417
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400418 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400419
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400420 if newChildRev.GetHash() == childRev.GetHash() {
421 if newChildRev != childRev {
422 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
423 newChildRev.ClearHash()
424 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500425 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400426 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400427
428 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500429
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400430 _newKeyType := fmt.Sprintf("%s", newKey)
431 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500432
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400433 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400434 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400435 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500436
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500437 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
438 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500440
441 updatedRev := rev.UpdateChildren(name, children, branch)
442 branch.GetLatest().Drop(txid, false)
443 n.makeLatest(branch, updatedRev, nil)
444
Stephane Barbariea188d942018-10-16 16:43:04 -0400445 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500446
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400447 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400448 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400449 }
450 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500451 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400452 childNode := childRev.GetNode()
453 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500454 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
455 rev.Drop(txid, false)
456 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500457
Stephane Barbariea188d942018-10-16 16:43:04 -0400458 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400459 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500460
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400461 return nil
462}
463
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400464func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500465 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
466 reflect.TypeOf(data),
467 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400468
469 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
470 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400471 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400472 return nil
473 }
474
475 // TODO: validate that this actually works
476 //if n.hasChildren(data) {
477 // return nil
478 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400479
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500480 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400481 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500482 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400483 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500484
485 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400486 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400487 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400488 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400489 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500490
491 rev := branch.GetLatest().UpdateData(data, branch)
492 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400493
494 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
495 // 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 -0500496 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400497
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500498 n.makeLatest(branch, rev, changes)
499
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400500 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400501 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500502
503 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400504}
505
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500506// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400507func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400508 for strings.HasPrefix(path, "/") {
509 path = path[1:]
510 }
511 if path == "" {
512 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400513 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400514 }
515
516 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400517 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500518 branch = n.GetBranch(NONE)
519 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400520 branch = makeBranch(n)
521 }
522
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500523 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400524
525 partition := strings.SplitN(path, "/", 2)
526 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400527
528 if len(partition) < 2 {
529 path = ""
530 } else {
531 path = partition[1]
532 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400533
534 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500535
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400536 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400537
538 if field.IsContainer {
539 if path == "" {
540 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500541 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400542 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500543 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400544 }
545
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500546 children = make([]Revision, len(rev.GetChildren(name)))
547 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500548
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400549 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500550
Stephane Barbarie126101e2018-10-11 16:18:48 -0400551 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400552 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400553 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500554 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400555 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500556 childRev := n.MakeNode(data, txid).Latest(txid)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500557
558 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
559 childRev.SetHash(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500560
561 // Create watch for <component>/<key>
562 childRev.SetupWatch(childRev.GetHash())
563
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564 children = append(children, childRev)
565 rev = rev.UpdateChildren(name, children, branch)
566 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400567
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500568 rev.Drop(txid, false)
569 n.makeLatest(branch, rev, changes)
570
571 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400572 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500573 log.Errorf("cannot add to non-keyed container")
574
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400575 } else if field.Key != "" {
576 partition := strings.SplitN(path, "/", 2)
577 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400578 if len(partition) < 2 {
579 path = ""
580 } else {
581 path = partition[1]
582 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400583 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500584
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500585 children = make([]Revision, len(rev.GetChildren(name)))
586 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500587
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400588 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500589
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400590 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400591 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500592
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400593 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500594
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500595 rev = rev.UpdateChildren(name, branch.GetLatest().GetChildren(name), branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500596 rev.Drop(txid, false)
597 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
598
599 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400600 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400601 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400602 }
603 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400604 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400605 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500606
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400607 return nil
608}
609
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500610// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400611func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400612 for strings.HasPrefix(path, "/") {
613 path = path[1:]
614 }
615 if path == "" {
616 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400617 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400618 }
619 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400620 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500621 branch = n.GetBranch(NONE)
622 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400623 branch = makeBranch(n)
624 }
625
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500626 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400627
628 partition := strings.SplitN(path, "/", 2)
629 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400630 if len(partition) < 2 {
631 path = ""
632 } else {
633 path = partition[1]
634 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400635
636 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400637 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400638 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400639
640 if field.IsContainer {
641 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400642 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400643 } else if field.Key != "" {
644 partition := strings.SplitN(path, "/", 2)
645 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400646 if len(partition) < 2 {
647 path = ""
648 } else {
649 path = partition[1]
650 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400651 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500652 children = make([]Revision, len(rev.GetChildren(name)))
653 copy(children, rev.GetChildren(name))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400654 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400655 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400656 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400657 newChildRev := childNode.Remove(path, txid, makeBranch)
658 children[idx] = newChildRev
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500659 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500660 branch.GetLatest().Drop(txid, false)
661 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400662 return rev
663 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500664 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
665 if n.GetProxy() != nil {
666 data := childRev.GetData()
667 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
668 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
669 } else {
670 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
671 }
672 childRev.Drop(txid, true)
673 children = append(children[:idx], children[idx+1:]...)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500674 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500675 branch.GetLatest().Drop(txid, false)
676 n.makeLatest(branch, rev, postAnnouncement)
677 return rev
678
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400679 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500680 log.Errorf("cannot add to non-keyed container")
681
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400682 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400683 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400684 }
685
686 return nil
687}
688
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400689// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
690
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500691// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400692type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400693
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500694// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400695func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500696 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400697 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500698 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400699 return branch
700}
701
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500702// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400703func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500704 n.Lock()
705 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400706 delete(n.Branches, txid)
707}
708
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400709func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400710 f := func(rev Revision) Revision {
711 childBranch := rev.GetBranch()
712
713 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400714 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400715 }
716
717 return rev
718 }
719 return f
720}
721
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500722// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400723func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500724 srcBranch := n.GetBranch(txid)
725 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400726
727 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500728 srcRev := srcBranch.GetLatest()
729 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400730
731 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
732
733 if !dryRun {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500734 n.makeLatest(dstBranch, rev, changes)
735 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400736 }
737
Stephane Barbariee16186c2018-09-11 10:46:34 -0400738 // TODO: return proper error when one occurs
739 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400740}
741
742// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
743
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400744//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400745// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500746// rev1 := branch.GetHash(hash1)
747// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400748//
749// if rev1.GetHash() == rev2.GetHash() {
750// // empty patch
751// } else {
752// // translate data to json and generate patch
753// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
754// patch.
755// }
756//}
757
758// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
759
760// TODO: is tag mgmt used in the python implementation? Need to validate
761
762// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
763
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400764func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400765 for fieldName, field := range ChildrenFields(n.Type) {
766 _, fieldValue := GetAttributeValue(data, fieldName, 0)
767
768 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
769 log.Error("cannot update external children")
770 return true
771 }
772 }
773
774 return false
775}
776
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400777// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400778
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500779// CreateProxy returns a reference to a sub-tree of the data model
780func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500781 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400782}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500783
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500784func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400785 for strings.HasPrefix(path, "/") {
786 path = path[1:]
787 }
788 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500789 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400790 }
791
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500792 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400793 partition := strings.SplitN(path, "/", 2)
794 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400795 if len(partition) < 2 {
796 path = ""
797 } else {
798 path = partition[1]
799 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400800
801 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500802 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400803 if path == "" {
804 log.Error("cannot proxy a container field")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400805 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400806 partition := strings.SplitN(path, "/", 2)
807 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400808 if len(partition) < 2 {
809 path = ""
810 } else {
811 path = partition[1]
812 }
813 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400814 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500815 children = make([]Revision, len(rev.GetChildren(name)))
816 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500817 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
818 childNode := childRev.GetNode()
819 return childNode.createProxy(path, fullPath, n, exclusive)
820 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400821 } else {
822 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400823 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400824 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500825 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400826 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500827 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400828 }
829
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500830 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400831 return nil
832}
833
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500834func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500835 n.Lock()
836 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400837 r := &root{
838 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500839 Callbacks: n.Root.GetCallbacks(),
840 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400841 DirtyNodes: n.Root.DirtyNodes,
842 KvStore: n.Root.KvStore,
843 Loading: n.Root.Loading,
844 RevisionClass: n.Root.RevisionClass,
845 }
846
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400847 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500848 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400849 } else {
850 if n.Proxy.Exclusive {
851 log.Error("node is already owned exclusively")
852 }
853 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500854
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400855 return n.Proxy
856}
857
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400858func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500859 n.Lock()
860 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400861 if n.EventBus == nil {
862 n.EventBus = NewEventBus()
863 }
864 return n.EventBus
865}
866
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500867func (n *node) SetProxy(proxy *Proxy) {
868 n.Lock()
869 defer n.Unlock()
870 n.Proxy = proxy
871}
872
873func (n *node) GetProxy() *Proxy {
874 n.Lock()
875 defer n.Unlock()
876 return n.Proxy
877}
878
879func (n *node) GetBranch(key string) *Branch {
880 n.Lock()
881 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500882 if n.Branches != nil {
883 if branch, exists := n.Branches[key]; exists {
884 return branch
885 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500886 }
887 return nil
888}
889
890func (n *node) SetBranch(key string, branch *Branch) {
891 n.Lock()
892 defer n.Unlock()
893 n.Branches[key] = branch
894}
895
896func (n *node) GetRoot() *root {
897 n.Lock()
898 defer n.Unlock()
899 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400900}