blob: 7bfdca06753f85905bcb1815fd2b407c5a5ae08d [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 Barbarie260a5632019-02-26 16:12:49 -0500117 n.Lock()
118 defer n.Unlock()
119
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400120 // Keep a reference to the current revision
121 var previous string
122 if branch.GetLatest() != nil {
123 previous = branch.GetLatest().GetHash()
124 }
125
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500126 branch.AddRevision(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400127
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400128 // If anything is new, then set the revision as the latest
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500129 if branch.GetLatest() == nil || revision.GetHash() != branch.GetLatest().GetHash() {
130 branch.SetLatest(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400131 }
132
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400133 // Delete the previous revision if anything has changed
134 if previous != "" && previous != branch.GetLatest().GetHash() {
135 branch.DeleteRevision(previous)
136 }
137
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400138 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbarie260a5632019-02-26 16:12:49 -0500139 if n.Proxy != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400140 for _, change := range changeAnnouncement {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400141 log.Debugw("adding-callback",
142 log.Fields{
143 "callbacks": n.Proxy.getCallbacks(change.Type),
144 "type": change.Type,
145 "previousData": change.PreviousData,
146 "latestData": change.LatestData,
147 })
Stephane Barbarie260a5632019-02-26 16:12:49 -0500148 n.Root.AddCallback(
149 n.Proxy.InvokeCallbacks,
Stephane Barbarie126101e2018-10-11 16:18:48 -0400150 change.Type,
151 true,
152 change.PreviousData,
153 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400154 }
155 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400156 }
157}
158
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500159// Latest returns the latest revision of node with or without the transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400160func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400161 var branch *Branch
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400162
163 if len(txid) > 0 && txid[0] != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500164 if branch = n.GetBranch(txid[0]); branch != nil {
165 return branch.GetLatest()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400166 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500167 } else if branch = n.GetBranch(NONE); branch != nil {
168 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400169 }
170 return nil
171}
172
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500173// initialize prepares the content of a node along with its possible ramifications
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400174func (n *node) initialize(data interface{}, txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500175 n.Lock()
176 children := make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400177 for fieldName, field := range ChildrenFields(n.Type) {
178 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400179
180 if fieldValue.IsValid() {
181 if field.IsContainer {
182 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400183 for i := 0; i < fieldValue.Len(); i++ {
184 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400185
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500186 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
187 children[fieldName] = append(children[fieldName], rev)
188 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400189
Stephane Barbarie1e28f3e2019-02-08 15:45:20 -0500190 // TODO: The following logic was ported from v1.0. Need to verify if it is required
191 //var keysSeen []string
192 //_, key := GetAttributeValue(v.Interface(), field.Key, 0)
193 //for _, k := range keysSeen {
194 // if k == key.String() {
195 // //log.Errorf("duplicate key - %s", k)
196 // }
197 //}
198 //keysSeen = append(keysSeen, key.String())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400199 }
200
201 } else {
202 for i := 0; i < fieldValue.Len(); i++ {
203 v := fieldValue.Index(i)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500204 if newNodeRev := n.MakeNode(v.Interface(), txid).Latest(); newNodeRev != nil {
205 children[fieldName] = append(children[fieldName], newNodeRev)
206 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400207 }
208 }
209 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500210 if newNodeRev := n.MakeNode(fieldValue.Interface(), txid).Latest(); newNodeRev != nil {
211 children[fieldName] = append(children[fieldName], newNodeRev)
212 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400213 }
214 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400215 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400216 }
217 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500218 n.Unlock()
219
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400220 branch := NewBranch(n, "", nil, n.AutoPrune)
221 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400222 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400223
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400224 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500225 n.SetBranch(NONE, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400226 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500227 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400228 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400229}
230
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500231// findRevByKey retrieves a specific revision from a node tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400232func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500233 n.Lock()
234 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500235
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400236 for i, rev := range revs {
237 dataValue := reflect.ValueOf(rev.GetData())
238 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
239
240 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
241
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400242 a := fmt.Sprintf("%s", fieldValue.Interface())
243 b := fmt.Sprintf("%s", value)
244 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500245 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400246 }
247 }
248
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400249 return -1, nil
250}
251
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500252// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarieaa467942019-02-06 14:09:44 -0500253func (n *node) List(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500254 log.Debugw("node-list-request", log.Fields{"path": path, "hash": hash, "depth": depth, "deep": deep, "txid": txid})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500255 if deep {
256 depth = -1
257 }
258
259 for strings.HasPrefix(path, "/") {
260 path = path[1:]
261 }
262
263 var branch *Branch
264 var rev Revision
265
266 if branch = n.GetBranch(txid); txid == "" || branch == nil {
267 branch = n.GetBranch(NONE)
268 }
269
270 if hash != "" {
271 rev = branch.GetRevision(hash)
272 } else {
273 rev = branch.GetLatest()
274 }
275
276 var result interface{}
277 var prList []interface{}
278 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
279 for _, revEntry := range pr {
280 prList = append(prList, revEntry.GetData())
281 }
282 result = prList
283 }
284
285 return result
286}
287
288// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie260a5632019-02-26 16:12:49 -0500289func (n *node) Get(path string, hash string, depth int, reconcile bool, txid string) interface{} {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400290 log.Debugw("node-get-request", log.Fields{"path": path, "hash": hash, "depth": depth, "reconcile": reconcile, "txid": txid})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400291 for strings.HasPrefix(path, "/") {
292 path = path[1:]
293 }
294
295 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400296 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400297
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500298 if branch = n.GetBranch(txid); txid == "" || branch == nil {
299 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400300 }
301
302 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500303 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400304 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500305 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400306 }
307
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500308 var result interface{}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500309
310 // If there is not request to reconcile, try to get it from memory
311 if !reconcile {
Kent Hagerman0ab4cb22019-04-24 13:13:35 -0400312 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 -0500313 return result
314 }
315 }
316
317 // If we got to this point, we are either trying to reconcile with the db or
318 // or we simply failed at getting information from memory
319 if n.Root.KvStore != nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500320 var prList []interface{}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500321 if pr := rev.LoadFromPersistence(path, txid); pr != nil && len(pr) > 0 {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500322 // Did we receive a single or multiple revisions?
323 if len(pr) > 1 {
324 for _, revEntry := range pr {
325 prList = append(prList, revEntry.GetData())
326 }
327 result = prList
328 } else {
329 result = pr[0].GetData()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500330 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500331 }
332 }
333
334 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400335}
336
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500337// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400338func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400339 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400340 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400341 }
342
343 partition := strings.SplitN(path, "/", 2)
344 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400345
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400346 if len(partition) < 2 {
347 path = ""
348 } else {
349 path = partition[1]
350 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400351
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400352 names := ChildrenFields(n.Type)
353 field := names[name]
354
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500355 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500356 children := make([]Revision, len(rev.GetChildren(name)))
357 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500358
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400359 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 if path != "" {
361 partition = strings.SplitN(path, "/", 2)
362 key := partition[0]
363 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400364 keyValue := field.KeyFromStr(key)
365 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400366 return nil
367 } else {
368 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400369 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400370 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400371 } else {
372 var response []interface{}
373 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400374 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400375 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400376 response = append(response, value)
377 }
378 return response
379 }
380 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400381 var response []interface{}
382 if path != "" {
383 // TODO: raise error
384 return response
385 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500386 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400387 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400388 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400389 response = append(response, value)
390 }
391 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400392 }
393 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500394
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500395 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500396 childNode := childRev.GetNode()
397 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400398}
399
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500400// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400401func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500402 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400403 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400404
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500405 if n.GetProxy() != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500406 log.Debugw("invoking-get-callbacks", log.Fields{"data": msg})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500407 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400408 msg = modifiedMsg
409 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400410
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400411 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500412
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400413 return msg
414}
415
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500416// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400417func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500418 log.Debugw("node-update-request", log.Fields{"path": path, "strict": strict, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500419
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400420 for strings.HasPrefix(path, "/") {
421 path = path[1:]
422 }
423
424 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400425 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500426 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500427 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400428 branch = makeBranch(n)
429 }
430
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500431 if branch.GetLatest() != nil {
432 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
433 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400434 if path == "" {
435 return n.doUpdate(branch, data, strict)
436 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400437
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500438 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439
440 partition := strings.SplitN(path, "/", 2)
441 name := partition[0]
442
443 if len(partition) < 2 {
444 path = ""
445 } else {
446 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400447 }
448
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400449 field := ChildrenFields(n.Type)[name]
450 var children []Revision
451
Stephane Barbarieaa467942019-02-06 14:09:44 -0500452 if field == nil {
453 return n.doUpdate(branch, data, strict)
454 }
455
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400456 if field.IsContainer {
457 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400458 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400459 } else if field.Key != "" {
460 partition := strings.SplitN(path, "/", 2)
461 key := partition[0]
462 if len(partition) < 2 {
463 path = ""
464 } else {
465 path = partition[1]
466 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400467 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500468
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500469 children = make([]Revision, len(rev.GetChildren(name)))
470 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500471
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400472 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400473
474 if childRev == nil {
475 return branch.GetLatest()
476 }
477
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400478 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400479
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500480 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500481 // only assign in cases of non sub-folder proxies, i.e. "/"
482 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500483 childNode.Proxy = n.Proxy
484 }
485
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400486 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400487
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400488 if newChildRev.GetHash() == childRev.GetHash() {
489 if newChildRev != childRev {
490 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
491 newChildRev.ClearHash()
492 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500493 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400494 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400495
496 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500497
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400498 _newKeyType := fmt.Sprintf("%s", newKey)
499 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500500
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400501 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400502 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400503 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500504
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500505 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400506 newChildRev.SetName(name + "/" + _keyValueType)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400507
508 if idx >= 0 {
509 children[idx] = newChildRev
510 } else {
511 children = append(children, newChildRev)
512 }
513
514 branch.LatestLock.Lock()
515 defer branch.LatestLock.Unlock()
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500516
517 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500518
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500519 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400520 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500521
Stephane Barbariea188d942018-10-16 16:43:04 -0400522 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500523
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400524 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400525 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400526 }
527 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500528 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400529 childNode := childRev.GetNode()
530 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400531
532 branch.LatestLock.Lock()
533 defer branch.LatestLock.Unlock()
534
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500535 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500536 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500537
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400538 updatedRev.ChildDrop(name, childRev.GetHash())
539
Stephane Barbariea188d942018-10-16 16:43:04 -0400540 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400541 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500542
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400543 return nil
544}
545
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400546func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500547 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
548 reflect.TypeOf(data),
549 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400550
551 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
552 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400553 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400554 return nil
555 }
556
557 // TODO: validate that this actually works
558 //if n.hasChildren(data) {
559 // return nil
560 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400561
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500562 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400563 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400565 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500566
567 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400568 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400569 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400570 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400571 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500572
573 rev := branch.GetLatest().UpdateData(data, branch)
574 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500575 n.makeLatest(branch, rev, changes)
576
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400577 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400578 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500579 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400580}
581
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500582// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400583func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500584 log.Debugw("node-add-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500585
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400586 for strings.HasPrefix(path, "/") {
587 path = path[1:]
588 }
589 if path == "" {
590 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400591 log.Errorf("cannot add for non-container mode")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500592 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400593 }
594
595 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400596 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500597 branch = n.GetBranch(NONE)
598 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400599 branch = makeBranch(n)
600 }
601
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500602 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400603
604 partition := strings.SplitN(path, "/", 2)
605 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400606
607 if len(partition) < 2 {
608 path = ""
609 } else {
610 path = partition[1]
611 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400612
613 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500614
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400615 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400616
617 if field.IsContainer {
618 if path == "" {
619 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500620 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400621 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500622 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400623 }
624
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500625 children = make([]Revision, len(rev.GetChildren(name)))
626 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500627
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400628 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500629
Stephane Barbarie126101e2018-10-11 16:18:48 -0400630 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400631 // TODO raise error
Stephane Barbarie260a5632019-02-26 16:12:49 -0500632 log.Warnw("duplicate-key-found", log.Fields{"key": key.String()})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500633 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400634 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500635 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500636
637 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400638 childRev.SetName(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500639
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400640 branch.LatestLock.Lock()
641 defer branch.LatestLock.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500642
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500643 children = append(children, childRev)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400644
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400645 updatedRev := rev.UpdateChildren(name, children, branch)
646 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
647 childRev.SetupWatch(childRev.GetName())
648
649 n.makeLatest(branch, updatedRev, changes)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500650
651 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400652 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500653 log.Errorf("cannot add to non-keyed container")
654
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400655 } else if field.Key != "" {
656 partition := strings.SplitN(path, "/", 2)
657 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400658 if len(partition) < 2 {
659 path = ""
660 } else {
661 path = partition[1]
662 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400663 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500664
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500665 children = make([]Revision, len(rev.GetChildren(name)))
666 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500667
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400668 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500669
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400670 if childRev == nil {
671 return branch.GetLatest()
672 }
673
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400674 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400675 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500676
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500677 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400678 childRev.SetName(name + "/" + keyValue.(string))
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500679
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400680 if idx >= 0 {
681 children[idx] = newChildRev
682 } else {
683 children = append(children, newChildRev)
684 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500685
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400686 branch.LatestLock.Lock()
687 defer branch.LatestLock.Unlock()
688
689 updatedRev := rev.UpdateChildren(name, children, branch)
690 n.makeLatest(branch, updatedRev, nil)
691
692 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500693
694 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400695 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400696 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400697 }
698 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400699 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400700 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500701
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400702 return nil
703}
704
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500705// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400706func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500707 log.Debugw("node-remove-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500708
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400709 for strings.HasPrefix(path, "/") {
710 path = path[1:]
711 }
712 if path == "" {
713 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400714 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400715 }
716 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400717 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500718 branch = n.GetBranch(NONE)
719 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400720 branch = makeBranch(n)
721 }
722
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500723 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400724
725 partition := strings.SplitN(path, "/", 2)
726 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400727 if len(partition) < 2 {
728 path = ""
729 } else {
730 path = partition[1]
731 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400732
733 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400734 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400735 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400736
737 if field.IsContainer {
738 if path == "" {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500739 log.Errorw("cannot-remove-without-key", log.Fields{"name": name, "key": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400740 } else if field.Key != "" {
741 partition := strings.SplitN(path, "/", 2)
742 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400743 if len(partition) < 2 {
744 path = ""
745 } else {
746 path = partition[1]
747 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500748
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400749 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500750 children = make([]Revision, len(rev.GetChildren(name)))
751 copy(children, rev.GetChildren(name))
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500752
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400753 if path != "" {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400754 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
755 childNode := childRev.GetNode()
756 if childNode.Proxy == nil {
757 childNode.Proxy = n.Proxy
758 }
759 newChildRev := childNode.Remove(path, txid, makeBranch)
760
761 if idx >= 0 {
762 children[idx] = newChildRev
763 } else {
764 children = append(children, newChildRev)
765 }
766
767 branch.LatestLock.Lock()
768 defer branch.LatestLock.Unlock()
769
770 rev.SetChildren(name, children)
771 branch.GetLatest().Drop(txid, false)
772 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500773 }
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400774 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400775 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500776
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400777 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil && idx >= 0 {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500778 if n.GetProxy() != nil {
779 data := childRev.GetData()
780 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
781 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
782 } else {
783 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
784 }
785
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400786 childRev.StorageDrop(txid, true)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400787
788 branch.LatestLock.Lock()
789 defer branch.LatestLock.Unlock()
790
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500791 children = append(children[:idx], children[idx+1:]...)
792 rev.SetChildren(name, children)
793
794 branch.GetLatest().Drop(txid, false)
795 n.makeLatest(branch, rev, postAnnouncement)
796
797 return rev
798 } else {
799 log.Errorw("failed-to-find-revision", log.Fields{"name": name, "key": keyValue.(string)})
800 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400801 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500802 log.Errorw("cannot-add-to-non-keyed-container", log.Fields{"name": name, "path": path, "fieldKey": field.Key})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500803
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400804 } else {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500805 log.Errorw("cannot-add-to-non-container-field", log.Fields{"name": name, "path": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400806 }
807
808 return nil
809}
810
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400811// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
812
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500813// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400814type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400815
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500816// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400817func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500818 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400819 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500820 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400821 return branch
822}
823
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500824// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400825func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500826 n.Lock()
827 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400828 delete(n.Branches, txid)
829}
830
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400831func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400832 f := func(rev Revision) Revision {
833 childBranch := rev.GetBranch()
834
835 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400836 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400837 }
838
839 return rev
840 }
841 return f
842}
843
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500844// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400845func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500846 srcBranch := n.GetBranch(txid)
847 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400848
849 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500850 srcRev := srcBranch.GetLatest()
851 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400852
853 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
854
855 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500856 if rev != nil {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400857 rev.SetName(dstRev.GetName())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500858 n.makeLatest(dstBranch, rev, changes)
859 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500860 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400861 }
862
Stephane Barbariee16186c2018-09-11 10:46:34 -0400863 // TODO: return proper error when one occurs
864 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400865}
866
867// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
868
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400869//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400870// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500871// rev1 := branch.GetHash(hash1)
872// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400873//
874// if rev1.GetHash() == rev2.GetHash() {
875// // empty patch
876// } else {
877// // translate data to json and generate patch
878// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
879// patch.
880// }
881//}
882
883// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
884
885// TODO: is tag mgmt used in the python implementation? Need to validate
886
887// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
888
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400889func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400890 for fieldName, field := range ChildrenFields(n.Type) {
891 _, fieldValue := GetAttributeValue(data, fieldName, 0)
892
893 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
894 log.Error("cannot update external children")
895 return true
896 }
897 }
898
899 return false
900}
901
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400902// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400903
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500904// CreateProxy returns a reference to a sub-tree of the data model
905func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500906 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400907}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500908
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500909func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400910 for strings.HasPrefix(path, "/") {
911 path = path[1:]
912 }
913 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500914 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400915 }
916
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500917 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400918 partition := strings.SplitN(path, "/", 2)
919 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400920 if len(partition) < 2 {
921 path = ""
922 } else {
923 path = partition[1]
924 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400925
926 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500927 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400928 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500929 //log.Error("cannot proxy a container field")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500930 newNode := n.MakeNode(reflect.New(field.ClassType.Elem()).Interface(), "")
931 return newNode.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400932 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400933 partition := strings.SplitN(path, "/", 2)
934 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400935 if len(partition) < 2 {
936 path = ""
937 } else {
938 path = partition[1]
939 }
940 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400941 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500942 children = make([]Revision, len(rev.GetChildren(name)))
943 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500944 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
945 childNode := childRev.GetNode()
946 return childNode.createProxy(path, fullPath, n, exclusive)
947 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400948 } else {
949 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400950 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400951 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500952 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400953 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500954 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400955 }
956
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500957 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400958 return nil
959}
960
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500961func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500962 n.Lock()
963 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400964 r := &root{
965 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500966 Callbacks: n.Root.GetCallbacks(),
967 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400968 DirtyNodes: n.Root.DirtyNodes,
969 KvStore: n.Root.KvStore,
970 Loading: n.Root.Loading,
971 RevisionClass: n.Root.RevisionClass,
972 }
973
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400974 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500975 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400976 } else {
977 if n.Proxy.Exclusive {
978 log.Error("node is already owned exclusively")
979 }
980 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500981
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400982 return n.Proxy
983}
984
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400985func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500986 n.Lock()
987 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400988 if n.EventBus == nil {
989 n.EventBus = NewEventBus()
990 }
991 return n.EventBus
992}
993
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500994func (n *node) SetProxy(proxy *Proxy) {
995 n.Lock()
996 defer n.Unlock()
997 n.Proxy = proxy
998}
999
1000func (n *node) GetProxy() *Proxy {
1001 n.Lock()
1002 defer n.Unlock()
1003 return n.Proxy
1004}
1005
1006func (n *node) GetBranch(key string) *Branch {
1007 n.Lock()
1008 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -05001009
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001010 if n.Branches != nil {
1011 if branch, exists := n.Branches[key]; exists {
1012 return branch
1013 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -05001014 }
1015 return nil
1016}
1017
1018func (n *node) SetBranch(key string, branch *Branch) {
1019 n.Lock()
1020 defer n.Unlock()
1021 n.Branches[key] = branch
1022}
1023
1024func (n *node) GetRoot() *root {
1025 n.Lock()
1026 defer n.Unlock()
1027 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -04001028}