blob: 9ec5ce9ba54f672c13f6af6aa3ed63ae8f590731 [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"
27 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050028 "sync"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040029)
30
Stephane Barbariedc5022d2018-11-19 15:21:44 -050031// When a branch has no transaction id, everything gets stored in NONE
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040032const (
33 NONE string = "none"
34)
35
Stephane Barbariedc5022d2018-11-19 15:21:44 -050036// Node interface is an abstraction of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040037type Node interface {
38 MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
39
40 // CRUD functions
41 Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
42 Get(path string, hash string, depth int, deep bool, txid string) interface{}
43 Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
44 Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
45
46 MakeBranch(txid string) *Branch
47 DeleteBranch(txid string)
48 MergeBranch(txid string, dryRun bool) (Revision, error)
49
50 MakeTxBranch() string
51 DeleteTxBranch(txid string)
52 FoldTxBranch(txid string)
53
Stephane Barbariedc5022d2018-11-19 15:21:44 -050054 CreateProxy(path string, exclusive bool) *Proxy
55 GetProxy() *Proxy
Stephane Barbarie06c4a742018-10-01 11:09:32 -040056}
57
58type node struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050059 sync.RWMutex
Stephane Barbarie126101e2018-10-11 16:18:48 -040060 Root *root
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040061 Type interface{}
62 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040063 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040064 Proxy *Proxy
65 EventBus *EventBus
66 AutoPrune bool
67}
68
Stephane Barbariedc5022d2018-11-19 15:21:44 -050069// ChangeTuple holds details of modifications made to a revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -040070type ChangeTuple struct {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040071 Type CallbackType
72 PreviousData interface{}
73 LatestData interface{}
Stephane Barbarie694e2b92018-09-07 12:17:36 -040074}
75
Stephane Barbariedc5022d2018-11-19 15:21:44 -050076// NewNode creates a new instance of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040077func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
78 n := &node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040079
Stephane Barbarie126101e2018-10-11 16:18:48 -040080 n.Root = root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040081 n.Branches = make(map[string]*Branch)
82 n.Tags = make(map[string]Revision)
83 n.Proxy = nil
84 n.EventBus = nil
85 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040086
87 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040088 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040089 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040090 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040091 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050092 // FIXME: this block does not reflect the original implementation
93 // it should be checking if the provided initial_data is already a type!??!
94 // it should be checked before IsProtoMessage
Stephane Barbarieec0919b2018-09-05 14:14:29 -040095 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040096 } else {
97 // not implemented error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040098 log.Errorf("cannot process initial data - %+v", initialData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099 }
100
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400101 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400102}
103
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500104// MakeNode creates a new node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400105func (n *node) MakeNode(data interface{}, txid string) *node {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400106 return NewNode(n.Root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400107}
108
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500109// MakeRevision create a new revision of the node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400110func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500111 return n.GetRoot().MakeRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400112}
113
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500114// makeLatest will mark the revision of a node as being the latest
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400115func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500116 n.Lock()
117 defer n.Unlock()
118
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400119 // Keep a reference to the current revision
120 var previous string
121 if branch.GetLatest() != nil {
122 previous = branch.GetLatest().GetHash()
123 }
124
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500125 branch.AddRevision(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400126
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400127 // If anything is new, then set the revision as the latest
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500128 if branch.GetLatest() == nil || revision.GetHash() != branch.GetLatest().GetHash() {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400129 if revision.GetName() != "" {
130 GetRevCache().Cache.Store(revision.GetName(), revision)
131 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500132 branch.SetLatest(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400133 }
134
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400135 // Delete the previous revision if anything has changed
136 if previous != "" && previous != branch.GetLatest().GetHash() {
137 branch.DeleteRevision(previous)
138 }
139
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400140 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500141 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400142 for _, change := range changeAnnouncement {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400143 log.Debugw("adding-callback",
144 log.Fields{
145 "callbacks": n.Proxy.getCallbacks(change.Type),
146 "type": change.Type,
147 "previousData": change.PreviousData,
148 "latestData": change.LatestData,
149 })
Stephane Barbarie260a5632019-02-26 16:12:49 -0500150 n.Root.AddCallback(
151 n.Proxy.InvokeCallbacks,
Stephane Barbarie126101e2018-10-11 16:18:48 -0400152 change.Type,
153 true,
154 change.PreviousData,
155 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400156 }
157 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400158 }
159}
160
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500161// Latest returns the latest revision of node with or without the transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400162func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400163 var branch *Branch
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400164
165 if len(txid) > 0 && txid[0] != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500166 if branch = n.GetBranch(txid[0]); branch != nil {
167 return branch.GetLatest()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400168 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500169 } else if branch = n.GetBranch(NONE); branch != nil {
170 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400171 }
172 return nil
173}
174
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500175// initialize prepares the content of a node along with its possible ramifications
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400176func (n *node) initialize(data interface{}, txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500177 n.Lock()
178 children := make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400179 for fieldName, field := range ChildrenFields(n.Type) {
180 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400181
182 if fieldValue.IsValid() {
183 if field.IsContainer {
184 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400185 for i := 0; i < fieldValue.Len(); i++ {
186 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400187
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500188 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
189 children[fieldName] = append(children[fieldName], rev)
190 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400191
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500192 // TODO: The following logic was ported from v1.0. Need to verify if it is required
193 //var keysSeen []string
194 //_, key := GetAttributeValue(v.Interface(), field.Key, 0)
195 //for _, k := range keysSeen {
196 // if k == key.String() {
197 // //log.Errorf("duplicate key - %s", k)
198 // }
199 //}
200 //keysSeen = append(keysSeen, key.String())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400201 }
202
203 } else {
204 for i := 0; i < fieldValue.Len(); i++ {
205 v := fieldValue.Index(i)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500206 if newNodeRev := n.MakeNode(v.Interface(), txid).Latest(); newNodeRev != nil {
207 children[fieldName] = append(children[fieldName], newNodeRev)
208 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400209 }
210 }
211 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500212 if newNodeRev := n.MakeNode(fieldValue.Interface(), txid).Latest(); newNodeRev != nil {
213 children[fieldName] = append(children[fieldName], newNodeRev)
214 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400215 }
216 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400217 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400218 }
219 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500220 n.Unlock()
221
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400222 branch := NewBranch(n, "", nil, n.AutoPrune)
223 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400224 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400225
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400226 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500227 n.SetBranch(NONE, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400228 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500229 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400230 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400231}
232
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500233// findRevByKey retrieves a specific revision from a node tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400234func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500235 n.Lock()
236 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500237
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400238 for i, rev := range revs {
239 dataValue := reflect.ValueOf(rev.GetData())
240 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
241
242 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
243
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400244 a := fmt.Sprintf("%s", fieldValue.Interface())
245 b := fmt.Sprintf("%s", value)
246 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500247 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400248 }
249 }
250
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400251 return -1, nil
252}
253
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500254// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarieaa467942019-02-06 14:09:44 -0500255func (n *node) List(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500256 log.Debugw("node-list-request", log.Fields{"path": path, "hash": hash, "depth": depth, "deep": deep, "txid": txid})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500257 if deep {
258 depth = -1
259 }
260
261 for strings.HasPrefix(path, "/") {
262 path = path[1:]
263 }
264
265 var branch *Branch
266 var rev Revision
267
268 if branch = n.GetBranch(txid); txid == "" || branch == nil {
269 branch = n.GetBranch(NONE)
270 }
271
272 if hash != "" {
273 rev = branch.GetRevision(hash)
274 } else {
275 rev = branch.GetLatest()
276 }
277
278 var result interface{}
279 var prList []interface{}
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400280 if pr := rev.LoadFromPersistence(path, txid, nil); pr != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500281 for _, revEntry := range pr {
282 prList = append(prList, revEntry.GetData())
283 }
284 result = prList
285 }
286
287 return result
288}
289
290// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie260a5632019-02-26 16:12:49 -0500291func (n *node) Get(path string, hash string, depth int, reconcile bool, txid string) interface{} {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400292 log.Debugw("node-get-request", log.Fields{"path": path, "hash": hash, "depth": depth, "reconcile": reconcile, "txid": txid})
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400293
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400294 for strings.HasPrefix(path, "/") {
295 path = path[1:]
296 }
297
298 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400299 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400300
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500301 if branch = n.GetBranch(txid); txid == "" || branch == nil {
302 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400303 }
304
305 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500306 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400307 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500308 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400309 }
310
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500311 var result interface{}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500312
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400313 // If there is no request to reconcile, try to get it from memory
Stephane Barbarie260a5632019-02-26 16:12:49 -0500314 if !reconcile {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400315 // Try to find an entry matching the path value from one of these sources
316 // 1. Start with the cache which stores revisions by watch names
317 // 2. Then look in the revision tree, especially if it's a sub-path such as /devices/1234/flows
318 // 3. As a last effort, move on to the KV store
319 if entry, exists := GetRevCache().Cache.Load(path); exists && entry.(Revision) != nil {
320 return proto.Clone(entry.(Revision).GetData().(proto.Message))
321 } else if result = n.getPath(rev.GetBranch().GetLatest(), path, depth); result != nil && reflect.ValueOf(result).IsValid() && !reflect.ValueOf(result).IsNil() {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500322 return result
323 }
324 }
325
326 // If we got to this point, we are either trying to reconcile with the db or
327 // or we simply failed at getting information from memory
328 if n.Root.KvStore != nil {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400329 if pr := rev.LoadFromPersistence(path, txid, nil); pr != nil && len(pr) > 0 {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500330 // Did we receive a single or multiple revisions?
331 if len(pr) > 1 {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400332 var revs []interface{}
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500333 for _, revEntry := range pr {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400334 revs = append(revs, revEntry.GetData())
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500335 }
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400336 result = revs
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500337 } else {
338 result = pr[0].GetData()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500339 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500340 }
341 }
342
343 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400344}
345
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400346//getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400347func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400348 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400349 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400350 }
351
352 partition := strings.SplitN(path, "/", 2)
353 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400354
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400355 if len(partition) < 2 {
356 path = ""
357 } else {
358 path = partition[1]
359 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400361 names := ChildrenFields(n.Type)
362 field := names[name]
363
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500364 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500365 children := make([]Revision, len(rev.GetChildren(name)))
366 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500367
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400368 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400369 if path != "" {
370 partition = strings.SplitN(path, "/", 2)
371 key := partition[0]
372 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400373 keyValue := field.KeyFromStr(key)
374 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400375 return nil
376 } else {
377 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400378 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400379 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400380 } else {
381 var response []interface{}
382 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400383 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400384 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400385 response = append(response, value)
386 }
387 return response
388 }
389 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400390 var response []interface{}
391 if path != "" {
392 // TODO: raise error
393 return response
394 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500395 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400396 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400397 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400398 response = append(response, value)
399 }
400 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400401 }
402 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500403
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500404 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500405 childNode := childRev.GetNode()
406 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400407}
408
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500409// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400410func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500411 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400412 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400413
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500414 if n.GetProxy() != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500415 log.Debugw("invoking-get-callbacks", log.Fields{"data": msg})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500416 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400417 msg = modifiedMsg
418 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400419
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400420 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500421
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400422 return msg
423}
424
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500425// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400426func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500427 log.Debugw("node-update-request", log.Fields{"path": path, "strict": strict, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500428
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400429 for strings.HasPrefix(path, "/") {
430 path = path[1:]
431 }
432
433 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400434 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500435 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500436 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400437 branch = makeBranch(n)
438 }
439
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500440 if branch.GetLatest() != nil {
441 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
442 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400443 if path == "" {
444 return n.doUpdate(branch, data, strict)
445 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400446
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500447 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400448
449 partition := strings.SplitN(path, "/", 2)
450 name := partition[0]
451
452 if len(partition) < 2 {
453 path = ""
454 } else {
455 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400456 }
457
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400458 field := ChildrenFields(n.Type)[name]
459 var children []Revision
460
Stephane Barbarieaa467942019-02-06 14:09:44 -0500461 if field == nil {
462 return n.doUpdate(branch, data, strict)
463 }
464
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400465 if field.IsContainer {
466 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400467 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400468 } else if field.Key != "" {
469 partition := strings.SplitN(path, "/", 2)
470 key := partition[0]
471 if len(partition) < 2 {
472 path = ""
473 } else {
474 path = partition[1]
475 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400476 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500477
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500478 children = make([]Revision, len(rev.GetChildren(name)))
479 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500480
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400481 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400482
483 if childRev == nil {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400484 log.Debugw("child-revision-is-nil", log.Fields{"key": keyValue})
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400485 return branch.GetLatest()
486 }
487
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400488 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400489
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500490 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500491 // only assign in cases of non sub-folder proxies, i.e. "/"
492 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500493 childNode.Proxy = n.Proxy
494 }
495
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400496 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400497
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400498 if newChildRev.GetHash() == childRev.GetHash() {
499 if newChildRev != childRev {
500 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
501 newChildRev.ClearHash()
502 }
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400503 log.Debugw("child-revisions-have-matching-hash", log.Fields{"hash": childRev.GetHash(), "key": keyValue})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500504 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400505 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400506
507 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500508
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400509 _newKeyType := fmt.Sprintf("%s", newKey)
510 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500511
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400512 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400513 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400514 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500515
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500516 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400517 newChildRev.SetName(name + "/" + _keyValueType)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400518
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400519 branch.LatestLock.Lock()
520 defer branch.LatestLock.Unlock()
521
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400522 if idx >= 0 {
523 children[idx] = newChildRev
524 } else {
525 children = append(children, newChildRev)
526 }
527
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500528 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500529
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500530 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400531 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500532
Stephane Barbariea188d942018-10-16 16:43:04 -0400533 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500534
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400535 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400536 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400537 }
538 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500539 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400540 childNode := childRev.GetNode()
541 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400542
543 branch.LatestLock.Lock()
544 defer branch.LatestLock.Unlock()
545
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500546 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500547 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500548
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400549 updatedRev.ChildDrop(name, childRev.GetHash())
550
Stephane Barbariea188d942018-10-16 16:43:04 -0400551 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400552 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500553
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400554 return nil
555}
556
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400557func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400558 log.Debugw("comparing-types", log.Fields{"expected": reflect.ValueOf(n.Type).Type(), "actual": reflect.TypeOf(data)})
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400559
560 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
561 // TODO raise error
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400562 log.Errorw("types-do-not-match: %+v", log.Fields{"actual": reflect.TypeOf(data), "expected": n.Type})
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400563 return nil
564 }
565
566 // TODO: validate that this actually works
567 //if n.hasChildren(data) {
568 // return nil
569 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400570
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500571 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400572 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500573 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400574 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500575
576 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400577 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400578 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400579 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400580 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500581
582 rev := branch.GetLatest().UpdateData(data, branch)
583 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500584 n.makeLatest(branch, rev, changes)
585
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400586 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400587 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500588 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400589}
590
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500591// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400592func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500593 log.Debugw("node-add-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500594
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400595 for strings.HasPrefix(path, "/") {
596 path = path[1:]
597 }
598 if path == "" {
599 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400600 log.Errorf("cannot add for non-container mode")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500601 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400602 }
603
604 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400605 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500606 branch = n.GetBranch(NONE)
607 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400608 branch = makeBranch(n)
609 }
610
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500611 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400612
613 partition := strings.SplitN(path, "/", 2)
614 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400615
616 if len(partition) < 2 {
617 path = ""
618 } else {
619 path = partition[1]
620 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400621
622 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500623
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400624 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400625
626 if field.IsContainer {
627 if path == "" {
628 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500629 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400630 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500631 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400632 }
633
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500634 children = make([]Revision, len(rev.GetChildren(name)))
635 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500636
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400637 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500638
Stephane Barbarie126101e2018-10-11 16:18:48 -0400639 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400640 // TODO raise error
Stephane Barbarie260a5632019-02-26 16:12:49 -0500641 log.Warnw("duplicate-key-found", log.Fields{"key": key.String()})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500642 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400643 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500644 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500645
646 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400647 childRev.SetName(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500648
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400649 branch.LatestLock.Lock()
650 defer branch.LatestLock.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500651
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500652 children = append(children, childRev)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400653
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400654 updatedRev := rev.UpdateChildren(name, children, branch)
655 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400656 childRev.GetNode().SetProxy(n.GetProxy())
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400657 childRev.SetupWatch(childRev.GetName())
658
659 n.makeLatest(branch, updatedRev, changes)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500660
661 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400662 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500663 log.Errorf("cannot add to non-keyed container")
664
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400665 } else if field.Key != "" {
666 partition := strings.SplitN(path, "/", 2)
667 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400668 if len(partition) < 2 {
669 path = ""
670 } else {
671 path = partition[1]
672 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400673 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500674
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500675 children = make([]Revision, len(rev.GetChildren(name)))
676 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500677
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400678 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500679
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400680 if childRev == nil {
681 return branch.GetLatest()
682 }
683
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400684 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400685 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500686
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500687 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400688 newChildRev.SetName(name + "/" + keyValue.(string))
689
690 branch.LatestLock.Lock()
691 defer branch.LatestLock.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500692
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400693 if idx >= 0 {
694 children[idx] = newChildRev
695 } else {
696 children = append(children, newChildRev)
697 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500698
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400699 updatedRev := rev.UpdateChildren(name, children, branch)
700 n.makeLatest(branch, updatedRev, nil)
701
702 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500703
704 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400705 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400706 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400707 }
708 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400709 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400710 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500711
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400712 return nil
713}
714
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500715// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400716func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500717 log.Debugw("node-remove-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500718
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400719 for strings.HasPrefix(path, "/") {
720 path = path[1:]
721 }
722 if path == "" {
723 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400724 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400725 }
726 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400727 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500728 branch = n.GetBranch(NONE)
729 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400730 branch = makeBranch(n)
731 }
732
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500733 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400734
735 partition := strings.SplitN(path, "/", 2)
736 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400737 if len(partition) < 2 {
738 path = ""
739 } else {
740 path = partition[1]
741 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400742
743 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400744 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400745 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400746
747 if field.IsContainer {
748 if path == "" {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500749 log.Errorw("cannot-remove-without-key", log.Fields{"name": name, "key": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400750 } else if field.Key != "" {
751 partition := strings.SplitN(path, "/", 2)
752 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400753 if len(partition) < 2 {
754 path = ""
755 } else {
756 path = partition[1]
757 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500758
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400759 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500760 children = make([]Revision, len(rev.GetChildren(name)))
761 copy(children, rev.GetChildren(name))
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500762
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400763 if path != "" {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400764 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
765 childNode := childRev.GetNode()
766 if childNode.Proxy == nil {
767 childNode.Proxy = n.Proxy
768 }
769 newChildRev := childNode.Remove(path, txid, makeBranch)
770
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400771 branch.LatestLock.Lock()
772 defer branch.LatestLock.Unlock()
773
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400774 if idx >= 0 {
775 children[idx] = newChildRev
776 } else {
777 children = append(children, newChildRev)
778 }
779
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400780 rev.SetChildren(name, children)
781 branch.GetLatest().Drop(txid, false)
782 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500783 }
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400784 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400785 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500786
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400787 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil && idx >= 0 {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500788 if n.GetProxy() != nil {
789 data := childRev.GetData()
790 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
791 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
792 } else {
793 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
794 }
795
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400796 childRev.StorageDrop(txid, true)
Stephane Barbarie7512fc82019-05-07 12:25:46 -0400797 GetRevCache().Cache.Delete(childRev.GetName())
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400798
799 branch.LatestLock.Lock()
800 defer branch.LatestLock.Unlock()
801
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500802 children = append(children[:idx], children[idx+1:]...)
803 rev.SetChildren(name, children)
804
805 branch.GetLatest().Drop(txid, false)
806 n.makeLatest(branch, rev, postAnnouncement)
807
808 return rev
809 } else {
810 log.Errorw("failed-to-find-revision", log.Fields{"name": name, "key": keyValue.(string)})
811 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400812 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500813 log.Errorw("cannot-add-to-non-keyed-container", log.Fields{"name": name, "path": path, "fieldKey": field.Key})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500814
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400815 } else {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500816 log.Errorw("cannot-add-to-non-container-field", log.Fields{"name": name, "path": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400817 }
818
819 return nil
820}
821
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400822// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
823
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500824// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400825type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400826
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500827// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400828func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500829 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400830 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500831 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400832 return branch
833}
834
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500835// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400836func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500837 n.Lock()
838 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400839 delete(n.Branches, txid)
840}
841
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400842func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400843 f := func(rev Revision) Revision {
844 childBranch := rev.GetBranch()
845
846 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400847 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400848 }
849
850 return rev
851 }
852 return f
853}
854
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500855// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400856func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500857 srcBranch := n.GetBranch(txid)
858 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400859
860 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500861 srcRev := srcBranch.GetLatest()
862 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400863
864 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
865
866 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500867 if rev != nil {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400868 rev.SetName(dstRev.GetName())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500869 n.makeLatest(dstBranch, rev, changes)
870 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500871 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400872 }
873
Stephane Barbariee16186c2018-09-11 10:46:34 -0400874 // TODO: return proper error when one occurs
875 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400876}
877
878// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
879
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400880//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400881// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500882// rev1 := branch.GetHash(hash1)
883// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400884//
885// if rev1.GetHash() == rev2.GetHash() {
886// // empty patch
887// } else {
888// // translate data to json and generate patch
889// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
890// patch.
891// }
892//}
893
894// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
895
896// TODO: is tag mgmt used in the python implementation? Need to validate
897
898// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
899
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400900func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400901 for fieldName, field := range ChildrenFields(n.Type) {
902 _, fieldValue := GetAttributeValue(data, fieldName, 0)
903
904 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
905 log.Error("cannot update external children")
906 return true
907 }
908 }
909
910 return false
911}
912
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400913// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400914
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500915// CreateProxy returns a reference to a sub-tree of the data model
916func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500917 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400918}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500919
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500920func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400921 for strings.HasPrefix(path, "/") {
922 path = path[1:]
923 }
924 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500925 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400926 }
927
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500928 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400929 partition := strings.SplitN(path, "/", 2)
930 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400931 if len(partition) < 2 {
932 path = ""
933 } else {
934 path = partition[1]
935 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400936
937 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500938 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400939 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500940 //log.Error("cannot proxy a container field")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500941 newNode := n.MakeNode(reflect.New(field.ClassType.Elem()).Interface(), "")
942 return newNode.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400943 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400944 partition := strings.SplitN(path, "/", 2)
945 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400946 if len(partition) < 2 {
947 path = ""
948 } else {
949 path = partition[1]
950 }
951 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400952 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500953 children = make([]Revision, len(rev.GetChildren(name)))
954 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500955 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
956 childNode := childRev.GetNode()
957 return childNode.createProxy(path, fullPath, n, exclusive)
958 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400959 } else {
960 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400961 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400962 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500963 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400964 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500965 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400966 }
967
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500968 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400969 return nil
970}
971
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500972func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500973 n.Lock()
974 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400975 r := &root{
976 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500977 Callbacks: n.Root.GetCallbacks(),
978 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400979 DirtyNodes: n.Root.DirtyNodes,
980 KvStore: n.Root.KvStore,
981 Loading: n.Root.Loading,
982 RevisionClass: n.Root.RevisionClass,
983 }
984
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400985 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500986 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400987 } else {
988 if n.Proxy.Exclusive {
989 log.Error("node is already owned exclusively")
990 }
991 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500992
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400993 return n.Proxy
994}
995
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400996func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500997 n.Lock()
998 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400999 if n.EventBus == nil {
1000 n.EventBus = NewEventBus()
1001 }
1002 return n.EventBus
1003}
1004
Stephane Barbariedc5022d2018-11-19 15:21:44 -05001005func (n *node) SetProxy(proxy *Proxy) {
1006 n.Lock()
1007 defer n.Unlock()
1008 n.Proxy = proxy
1009}
1010
1011func (n *node) GetProxy() *Proxy {
1012 n.Lock()
1013 defer n.Unlock()
1014 return n.Proxy
1015}
1016
1017func (n *node) GetBranch(key string) *Branch {
1018 n.Lock()
1019 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -05001020
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001021 if n.Branches != nil {
1022 if branch, exists := n.Branches[key]; exists {
1023 return branch
1024 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -05001025 }
1026 return nil
1027}
1028
1029func (n *node) SetBranch(key string, branch *Branch) {
1030 n.Lock()
1031 defer n.Unlock()
1032 n.Branches[key] = branch
1033}
1034
1035func (n *node) GetRoot() *root {
1036 n.Lock()
1037 defer n.Unlock()
1038 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -04001039}