blob: 20fd495df5916a80d9a62e31c05473c209051162 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040017package model
18
Stephane Barbariee16186c2018-09-11 10:46:34 -040019// TODO: proper error handling
20// TODO: proper logging
21
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040022import (
23 "fmt"
24 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040025 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040026 "reflect"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050027 "runtime/debug"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040028 "strings"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050029 "sync"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040030)
31
Stephane Barbariedc5022d2018-11-19 15:21:44 -050032// When a branch has no transaction id, everything gets stored in NONE
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040033const (
34 NONE string = "none"
35)
36
Stephane Barbariedc5022d2018-11-19 15:21:44 -050037// Node interface is an abstraction of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040038type Node interface {
39 MakeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple)
40
41 // CRUD functions
42 Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision
43 Get(path string, hash string, depth int, deep bool, txid string) interface{}
44 Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision
45 Remove(path string, txid string, makeBranch MakeBranchFunction) Revision
46
47 MakeBranch(txid string) *Branch
48 DeleteBranch(txid string)
49 MergeBranch(txid string, dryRun bool) (Revision, error)
50
51 MakeTxBranch() string
52 DeleteTxBranch(txid string)
53 FoldTxBranch(txid string)
54
Stephane Barbariedc5022d2018-11-19 15:21:44 -050055 CreateProxy(path string, exclusive bool) *Proxy
56 GetProxy() *Proxy
Stephane Barbarie06c4a742018-10-01 11:09:32 -040057}
58
59type node struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050060 sync.RWMutex
Stephane Barbarie126101e2018-10-11 16:18:48 -040061 Root *root
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040062 Type interface{}
63 Branches map[string]*Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -040064 Tags map[string]Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040065 Proxy *Proxy
66 EventBus *EventBus
67 AutoPrune bool
68}
69
Stephane Barbariedc5022d2018-11-19 15:21:44 -050070// ChangeTuple holds details of modifications made to a revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -040071type ChangeTuple struct {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040072 Type CallbackType
73 PreviousData interface{}
74 LatestData interface{}
Stephane Barbarie694e2b92018-09-07 12:17:36 -040075}
76
Stephane Barbariedc5022d2018-11-19 15:21:44 -050077// NewNode creates a new instance of the node data structure
Stephane Barbarie06c4a742018-10-01 11:09:32 -040078func NewNode(root *root, initialData interface{}, autoPrune bool, txid string) *node {
79 n := &node{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040080
Stephane Barbarie126101e2018-10-11 16:18:48 -040081 n.Root = root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040082 n.Branches = make(map[string]*Branch)
83 n.Tags = make(map[string]Revision)
84 n.Proxy = nil
85 n.EventBus = nil
86 n.AutoPrune = autoPrune
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040087
88 if IsProtoMessage(initialData) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040089 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040090 dataCopy := proto.Clone(initialData.(proto.Message))
Stephane Barbarieec0919b2018-09-05 14:14:29 -040091 n.initialize(dataCopy, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 } else if reflect.ValueOf(initialData).IsValid() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050093 // FIXME: this block does not reflect the original implementation
94 // it should be checking if the provided initial_data is already a type!??!
95 // it should be checked before IsProtoMessage
Stephane Barbarieec0919b2018-09-05 14:14:29 -040096 n.Type = reflect.ValueOf(initialData).Interface()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040097 } else {
98 // not implemented error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -040099 log.Errorf("cannot process initial data - %+v", initialData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400100 }
101
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400102 return n
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400103}
104
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500105// MakeNode creates a new node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400106func (n *node) MakeNode(data interface{}, txid string) *node {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400107 return NewNode(n.Root, data, true, txid)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400108}
109
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500110// MakeRevision create a new revision of the node in the tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400111func (n *node) MakeRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500112 return n.GetRoot().MakeRevision(branch, data, children)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400113}
114
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500115// makeLatest will mark the revision of a node as being the latest
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400116func (n *node) makeLatest(branch *Branch, revision Revision, changeAnnouncement []ChangeTuple) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500117 branch.AddRevision(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400118
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500119 if branch.GetLatest() == nil || revision.GetHash() != branch.GetLatest().GetHash() {
120 branch.SetLatest(revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400121 }
122
123 if changeAnnouncement != nil && branch.Txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500124 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400125 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400126 log.Debugf("invoking callback - changeType: %+v, previous:%+v, latest: %+v",
127 change.Type,
128 change.PreviousData,
129 change.LatestData)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500130 n.GetRoot().AddCallback(
131 n.GetProxy().InvokeCallbacks,
Stephane Barbarie126101e2018-10-11 16:18:48 -0400132 change.Type,
133 true,
134 change.PreviousData,
135 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400136 }
137 }
138
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400139 for _, change := range changeAnnouncement {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400140 log.Debugf("sending notification - changeType: %+v, previous:%+v, latest: %+v",
141 change.Type,
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400142 change.PreviousData,
143 change.LatestData)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500144 n.GetRoot().AddNotificationCallback(
Stephane Barbarie126101e2018-10-11 16:18:48 -0400145 n.makeEventBus().Advertise,
146 change.Type,
147 revision.GetHash(),
148 change.PreviousData,
149 change.LatestData)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400150 }
151 }
152}
153
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500154// Latest returns the latest revision of node with or without the transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400155func (n *node) Latest(txid ...string) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400156 var branch *Branch
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400157
158 if len(txid) > 0 && txid[0] != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500159 if branch = n.GetBranch(txid[0]); branch != nil {
160 return branch.GetLatest()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400161 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500162 } else if branch = n.GetBranch(NONE); branch != nil {
163 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400164 }
165 return nil
166}
167
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500168// initialize prepares the content of a node along with its possible ramifications
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400169func (n *node) initialize(data interface{}, txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500170 n.Lock()
171 children := make(map[string][]Revision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400172 for fieldName, field := range ChildrenFields(n.Type) {
173 _, fieldValue := GetAttributeValue(data, fieldName, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400174
175 if fieldValue.IsValid() {
176 if field.IsContainer {
177 if field.Key != "" {
178 var keysSeen []string
179
180 for i := 0; i < fieldValue.Len(); i++ {
181 v := fieldValue.Index(i)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400182
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500183 if rev := n.MakeNode(v.Interface(), txid).Latest(txid); rev != nil {
184 children[fieldName] = append(children[fieldName], rev)
185 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400186
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400187 _, key := GetAttributeValue(v.Interface(), field.Key, 0)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400188 for _, k := range keysSeen {
189 if k == key.String() {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400190 log.Errorf("duplicate key - %s", k)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400191 }
192 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400193 keysSeen = append(keysSeen, key.String())
194 }
195
196 } else {
197 for i := 0; i < fieldValue.Len(); i++ {
198 v := fieldValue.Index(i)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500199 if newNodeRev := n.MakeNode(v.Interface(), txid).Latest(); newNodeRev != nil {
200 children[fieldName] = append(children[fieldName], newNodeRev)
201 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400202 }
203 }
204 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500205 if newNodeRev := n.MakeNode(fieldValue.Interface(), txid).Latest(); newNodeRev != nil {
206 children[fieldName] = append(children[fieldName], newNodeRev)
207 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400208 }
209 } else {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400210 log.Errorf("field is invalid - %+v", fieldValue)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400211 }
212 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500213 n.Unlock()
214
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400215 branch := NewBranch(n, "", nil, n.AutoPrune)
216 rev := n.MakeRevision(branch, data, children)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400217 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400218
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400219 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500220 n.SetBranch(NONE, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400221 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500222 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400223 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400224}
225
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500226// findRevByKey retrieves a specific revision from a node tree
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400227func (n *node) findRevByKey(revs []Revision, keyName string, value interface{}) (int, Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500228 n.Lock()
229 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500230
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400231 for i, rev := range revs {
232 dataValue := reflect.ValueOf(rev.GetData())
233 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
234
235 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
236
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400237 a := fmt.Sprintf("%s", fieldValue.Interface())
238 b := fmt.Sprintf("%s", value)
239 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500240 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400241 }
242 }
243
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400244 return -1, nil
245}
246
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500247// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400248func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400249 if deep {
250 depth = -1
251 }
252
253 for strings.HasPrefix(path, "/") {
254 path = path[1:]
255 }
256
257 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400258 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400259
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500260 if branch = n.GetBranch(txid); txid == "" || branch == nil {
261 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400262 }
263
264 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500265 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400266 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500267 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400268 }
269
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500270 var result interface{}
271 if result = n.getPath(rev.GetBranch().GetLatest(), path, depth);
272 reflect.ValueOf(result).IsValid() && reflect.ValueOf(result).IsNil() && n.Root.KvStore != nil {
273 // We got nothing from memory, try to pull it from persistence
274 var prList []interface{}
275 if pr := rev.LoadFromPersistence(path, txid); pr != nil {
276 for _, revEntry := range pr {
277 prList = append(prList, revEntry.GetData())
278 }
279 result = prList
280 }
281 }
282
283 return result
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400284}
285
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500286// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400287func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400288 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400289 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400290 }
291
292 partition := strings.SplitN(path, "/", 2)
293 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400294
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400295 if len(partition) < 2 {
296 path = ""
297 } else {
298 path = partition[1]
299 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400300
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400301 names := ChildrenFields(n.Type)
302 field := names[name]
303
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500304 if field != nil && field.IsContainer {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500305 children := make([]Revision, len(rev.GetChildren(name)))
306 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500307
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400308 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400309 if path != "" {
310 partition = strings.SplitN(path, "/", 2)
311 key := partition[0]
312 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400313 keyValue := field.KeyFromStr(key)
314 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400315 return nil
316 } else {
317 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400318 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400319 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400320 } else {
321 var response []interface{}
322 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400323 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400324 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400325 response = append(response, value)
326 }
327 return response
328 }
329 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400330 var response []interface{}
331 if path != "" {
332 // TODO: raise error
333 return response
334 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500335 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400336 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400337 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400338 response = append(response, value)
339 }
340 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400341 }
342 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500343
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500344 childRev := rev.GetChildren(name)[0]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500345 childNode := childRev.GetNode()
346 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400347}
348
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500349// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400350func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500351 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400352 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400353
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500354 if n.GetProxy() != nil {
355 log.Debug("invoking proxy GET Callbacks : %+v", msg)
356 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400357 msg = modifiedMsg
358 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400359
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400360 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500361
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400362 return msg
363}
364
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500365// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400366func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400367 for strings.HasPrefix(path, "/") {
368 path = path[1:]
369 }
370
371 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400372 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500373 branch = n.GetBranch(NONE)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500374 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400375 branch = makeBranch(n)
376 }
377
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500378 if branch.GetLatest() != nil {
379 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
380 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400381 if path == "" {
382 return n.doUpdate(branch, data, strict)
383 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400384
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500385 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400386
387 partition := strings.SplitN(path, "/", 2)
388 name := partition[0]
389
390 if len(partition) < 2 {
391 path = ""
392 } else {
393 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400394 }
395
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400396 field := ChildrenFields(n.Type)[name]
397 var children []Revision
398
399 if field.IsContainer {
400 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400401 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400402 } else if field.Key != "" {
403 partition := strings.SplitN(path, "/", 2)
404 key := partition[0]
405 if len(partition) < 2 {
406 path = ""
407 } else {
408 path = partition[1]
409 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400410 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500411
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500412 children = make([]Revision, len(rev.GetChildren(name)))
413 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500414
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400415 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400416 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400417
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500418 // Save proxy in child node to ensure callbacks are called later on
419 if childNode.Proxy == nil {
420 childNode.Proxy = n.Proxy
421 }
422
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400423 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400424
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400425 if newChildRev.GetHash() == childRev.GetHash() {
426 if newChildRev != childRev {
427 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
428 newChildRev.ClearHash()
429 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500430 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400431 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400432
433 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500434
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400435 _newKeyType := fmt.Sprintf("%s", newKey)
436 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500437
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400438 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400439 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400440 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500441
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500442 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
443 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400444 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500445
446 updatedRev := rev.UpdateChildren(name, children, branch)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500447
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500448 branch.GetLatest().Drop(txid, false)
449 n.makeLatest(branch, updatedRev, nil)
450
Stephane Barbariea188d942018-10-16 16:43:04 -0400451 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500452
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400453 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400454 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400455 }
456 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500457 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400458 childNode := childRev.GetNode()
459 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500460 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
461 rev.Drop(txid, false)
462 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500463
Stephane Barbariea188d942018-10-16 16:43:04 -0400464 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400465 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500466
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400467 return nil
468}
469
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400470func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500471 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
472 reflect.TypeOf(data),
473 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400474
475 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
476 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400477 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400478 return nil
479 }
480
481 // TODO: validate that this actually works
482 //if n.hasChildren(data) {
483 // return nil
484 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400485
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500486 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400487 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500488 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400489 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500490
491 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400492 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400493 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400494 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400495 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500496
497 rev := branch.GetLatest().UpdateData(data, branch)
498 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400499
500 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
501 // FIXME VOL-1293 cont'd: need to figure out the required conditions otherwise we are not cleaning up entries
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500502 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400503
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500504 n.makeLatest(branch, rev, changes)
505
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400506 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400507 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500508
509 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400510}
511
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500512// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400513func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400514 for strings.HasPrefix(path, "/") {
515 path = path[1:]
516 }
517 if path == "" {
518 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400519 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400520 }
521
522 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400523 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500524 branch = n.GetBranch(NONE)
525 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400526 branch = makeBranch(n)
527 }
528
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500529 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400530
531 partition := strings.SplitN(path, "/", 2)
532 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400533
534 if len(partition) < 2 {
535 path = ""
536 } else {
537 path = partition[1]
538 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400539
540 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500541
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400542 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400543
544 if field.IsContainer {
545 if path == "" {
546 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500547 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400548 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500549 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400550 }
551
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500552 children = make([]Revision, len(rev.GetChildren(name)))
553 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500554
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400555 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500556
Stephane Barbarie126101e2018-10-11 16:18:48 -0400557 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400558 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400559 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500560 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400561 }
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500562 childRev := n.MakeNode(data, "").Latest()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500563
564 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
565 childRev.SetHash(name + "/" + key.String())
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500566
567 // Create watch for <component>/<key>
568 childRev.SetupWatch(childRev.GetHash())
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500569
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500570 children = append(children, childRev)
571 rev = rev.UpdateChildren(name, children, branch)
572 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400573
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500574 rev.Drop(txid, false)
575 n.makeLatest(branch, rev, changes)
576
577 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400578 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500579 log.Errorf("cannot add to non-keyed container")
580
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400581 } else if field.Key != "" {
582 partition := strings.SplitN(path, "/", 2)
583 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400584 if len(partition) < 2 {
585 path = ""
586 } else {
587 path = partition[1]
588 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400589 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500590
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500591 children = make([]Revision, len(rev.GetChildren(name)))
592 copy(children, rev.GetChildren(name))
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500593
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400594 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500595
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400596 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400597 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500598
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500599 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
600 childRev.SetHash(name + "/" + keyValue.(string))
601
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400602 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500603
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500604 rev = rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500605 rev.Drop(txid, false)
606 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
607
608 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400609 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400610 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400611 }
612 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400613 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400614 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500615
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400616 return nil
617}
618
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500619// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400620func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400621 for strings.HasPrefix(path, "/") {
622 path = path[1:]
623 }
624 if path == "" {
625 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400626 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400627 }
628 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400629 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500630 branch = n.GetBranch(NONE)
631 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400632 branch = makeBranch(n)
633 }
634
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500635 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400636
637 partition := strings.SplitN(path, "/", 2)
638 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400639 if len(partition) < 2 {
640 path = ""
641 } else {
642 path = partition[1]
643 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400644
645 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400646 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400647 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400648
649 if field.IsContainer {
650 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400651 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400652 } else if field.Key != "" {
653 partition := strings.SplitN(path, "/", 2)
654 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400655 if len(partition) < 2 {
656 path = ""
657 } else {
658 path = partition[1]
659 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400660 keyValue := field.KeyFromStr(key)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500661 children = make([]Revision, len(rev.GetChildren(name)))
662 copy(children, rev.GetChildren(name))
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400663 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400664 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400665 childNode := childRev.GetNode()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500666 if childNode.Proxy == nil {
667 childNode.Proxy = n.Proxy
668 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400669 newChildRev := childNode.Remove(path, txid, makeBranch)
670 children[idx] = newChildRev
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500671 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500672 branch.GetLatest().Drop(txid, false)
673 n.makeLatest(branch, rev, nil)
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500674 return nil
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400675 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500676 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
677 if n.GetProxy() != nil {
678 data := childRev.GetData()
679 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
680 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
681 } else {
682 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
683 }
684 childRev.Drop(txid, true)
685 children = append(children[:idx], children[idx+1:]...)
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500686 rev.SetChildren(name, children)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500687 branch.GetLatest().Drop(txid, false)
688 n.makeLatest(branch, rev, postAnnouncement)
689 return rev
690
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400691 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500692 log.Errorf("cannot add to non-keyed container")
693
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400694 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400695 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400696 }
697
698 return nil
699}
700
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400701// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
702
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500703// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400704type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400705
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500706// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400707func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500708 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400709 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500710 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400711 return branch
712}
713
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500714// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400715func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500716 n.Lock()
717 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400718 delete(n.Branches, txid)
719}
720
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400721func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400722 f := func(rev Revision) Revision {
723 childBranch := rev.GetBranch()
724
725 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400726 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400727 }
728
729 return rev
730 }
731 return f
732}
733
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500734// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400735func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500736 srcBranch := n.GetBranch(txid)
737 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400738
739 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500740 srcRev := srcBranch.GetLatest()
741 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400742
743 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
744
745 if !dryRun {
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500746 if rev != nil {
747 n.makeLatest(dstBranch, rev, changes)
748 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500749 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400750 }
751
Stephane Barbariee16186c2018-09-11 10:46:34 -0400752 // TODO: return proper error when one occurs
753 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400754}
755
756// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
757
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400758//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400759// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500760// rev1 := branch.GetHash(hash1)
761// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400762//
763// if rev1.GetHash() == rev2.GetHash() {
764// // empty patch
765// } else {
766// // translate data to json and generate patch
767// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
768// patch.
769// }
770//}
771
772// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
773
774// TODO: is tag mgmt used in the python implementation? Need to validate
775
776// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
777
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400778func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400779 for fieldName, field := range ChildrenFields(n.Type) {
780 _, fieldValue := GetAttributeValue(data, fieldName, 0)
781
782 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
783 log.Error("cannot update external children")
784 return true
785 }
786 }
787
788 return false
789}
790
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400791// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400792
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500793// CreateProxy returns a reference to a sub-tree of the data model
794func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500795 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400796}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500797
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500798func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400799 for strings.HasPrefix(path, "/") {
800 path = path[1:]
801 }
802 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500803 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400804 }
805
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500806 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400807 partition := strings.SplitN(path, "/", 2)
808 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400809 if len(partition) < 2 {
810 path = ""
811 } else {
812 path = partition[1]
813 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400814
815 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500816 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400817 if path == "" {
khenaidoo21d51152019-02-01 13:48:37 -0500818 //log.Error("cannot proxy a container field")
819 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400820 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400821 partition := strings.SplitN(path, "/", 2)
822 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400823 if len(partition) < 2 {
824 path = ""
825 } else {
826 path = partition[1]
827 }
828 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400829 var children []Revision
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500830 children = make([]Revision, len(rev.GetChildren(name)))
831 copy(children, rev.GetChildren(name))
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500832 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev != nil {
833 childNode := childRev.GetNode()
834 return childNode.createProxy(path, fullPath, n, exclusive)
835 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400836 } else {
837 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400838 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400839 } else {
Stephane Barbarie3cb01222019-01-16 17:15:56 -0500840 childRev := rev.GetChildren(name)[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400841 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500842 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400843 }
844
Stephane Barbarie933b09b2019-01-09 11:12:09 -0500845 log.Warnf("Cannot create proxy - latest rev:%s, all revs:%+v", rev.GetHash(), n.GetBranch(NONE).Revisions)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400846 return nil
847}
848
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500849func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500850 n.Lock()
851 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400852 r := &root{
853 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500854 Callbacks: n.Root.GetCallbacks(),
855 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400856 DirtyNodes: n.Root.DirtyNodes,
857 KvStore: n.Root.KvStore,
858 Loading: n.Root.Loading,
859 RevisionClass: n.Root.RevisionClass,
860 }
861
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400862 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500863 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400864 } else {
865 if n.Proxy.Exclusive {
866 log.Error("node is already owned exclusively")
867 }
868 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500869
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400870 return n.Proxy
871}
872
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400873func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500874 n.Lock()
875 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400876 if n.EventBus == nil {
877 n.EventBus = NewEventBus()
878 }
879 return n.EventBus
880}
881
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500882func (n *node) SetProxy(proxy *Proxy) {
883 n.Lock()
884 defer n.Unlock()
885 n.Proxy = proxy
886}
887
888func (n *node) GetProxy() *Proxy {
889 n.Lock()
890 defer n.Unlock()
891 return n.Proxy
892}
893
894func (n *node) GetBranch(key string) *Branch {
895 n.Lock()
896 defer n.Unlock()
Stephane Barbarie1039ec42019-02-04 10:43:16 -0500897
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500898 if n.Branches != nil {
899 if branch, exists := n.Branches[key]; exists {
900 return branch
901 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500902 }
903 return nil
904}
905
906func (n *node) SetBranch(key string, branch *Branch) {
907 n.Lock()
908 defer n.Unlock()
909 n.Branches[key] = branch
910}
911
912func (n *node) GetRoot() *root {
913 n.Lock()
914 defer n.Unlock()
915 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400916}