blob: 3908c4e51f6b3624ec9100641066b259749c29df [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 {
312 if result = n.getPath(rev.GetBranch().GetLatest(), path, depth);
313 result != nil && reflect.ValueOf(result).IsValid() && !reflect.ValueOf(result).IsNil() {
314 return result
315 }
316 }
317
318 // If we got to this point, we are either trying to reconcile with the db or
319 // or we simply failed at getting information from memory
320 if n.Root.KvStore != nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500321 var prList []interface{}
Stephane Barbarie260a5632019-02-26 16:12:49 -0500322 if pr := rev.LoadFromPersistence(path, txid); pr != nil && len(pr) > 0 {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500323 // Did we receive a single or multiple revisions?
324 if len(pr) > 1 {
325 for _, revEntry := range pr {
326 prList = append(prList, revEntry.GetData())
327 }
328 result = prList
329 } else {
330 result = pr[0].GetData()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500331 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500332 }
333 }
334
335 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400336}
337
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500338// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400339func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400340 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400341 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400342 }
343
344 partition := strings.SplitN(path, "/", 2)
345 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400346
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400347 if len(partition) < 2 {
348 path = ""
349 } else {
350 path = partition[1]
351 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400352
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400353 names := ChildrenFields(n.Type)
354 field := names[name]
355
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500356 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500357 children := make([]Revision, len(rev.GetChildren(name)))
358 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500359
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400361 if path != "" {
362 partition = strings.SplitN(path, "/", 2)
363 key := partition[0]
364 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400365 keyValue := field.KeyFromStr(key)
366 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400367 return nil
368 } else {
369 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400370 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400371 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400372 } else {
373 var response []interface{}
374 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400375 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400376 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400377 response = append(response, value)
378 }
379 return response
380 }
381 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400382 var response []interface{}
383 if path != "" {
384 // TODO: raise error
385 return response
386 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500387 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400388 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400389 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400390 response = append(response, value)
391 }
392 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400393 }
394 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500395
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500396 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500397 childNode := childRev.GetNode()
398 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400399}
400
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500401// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400402func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500403 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400404 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400405
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500406 if n.GetProxy() != nil {
Stephane Barbarieaa467942019-02-06 14:09:44 -0500407 log.Debugw("invoking-get-callbacks", log.Fields{"data": msg})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500408 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400409 msg = modifiedMsg
410 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400411
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400412 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500413
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400414 return msg
415}
416
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500417// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400418func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500419 log.Debugw("node-update-request", log.Fields{"path": path, "strict": strict, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500420
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400421 for strings.HasPrefix(path, "/") {
422 path = path[1:]
423 }
424
425 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400426 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500427 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500428 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400429 branch = makeBranch(n)
430 }
431
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500432 if branch.GetLatest() != nil {
433 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
434 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400435 if path == "" {
436 return n.doUpdate(branch, data, strict)
437 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400438
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500439 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400440
441 partition := strings.SplitN(path, "/", 2)
442 name := partition[0]
443
444 if len(partition) < 2 {
445 path = ""
446 } else {
447 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400448 }
449
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400450 field := ChildrenFields(n.Type)[name]
451 var children []Revision
452
Stephane Barbarieaa467942019-02-06 14:09:44 -0500453 if field == nil {
454 return n.doUpdate(branch, data, strict)
455 }
456
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400457 if field.IsContainer {
458 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400459 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400460 } else if field.Key != "" {
461 partition := strings.SplitN(path, "/", 2)
462 key := partition[0]
463 if len(partition) < 2 {
464 path = ""
465 } else {
466 path = partition[1]
467 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400468 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500469
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500470 children = make([]Revision, len(rev.GetChildren(name)))
471 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500472
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400473 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400474
475 if childRev == nil {
476 return branch.GetLatest()
477 }
478
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400479 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400480
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500481 // Save proxy in child node to ensure callbacks are called later on
Stephane Barbaried62ac4e2019-02-05 14:08:38 -0500482 // only assign in cases of non sub-folder proxies, i.e. "/"
483 if childNode.Proxy == nil && n.Proxy != nil && n.Proxy.getFullPath() == "" {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500484 childNode.Proxy = n.Proxy
485 }
486
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400487 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400488
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400489 if newChildRev.GetHash() == childRev.GetHash() {
490 if newChildRev != childRev {
491 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
492 newChildRev.ClearHash()
493 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500494 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400495 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400496
497 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500498
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400499 _newKeyType := fmt.Sprintf("%s", newKey)
500 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500501
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400502 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400503 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400504 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500505
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500506 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400507 newChildRev.SetName(name + "/" + _keyValueType)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400508
509 if idx >= 0 {
510 children[idx] = newChildRev
511 } else {
512 children = append(children, newChildRev)
513 }
514
515 branch.LatestLock.Lock()
516 defer branch.LatestLock.Unlock()
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500517
518 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500519
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500520 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400521 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500522
Stephane Barbariea188d942018-10-16 16:43:04 -0400523 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500524
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400525 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400526 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400527 }
528 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500529 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400530 childNode := childRev.GetNode()
531 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400532
533 branch.LatestLock.Lock()
534 defer branch.LatestLock.Unlock()
535
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500536 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500537 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500538
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400539 updatedRev.ChildDrop(name, childRev.GetHash())
540
Stephane Barbariea188d942018-10-16 16:43:04 -0400541 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400542 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500543
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400544 return nil
545}
546
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400547func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500548 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
549 reflect.TypeOf(data),
550 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400551
552 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
553 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400554 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400555 return nil
556 }
557
558 // TODO: validate that this actually works
559 //if n.hasChildren(data) {
560 // return nil
561 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400562
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500563 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400564 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500565 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400566 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500567
568 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400569 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400570 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400571 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400572 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500573
574 rev := branch.GetLatest().UpdateData(data, branch)
575 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500576 n.makeLatest(branch, rev, changes)
577
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400578 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400579 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500580
581 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400582}
583
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500584// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400585func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500586 log.Debugw("node-add-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500587
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400588 for strings.HasPrefix(path, "/") {
589 path = path[1:]
590 }
591 if path == "" {
592 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400593 log.Errorf("cannot add for non-container mode")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500594 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400595 }
596
597 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400598 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500599 branch = n.GetBranch(NONE)
600 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400601 branch = makeBranch(n)
602 }
603
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500604 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400605
606 partition := strings.SplitN(path, "/", 2)
607 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400608
609 if len(partition) < 2 {
610 path = ""
611 } else {
612 path = partition[1]
613 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400614
615 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500616
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400617 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400618
619 if field.IsContainer {
620 if path == "" {
621 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500622 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400623 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500624 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400625 }
626
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500627 children = make([]Revision, len(rev.GetChildren(name)))
628 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500629
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400630 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500631
Stephane Barbarie126101e2018-10-11 16:18:48 -0400632 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400633 // TODO raise error
Stephane Barbarie260a5632019-02-26 16:12:49 -0500634 log.Warnw("duplicate-key-found", log.Fields{"key": key.String()})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500635 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400636 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500637 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500638
639 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400640 childRev.SetName(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500641
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400642 branch.LatestLock.Lock()
643 defer branch.LatestLock.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500644
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500645 children = append(children, childRev)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400646
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400647 updatedRev := rev.UpdateChildren(name, children, branch)
648 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
649 childRev.SetupWatch(childRev.GetName())
650
651 n.makeLatest(branch, updatedRev, changes)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500652
653 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400654 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500655 log.Errorf("cannot add to non-keyed container")
656
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400657 } else if field.Key != "" {
658 partition := strings.SplitN(path, "/", 2)
659 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400660 if len(partition) < 2 {
661 path = ""
662 } else {
663 path = partition[1]
664 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400665 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500666
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500667 children = make([]Revision, len(rev.GetChildren(name)))
668 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500669
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400670 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500671
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400672 if childRev == nil {
673 return branch.GetLatest()
674 }
675
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400676 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400677 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500678
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500679 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400680 childRev.SetName(name + "/" + keyValue.(string))
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500681
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400682 if idx >= 0 {
683 children[idx] = newChildRev
684 } else {
685 children = append(children, newChildRev)
686 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500687
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400688 branch.LatestLock.Lock()
689 defer branch.LatestLock.Unlock()
690
691 updatedRev := rev.UpdateChildren(name, children, branch)
692 n.makeLatest(branch, updatedRev, nil)
693
694 updatedRev.ChildDrop(name, childRev.GetHash())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500695
696 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400697 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400698 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400699 }
700 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400701 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400702 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500703
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400704 return nil
705}
706
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500707// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400708func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie11b88e72019-02-07 12:28:29 -0500709 log.Debugw("node-remove-request", log.Fields{"path": path, "txid": txid, "makeBranch": makeBranch})
Stephane Barbarieaa467942019-02-06 14:09:44 -0500710
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400711 for strings.HasPrefix(path, "/") {
712 path = path[1:]
713 }
714 if path == "" {
715 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400716 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400717 }
718 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400719 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500720 branch = n.GetBranch(NONE)
721 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400722 branch = makeBranch(n)
723 }
724
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500725 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400726
727 partition := strings.SplitN(path, "/", 2)
728 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400729 if len(partition) < 2 {
730 path = ""
731 } else {
732 path = partition[1]
733 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400734
735 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400736 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400737 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400738
739 if field.IsContainer {
740 if path == "" {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500741 log.Errorw("cannot-remove-without-key", log.Fields{"name": name, "key": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400742 } else if field.Key != "" {
743 partition := strings.SplitN(path, "/", 2)
744 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400745 if len(partition) < 2 {
746 path = ""
747 } else {
748 path = partition[1]
749 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500750
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400751 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500752 children = make([]Revision, len(rev.GetChildren(name)))
753 copy(children, rev.GetChildren(name))
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500754
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400755 if path != "" {
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400756 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
757 childNode := childRev.GetNode()
758 if childNode.Proxy == nil {
759 childNode.Proxy = n.Proxy
760 }
761 newChildRev := childNode.Remove(path, txid, makeBranch)
762
763 if idx >= 0 {
764 children[idx] = newChildRev
765 } else {
766 children = append(children, newChildRev)
767 }
768
769 branch.LatestLock.Lock()
770 defer branch.LatestLock.Unlock()
771
772 rev.SetChildren(name, children)
773 branch.GetLatest().Drop(txid, false)
774 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500775 }
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400776 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400777 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500778
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400779 if idx, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil && idx >= 0 {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500780 if n.GetProxy() != nil {
781 data := childRev.GetData()
782 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
783 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
784 } else {
785 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
786 }
787
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400788 childRev.StorageDrop(txid, true)
Stephane Barbarie40fd3b22019-04-23 21:50:47 -0400789
790 branch.LatestLock.Lock()
791 defer branch.LatestLock.Unlock()
792
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500793 children = append(children[:idx], children[idx+1:]...)
794 rev.SetChildren(name, children)
795
796 branch.GetLatest().Drop(txid, false)
797 n.makeLatest(branch, rev, postAnnouncement)
798
799 return rev
800 } else {
801 log.Errorw("failed-to-find-revision", log.Fields{"name": name, "key": keyValue.(string)})
802 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400803 }
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500804 log.Errorw("cannot-add-to-non-keyed-container", log.Fields{"name": name, "path": path, "fieldKey": field.Key})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500805
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400806 } else {
Stephane Barbarieb0c79892019-02-13 11:29:59 -0500807 log.Errorw("cannot-add-to-non-container-field", log.Fields{"name": name, "path": path})
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400808 }
809
810 return nil
811}
812
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400813// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
814
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500815// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400816type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400817
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500818// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400819func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500820 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400821 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500822 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400823 return branch
824}
825
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500826// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400827func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500828 n.Lock()
829 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400830 delete(n.Branches, txid)
831}
832
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400833func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400834 f := func(rev Revision) Revision {
835 childBranch := rev.GetBranch()
836
837 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400838 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400839 }
840
841 return rev
842 }
843 return f
844}
845
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500846// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400847func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500848 srcBranch := n.GetBranch(txid)
849 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400850
851 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500852 srcRev := srcBranch.GetLatest()
853 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400854
855 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
856
857 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500858 if rev != nil {
Stephane Barbarief7fc1782019-03-28 22:33:41 -0400859 rev.SetName(dstRev.GetName())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500860 n.makeLatest(dstBranch, rev, changes)
861 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500862 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400863 }
864
Stephane Barbariee16186c2018-09-11 10:46:34 -0400865 // TODO: return proper error when one occurs
866 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400867}
868
869// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
870
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400871//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400872// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500873// rev1 := branch.GetHash(hash1)
874// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400875//
876// if rev1.GetHash() == rev2.GetHash() {
877// // empty patch
878// } else {
879// // translate data to json and generate patch
880// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
881// patch.
882// }
883//}
884
885// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
886
887// TODO: is tag mgmt used in the python implementation? Need to validate
888
889// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
890
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400891func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400892 for fieldName, field := range ChildrenFields(n.Type) {
893 _, fieldValue := GetAttributeValue(data, fieldName, 0)
894
895 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
896 log.Error("cannot update external children")
897 return true
898 }
899 }
900
901 return false
902}
903
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400904// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400905
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500906// CreateProxy returns a reference to a sub-tree of the data model
907func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500908 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400909}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500910
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500911func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400912 for strings.HasPrefix(path, "/") {
913 path = path[1:]
914 }
915 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500916 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400917 }
918
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500919 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400920 partition := strings.SplitN(path, "/", 2)
921 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400922 if len(partition) < 2 {
923 path = ""
924 } else {
925 path = partition[1]
926 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400927
928 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500929 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400930 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500931 //log.Error("cannot proxy a container field")
Stephane Barbarieaa467942019-02-06 14:09:44 -0500932 newNode := n.MakeNode(reflect.New(field.ClassType.Elem()).Interface(), "")
933 return newNode.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400934 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400935 partition := strings.SplitN(path, "/", 2)
936 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400937 if len(partition) < 2 {
938 path = ""
939 } else {
940 path = partition[1]
941 }
942 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400943 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500944 children = make([]Revision, len(rev.GetChildren(name)))
945 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500946 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
947 childNode := childRev.GetNode()
948 return childNode.createProxy(path, fullPath, n, exclusive)
949 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400950 } else {
951 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400952 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400953 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500954 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400955 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500956 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400957 }
958
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500959 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400960 return nil
961}
962
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500963func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500964 n.Lock()
965 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400966 r := &root{
967 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500968 Callbacks: n.Root.GetCallbacks(),
969 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400970 DirtyNodes: n.Root.DirtyNodes,
971 KvStore: n.Root.KvStore,
972 Loading: n.Root.Loading,
973 RevisionClass: n.Root.RevisionClass,
974 }
975
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400976 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500977 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400978 } else {
979 if n.Proxy.Exclusive {
980 log.Error("node is already owned exclusively")
981 }
982 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500983
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400984 return n.Proxy
985}
986
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400987func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500988 n.Lock()
989 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400990 if n.EventBus == nil {
991 n.EventBus = NewEventBus()
992 }
993 return n.EventBus
994}
995
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500996func (n *node) SetProxy(proxy *Proxy) {
997 n.Lock()
998 defer n.Unlock()
999 n.Proxy = proxy
1000}
1001
1002func (n *node) GetProxy() *Proxy {
1003 n.Lock()
1004 defer n.Unlock()
1005 return n.Proxy
1006}
1007
1008func (n *node) GetBranch(key string) *Branch {
1009 n.Lock()
1010 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -05001011
Stephane Barbarie1ab43272018-12-08 21:42:13 -05001012 if n.Branches != nil {
1013 if branch, exists := n.Branches[key]; exists {
1014 return branch
1015 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -05001016 }
1017 return nil
1018}
1019
1020func (n *node) SetBranch(key string, branch *Branch) {
1021 n.Lock()
1022 defer n.Unlock()
1023 n.Branches[key] = branch
1024}
1025
1026func (n *node) GetRoot() *root {
1027 n.Lock()
1028 defer n.Unlock()
1029 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -04001030}