blob: bcda91e4b013de1dcaae57e79890d50664df4f7b [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 Barbarie06c4a742018-10-01 11:09:32 -0400304 if field.IsContainer {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500305 children := make([]Revision, len(rev.GetChildren()[name]))
306 copy(children, rev.GetChildren()[name])
307
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
344 childRev := rev.GetChildren()[name][0]
345 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
412 children = make([]Revision, len(rev.GetChildren()[name]))
413 copy(children, rev.GetChildren()[name])
414
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400415 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400416 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400417
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400418 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400419
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400420 if newChildRev.GetHash() == childRev.GetHash() {
421 if newChildRev != childRev {
422 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
423 newChildRev.ClearHash()
424 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500425 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400426 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400427
428 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500429
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400430 _newKeyType := fmt.Sprintf("%s", newKey)
431 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500432
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400433 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400434 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400435 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500436
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500437 // Prefix the hash value with the data type (e.g. devices, logical_devices, adapters)
438 newChildRev.SetHash(name + "/" + _keyValueType)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400439 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500440
441 updatedRev := rev.UpdateChildren(name, children, branch)
442 branch.GetLatest().Drop(txid, false)
443 n.makeLatest(branch, updatedRev, nil)
444
Stephane Barbariea188d942018-10-16 16:43:04 -0400445 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500446
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400447 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400448 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400449 }
450 } else {
451 childRev := rev.GetChildren()[name][0]
452 childNode := childRev.GetNode()
453 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500454 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
455 rev.Drop(txid, false)
456 n.makeLatest(branch, updatedRev, nil)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500457
Stephane Barbariea188d942018-10-16 16:43:04 -0400458 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400459 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500460
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400461 return nil
462}
463
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400464func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500465 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
466 reflect.TypeOf(data),
467 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400468
469 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
470 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400471 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400472 return nil
473 }
474
475 // TODO: validate that this actually works
476 //if n.hasChildren(data) {
477 // return nil
478 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400479
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500480 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400481 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500482 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400483 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500484
485 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400486 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400487 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400488 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400489 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500490
491 rev := branch.GetLatest().UpdateData(data, branch)
492 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400493
494 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
495 // FIXME VOL-1293 cont'd: need to figure out the required conditions otherwise we are not cleaning up entries
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500496 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400497
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500498 n.makeLatest(branch, rev, changes)
499
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400500 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400501 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500502
503 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400504}
505
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500506// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400507func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400508 for strings.HasPrefix(path, "/") {
509 path = path[1:]
510 }
511 if path == "" {
512 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400513 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400514 }
515
516 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400517 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500518 branch = n.GetBranch(NONE)
519 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400520 branch = makeBranch(n)
521 }
522
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500523 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400524
525 partition := strings.SplitN(path, "/", 2)
526 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400527
528 if len(partition) < 2 {
529 path = ""
530 } else {
531 path = partition[1]
532 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400533
534 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500535
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400536 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400537
538 if field.IsContainer {
539 if path == "" {
540 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500541 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400542 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500543 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400544 }
545
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500546 children = make([]Revision, len(rev.GetChildren()[name]))
547 copy(children, rev.GetChildren()[name])
548
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400549 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500550
Stephane Barbarie126101e2018-10-11 16:18:48 -0400551 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400552 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400553 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500554 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400555 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500556 childRev := n.MakeNode(data, txid).Latest(txid)
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500557
558 // Prefix the hash with the data type (e.g. devices, logical_devices, adapters)
559 childRev.SetHash(name + "/" + key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500560 children = append(children, childRev)
561 rev = rev.UpdateChildren(name, children, branch)
562 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400563
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564 rev.Drop(txid, false)
565 n.makeLatest(branch, rev, changes)
566
567 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400568 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500569 log.Errorf("cannot add to non-keyed container")
570
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400571 } else if field.Key != "" {
572 partition := strings.SplitN(path, "/", 2)
573 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400574 if len(partition) < 2 {
575 path = ""
576 } else {
577 path = partition[1]
578 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400579 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500580
581 children = make([]Revision, len(rev.GetChildren()[name]))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400582 copy(children, rev.GetChildren()[name])
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500583
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400584 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500585
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400586 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400587 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500588
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400589 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500590
591 rev = rev.UpdateChildren(name, branch.GetLatest().GetChildren()[name], branch)
592 rev.Drop(txid, false)
593 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
594
595 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400596 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400597 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400598 }
599 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400600 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400601 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500602
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400603 return nil
604}
605
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500606// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400607func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400608 for strings.HasPrefix(path, "/") {
609 path = path[1:]
610 }
611 if path == "" {
612 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400613 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400614 }
615 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400616 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500617 branch = n.GetBranch(NONE)
618 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400619 branch = makeBranch(n)
620 }
621
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500622 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400623
624 partition := strings.SplitN(path, "/", 2)
625 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400626 if len(partition) < 2 {
627 path = ""
628 } else {
629 path = partition[1]
630 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400631
632 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400633 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400634 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400635
636 if field.IsContainer {
637 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400638 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400639 } else if field.Key != "" {
640 partition := strings.SplitN(path, "/", 2)
641 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400642 if len(partition) < 2 {
643 path = ""
644 } else {
645 path = partition[1]
646 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400647 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500648 children = make([]Revision, len(rev.GetChildren()[name]))
649 copy(children, rev.GetChildren()[name])
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400650 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400651 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400652 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400653 newChildRev := childNode.Remove(path, txid, makeBranch)
654 children[idx] = newChildRev
655 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500656 branch.GetLatest().Drop(txid, false)
657 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400658 return rev
659 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500660 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
661 if n.GetProxy() != nil {
662 data := childRev.GetData()
663 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
664 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
665 } else {
666 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
667 }
668 childRev.Drop(txid, true)
669 children = append(children[:idx], children[idx+1:]...)
670 rev := rev.UpdateChildren(name, children, branch)
671 branch.GetLatest().Drop(txid, false)
672 n.makeLatest(branch, rev, postAnnouncement)
673 return rev
674
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400675 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500676 log.Errorf("cannot add to non-keyed container")
677
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400678 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400679 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400680 }
681
682 return nil
683}
684
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400685// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
686
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500687// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400688type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400689
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500690// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400691func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500692 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400693 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500694 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400695 return branch
696}
697
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500698// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400699func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500700 n.Lock()
701 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400702 delete(n.Branches, txid)
703}
704
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400705func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400706 f := func(rev Revision) Revision {
707 childBranch := rev.GetBranch()
708
709 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400710 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400711 }
712
713 return rev
714 }
715 return f
716}
717
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500718// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400719func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500720 srcBranch := n.GetBranch(txid)
721 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400722
723 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500724 srcRev := srcBranch.GetLatest()
725 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400726
727 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
728
729 if !dryRun {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500730 n.makeLatest(dstBranch, rev, changes)
731 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400732 }
733
Stephane Barbariee16186c2018-09-11 10:46:34 -0400734 // TODO: return proper error when one occurs
735 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400736}
737
738// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
739
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400740//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400741// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500742// rev1 := branch.GetHash(hash1)
743// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400744//
745// if rev1.GetHash() == rev2.GetHash() {
746// // empty patch
747// } else {
748// // translate data to json and generate patch
749// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
750// patch.
751// }
752//}
753
754// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
755
756// TODO: is tag mgmt used in the python implementation? Need to validate
757
758// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
759
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400760func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400761 for fieldName, field := range ChildrenFields(n.Type) {
762 _, fieldValue := GetAttributeValue(data, fieldName, 0)
763
764 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
765 log.Error("cannot update external children")
766 return true
767 }
768 }
769
770 return false
771}
772
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400773// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400774
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500775// CreateProxy returns a reference to a sub-tree of the data model
776func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500777 return n.createProxy(path, path, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400778}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500779
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500780func (n *node) createProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400781 for strings.HasPrefix(path, "/") {
782 path = path[1:]
783 }
784 if path == "" {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500785 return n.makeProxy(path, fullPath, parentNode, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400786 }
787
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500788 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400789 partition := strings.SplitN(path, "/", 2)
790 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400791 if len(partition) < 2 {
792 path = ""
793 } else {
794 path = partition[1]
795 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400796
797 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500798 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400799 if path == "" {
800 log.Error("cannot proxy a container field")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400801 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400802 partition := strings.SplitN(path, "/", 2)
803 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400804 if len(partition) < 2 {
805 path = ""
806 } else {
807 path = partition[1]
808 }
809 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400810 var children []Revision
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500811 children = make([]Revision, len(rev.GetChildren()[name]))
812 copy(children, rev.GetChildren()[name])
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400813 _, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400814 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400815
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500816 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400817 } else {
818 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400819 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400820 } else {
821 childRev := rev.GetChildren()[name][0]
822 childNode := childRev.GetNode()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500823 return childNode.createProxy(path, fullPath, n, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400824 }
825
826 return nil
827}
828
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500829func (n *node) makeProxy(path string, fullPath string, parentNode *node, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500830 n.Lock()
831 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400832 r := &root{
833 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500834 Callbacks: n.Root.GetCallbacks(),
835 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400836 DirtyNodes: n.Root.DirtyNodes,
837 KvStore: n.Root.KvStore,
838 Loading: n.Root.Loading,
839 RevisionClass: n.Root.RevisionClass,
840 }
841
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400842 if n.Proxy == nil {
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500843 n.Proxy = NewProxy(r, n, parentNode, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400844 } else {
845 if n.Proxy.Exclusive {
846 log.Error("node is already owned exclusively")
847 }
848 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500849
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400850 return n.Proxy
851}
852
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400853func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500854 n.Lock()
855 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400856 if n.EventBus == nil {
857 n.EventBus = NewEventBus()
858 }
859 return n.EventBus
860}
861
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500862func (n *node) SetProxy(proxy *Proxy) {
863 n.Lock()
864 defer n.Unlock()
865 n.Proxy = proxy
866}
867
868func (n *node) GetProxy() *Proxy {
869 n.Lock()
870 defer n.Unlock()
871 return n.Proxy
872}
873
874func (n *node) GetBranch(key string) *Branch {
875 n.Lock()
876 defer n.Unlock()
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500877 if n.Branches != nil {
878 if branch, exists := n.Branches[key]; exists {
879 return branch
880 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500881 }
882 return nil
883}
884
885func (n *node) SetBranch(key string, branch *Branch) {
886 n.Lock()
887 defer n.Unlock()
888 n.Branches[key] = branch
889}
890
891func (n *node) GetRoot() *root {
892 n.Lock()
893 defer n.Unlock()
894 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400895}