blob: 7ea41ce21ec9914a509c8c4c34deabceb6384b3f [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 Barbarie06c4a742018-10-01 11:09:32 -0400230 for i, rev := range revs {
231 dataValue := reflect.ValueOf(rev.GetData())
232 dataStruct := GetAttributeStructure(rev.GetData(), keyName, 0)
233
234 fieldValue := dataValue.Elem().FieldByName(dataStruct.Name)
235
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400236 a := fmt.Sprintf("%s", fieldValue.Interface())
237 b := fmt.Sprintf("%s", value)
238 if a == b {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500239 return i, revs[i]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400240 }
241 }
242
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400243 return -1, nil
244}
245
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500246// Get retrieves the data from a node tree that resides at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400247func (n *node) Get(path string, hash string, depth int, deep bool, txid string) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400248 if deep {
249 depth = -1
250 }
251
252 for strings.HasPrefix(path, "/") {
253 path = path[1:]
254 }
255
256 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400257 var rev Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400258
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500259 if branch = n.GetBranch(txid); txid == "" || branch == nil {
260 branch = n.GetBranch(NONE)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400261 }
262
263 if hash != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500264 rev = branch.GetRevision(hash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400265 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500266 rev = branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400267 }
268
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400269 return n.getPath(rev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400270}
271
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500272// getPath traverses the specified path and retrieves the data associated to it
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400273func (n *node) getPath(rev Revision, path string, depth int) interface{} {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400274 if path == "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400275 return n.getData(rev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400276 }
277
278 partition := strings.SplitN(path, "/", 2)
279 name := partition[0]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400280
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400281 if len(partition) < 2 {
282 path = ""
283 } else {
284 path = partition[1]
285 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400286
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400287 names := ChildrenFields(n.Type)
288 field := names[name]
289
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400290 if field.IsContainer {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500291 children := make([]Revision, len(rev.GetChildren()[name]))
292 copy(children, rev.GetChildren()[name])
293
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400294 if field.Key != "" {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400295 if path != "" {
296 partition = strings.SplitN(path, "/", 2)
297 key := partition[0]
298 path = ""
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400299 keyValue := field.KeyFromStr(key)
300 if _, childRev := n.findRevByKey(children, field.Key, keyValue); childRev == nil {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400301 return nil
302 } else {
303 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400304 return childNode.getPath(childRev, path, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400305 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400306 } else {
307 var response []interface{}
308 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400309 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400310 value := childNode.getData(childRev, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400311 response = append(response, value)
312 }
313 return response
314 }
315 } else {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400316 var response []interface{}
317 if path != "" {
318 // TODO: raise error
319 return response
320 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500321 for _, childRev := range children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400322 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400323 value := childNode.getData(childRev, depth)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400324 response = append(response, value)
325 }
326 return response
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400327 }
328 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500329
330 childRev := rev.GetChildren()[name][0]
331 childNode := childRev.GetNode()
332 return childNode.getPath(childRev, path, depth)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400333}
334
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500335// getData retrieves the data from a node revision
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400336func (n *node) getData(rev Revision, depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500337 msg := rev.GetBranch().GetLatest().Get(depth)
Stephane Barbariea188d942018-10-16 16:43:04 -0400338 var modifiedMsg interface{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400339
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500340 if n.GetProxy() != nil {
341 log.Debug("invoking proxy GET Callbacks : %+v", msg)
342 if modifiedMsg = n.GetProxy().InvokeCallbacks(GET, false, msg); modifiedMsg != nil {
Stephane Barbariea188d942018-10-16 16:43:04 -0400343 msg = modifiedMsg
344 }
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400345
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400346 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500347
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400348 return msg
349}
350
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500351// Update changes the content of a node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400352func (n *node) Update(path string, data interface{}, strict bool, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400353 for strings.HasPrefix(path, "/") {
354 path = path[1:]
355 }
356
357 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400358 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500359 branch = n.GetBranch(NONE)
360 } else if branch = n.GetBranch(txid); &branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400361 branch = makeBranch(n)
362 }
363
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500364 if branch.GetLatest() != nil {
365 log.Debugf("Branch data : %+v, Passed data: %+v", branch.GetLatest().GetData(), data)
366 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400367 if path == "" {
368 return n.doUpdate(branch, data, strict)
369 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400370
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500371 rev := branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400372
373 partition := strings.SplitN(path, "/", 2)
374 name := partition[0]
375
376 if len(partition) < 2 {
377 path = ""
378 } else {
379 path = partition[1]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400380 }
381
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400382 field := ChildrenFields(n.Type)[name]
383 var children []Revision
384
385 if field.IsContainer {
386 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400387 log.Errorf("cannot update a list")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400388 } else if field.Key != "" {
389 partition := strings.SplitN(path, "/", 2)
390 key := partition[0]
391 if len(partition) < 2 {
392 path = ""
393 } else {
394 path = partition[1]
395 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400396 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500397
398 children = make([]Revision, len(rev.GetChildren()[name]))
399 copy(children, rev.GetChildren()[name])
400
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400401 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400402 childNode := childRev.GetNode()
Stephane Barbariea188d942018-10-16 16:43:04 -0400403
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400404 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400405
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400406 if newChildRev.GetHash() == childRev.GetHash() {
407 if newChildRev != childRev {
408 log.Debug("clear-hash - %s %+v", newChildRev.GetHash(), newChildRev)
409 newChildRev.ClearHash()
410 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500411 return branch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400412 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400413
414 _, newKey := GetAttributeValue(newChildRev.GetData(), field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500415
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400416 _newKeyType := fmt.Sprintf("%s", newKey)
417 _keyValueType := fmt.Sprintf("%s", keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500418
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400419 if _newKeyType != _keyValueType {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400420 log.Errorf("cannot change key field")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400421 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500422
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400423 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500424
425 updatedRev := rev.UpdateChildren(name, children, branch)
426 branch.GetLatest().Drop(txid, false)
427 n.makeLatest(branch, updatedRev, nil)
428
Stephane Barbariea188d942018-10-16 16:43:04 -0400429 return newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500430
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400431 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400432 log.Errorf("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400433 }
434 } else {
435 childRev := rev.GetChildren()[name][0]
436 childNode := childRev.GetNode()
437 newChildRev := childNode.Update(path, data, strict, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500438 updatedRev := rev.UpdateChildren(name, []Revision{newChildRev}, branch)
439 rev.Drop(txid, false)
440 n.makeLatest(branch, updatedRev, nil)
Stephane Barbariea188d942018-10-16 16:43:04 -0400441 return newChildRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400442 }
443 return nil
444}
445
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400446func (n *node) doUpdate(branch *Branch, data interface{}, strict bool) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500447 log.Debugf("Comparing types - expected: %+v, actual: %+v &&&&&& %s", reflect.ValueOf(n.Type).Type(),
448 reflect.TypeOf(data),
449 string(debug.Stack()))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400450
451 if reflect.TypeOf(data) != reflect.ValueOf(n.Type).Type() {
452 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400453 log.Errorf("data does not match type: %+v", n.Type)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400454 return nil
455 }
456
457 // TODO: validate that this actually works
458 //if n.hasChildren(data) {
459 // return nil
460 //}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400461
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500462 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400463 log.Debug("invoking proxy PRE_UPDATE Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500464 n.GetProxy().InvokeCallbacks(PRE_UPDATE, false, branch.GetLatest(), data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400465 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500466
467 if branch.GetLatest().GetData().(proto.Message).String() != data.(proto.Message).String() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400468 if strict {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400469 // TODO: checkAccessViolations(data, Branch.GetLatest.data)
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400470 log.Debugf("checking access violations")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400471 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500472
473 rev := branch.GetLatest().UpdateData(data, branch)
474 changes := []ChangeTuple{{POST_UPDATE, branch.GetLatest().GetData(), rev.GetData()}}
Stephane Barbariea188d942018-10-16 16:43:04 -0400475
476 // FIXME VOL-1293: the following statement corrupts the kv when using a subproxy (commenting for now)
477 // 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 -0500478 //branch.GetLatest().Drop(branch.Txid, true)
Stephane Barbariea188d942018-10-16 16:43:04 -0400479
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500480 n.makeLatest(branch, rev, changes)
481
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400482 return rev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400483 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500484
485 return branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400486}
487
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500488// Add inserts a new node at the specified path with the provided data
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400489func (n *node) Add(path string, data interface{}, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400490 for strings.HasPrefix(path, "/") {
491 path = path[1:]
492 }
493 if path == "" {
494 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400495 log.Errorf("cannot add for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400496 }
497
498 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400499 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500500 branch = n.GetBranch(NONE)
501 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400502 branch = makeBranch(n)
503 }
504
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500505 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400506
507 partition := strings.SplitN(path, "/", 2)
508 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400509
510 if len(partition) < 2 {
511 path = ""
512 } else {
513 path = partition[1]
514 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400515
516 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500517
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400518 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400519
520 if field.IsContainer {
521 if path == "" {
522 if field.Key != "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500523 if n.GetProxy() != nil {
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400524 log.Debug("invoking proxy PRE_ADD Callbacks")
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500525 n.GetProxy().InvokeCallbacks(PRE_ADD, false, data)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400526 }
527
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500528 children = make([]Revision, len(rev.GetChildren()[name]))
529 copy(children, rev.GetChildren()[name])
530
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400531 _, key := GetAttributeValue(data, field.Key, 0)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500532
Stephane Barbarie126101e2018-10-11 16:18:48 -0400533 if _, exists := n.findRevByKey(children, field.Key, key.String()); exists != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400534 // TODO raise error
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400535 log.Errorf("duplicate key found: %s", key.String())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500536 return exists
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400537 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500538 childRev := n.MakeNode(data, txid).Latest(txid)
539 children = append(children, childRev)
540 rev = rev.UpdateChildren(name, children, branch)
541 changes := []ChangeTuple{{POST_ADD, nil, childRev.GetData()}}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400542
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500543 rev.Drop(txid, false)
544 n.makeLatest(branch, rev, changes)
545
546 return childRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400547 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500548 log.Errorf("cannot add to non-keyed container")
549
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400550 } else if field.Key != "" {
551 partition := strings.SplitN(path, "/", 2)
552 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400553 if len(partition) < 2 {
554 path = ""
555 } else {
556 path = partition[1]
557 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400558 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500559
560 children = make([]Revision, len(rev.GetChildren()[name]))
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400561 copy(children, rev.GetChildren()[name])
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500562
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400563 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500564
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400565 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400566 newChildRev := childNode.Add(path, data, txid, makeBranch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500567
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400568 children[idx] = newChildRev
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500569
570 rev = rev.UpdateChildren(name, branch.GetLatest().GetChildren()[name], branch)
571 rev.Drop(txid, false)
572 n.makeLatest(branch, rev.GetBranch().GetLatest(), nil)
573
574 return newChildRev
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400575 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400576 log.Errorf("cannot add to non-keyed container")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400577 }
578 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400579 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400580 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500581
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400582 return nil
583}
584
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500585// Remove eliminates a node at the specified path
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400586func (n *node) Remove(path string, txid string, makeBranch MakeBranchFunction) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400587 for strings.HasPrefix(path, "/") {
588 path = path[1:]
589 }
590 if path == "" {
591 // TODO raise error
Stephane Barbarie126101e2018-10-11 16:18:48 -0400592 log.Errorf("cannot remove for non-container mode")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400593 }
594 var branch *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400595 if txid == "" {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500596 branch = n.GetBranch(NONE)
597 } else if branch = n.GetBranch(txid); branch == nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400598 branch = makeBranch(n)
599 }
600
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500601 rev := branch.GetLatest()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400602
603 partition := strings.SplitN(path, "/", 2)
604 name := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400605 if len(partition) < 2 {
606 path = ""
607 } else {
608 path = partition[1]
609 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400610
611 field := ChildrenFields(n.Type)[name]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400612 var children []Revision
Stephane Barbarie694e2b92018-09-07 12:17:36 -0400613 postAnnouncement := []ChangeTuple{}
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400614
615 if field.IsContainer {
616 if path == "" {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400617 log.Errorf("cannot remove without a key")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400618 } else if field.Key != "" {
619 partition := strings.SplitN(path, "/", 2)
620 key := partition[0]
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400621 if len(partition) < 2 {
622 path = ""
623 } else {
624 path = partition[1]
625 }
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400626 keyValue := field.KeyFromStr(key)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500627 children = make([]Revision, len(rev.GetChildren()[name]))
628 copy(children, rev.GetChildren()[name])
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400629 if path != "" {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400630 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400631 childNode := childRev.GetNode()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400632 newChildRev := childNode.Remove(path, txid, makeBranch)
633 children[idx] = newChildRev
634 rev := rev.UpdateChildren(name, children, branch)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500635 branch.GetLatest().Drop(txid, false)
636 n.makeLatest(branch, rev, nil)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400637 return rev
638 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500639 idx, childRev := n.findRevByKey(children, field.Key, keyValue)
640 if n.GetProxy() != nil {
641 data := childRev.GetData()
642 n.GetProxy().InvokeCallbacks(PRE_REMOVE, false, data)
643 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, data, nil})
644 } else {
645 postAnnouncement = append(postAnnouncement, ChangeTuple{POST_REMOVE, childRev.GetData(), nil})
646 }
647 childRev.Drop(txid, true)
648 children = append(children[:idx], children[idx+1:]...)
649 rev := rev.UpdateChildren(name, children, branch)
650 branch.GetLatest().Drop(txid, false)
651 n.makeLatest(branch, rev, postAnnouncement)
652 return rev
653
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400654 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500655 log.Errorf("cannot add to non-keyed container")
656
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400657 } else {
Stephane Barbarie126101e2018-10-11 16:18:48 -0400658 log.Errorf("cannot add to non-container field")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400659 }
660
661 return nil
662}
663
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400664// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Branching ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
665
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500666// MakeBranchFunction is a type for function references intented to create a branch
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400667type MakeBranchFunction func(*node) *Branch
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400668
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500669// MakeBranch creates a new branch for the provided transaction id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400670func (n *node) MakeBranch(txid string) *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500671 branchPoint := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400672 branch := NewBranch(n, txid, branchPoint, true)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500673 n.SetBranch(txid, branch)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400674 return branch
675}
676
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500677// DeleteBranch removes a branch with the specified id
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400678func (n *node) DeleteBranch(txid string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500679 n.Lock()
680 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400681 delete(n.Branches, txid)
682}
683
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400684func (n *node) mergeChild(txid string, dryRun bool) func(Revision) Revision {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400685 f := func(rev Revision) Revision {
686 childBranch := rev.GetBranch()
687
688 if childBranch.Txid == txid {
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400689 rev, _ = childBranch.Node.MergeBranch(txid, dryRun)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400690 }
691
692 return rev
693 }
694 return f
695}
696
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500697// MergeBranch will integrate the contents of a transaction branch within the latest branch of a given node
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400698func (n *node) MergeBranch(txid string, dryRun bool) (Revision, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500699 srcBranch := n.GetBranch(txid)
700 dstBranch := n.GetBranch(NONE)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400701
702 forkRev := srcBranch.Origin
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500703 srcRev := srcBranch.GetLatest()
704 dstRev := dstBranch.GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400705
706 rev, changes := Merge3Way(forkRev, srcRev, dstRev, n.mergeChild(txid, dryRun), dryRun)
707
708 if !dryRun {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500709 n.makeLatest(dstBranch, rev, changes)
710 n.DeleteBranch(txid)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400711 }
712
Stephane Barbariee16186c2018-09-11 10:46:34 -0400713 // TODO: return proper error when one occurs
714 return rev, nil
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400715}
716
717// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Diff utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
718
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400719//func (n *node) diff(hash1, hash2, txid string) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400720// branch := n.Branches[txid]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500721// rev1 := branch.GetHash(hash1)
722// rev2 := branch.GetHash(hash2)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400723//
724// if rev1.GetHash() == rev2.GetHash() {
725// // empty patch
726// } else {
727// // translate data to json and generate patch
728// patch, err := jsonpatch.MakePatch(rev1.GetData(), rev2.GetData())
729// patch.
730// }
731//}
732
733// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Tag utility ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
734
735// TODO: is tag mgmt used in the python implementation? Need to validate
736
737// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Internals ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
738
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400739func (n *node) hasChildren(data interface{}) bool {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400740 for fieldName, field := range ChildrenFields(n.Type) {
741 _, fieldValue := GetAttributeValue(data, fieldName, 0)
742
743 if (field.IsContainer && fieldValue.Len() > 0) || !fieldValue.IsNil() {
744 log.Error("cannot update external children")
745 return true
746 }
747 }
748
749 return false
750}
751
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400752// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ node Proxy ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400753
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500754// CreateProxy returns a reference to a sub-tree of the data model
755func (n *node) CreateProxy(path string, exclusive bool) *Proxy {
756 return n.createProxy(path, path, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400757}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500758
759func (n *node) createProxy(path string, fullPath string, exclusive bool) *Proxy {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400760 for strings.HasPrefix(path, "/") {
761 path = path[1:]
762 }
763 if path == "" {
Stephane Barbariea188d942018-10-16 16:43:04 -0400764 return n.makeProxy(path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400765 }
766
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500767 rev := n.GetBranch(NONE).GetLatest()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400768 partition := strings.SplitN(path, "/", 2)
769 name := partition[0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400770 if len(partition) < 2 {
771 path = ""
772 } else {
773 path = partition[1]
774 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400775
776 field := ChildrenFields(n.Type)[name]
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500777 if field.IsContainer {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400778 if path == "" {
779 log.Error("cannot proxy a container field")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400780 } else if field.Key != "" {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400781 partition := strings.SplitN(path, "/", 2)
782 key := partition[0]
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400783 if len(partition) < 2 {
784 path = ""
785 } else {
786 path = partition[1]
787 }
788 keyValue := field.KeyFromStr(key)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400789 var children []Revision
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500790 children = make([]Revision, len(rev.GetChildren()[name]))
791 copy(children, rev.GetChildren()[name])
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400792 _, childRev := n.findRevByKey(children, field.Key, keyValue)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400793 childNode := childRev.GetNode()
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400794
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500795 return childNode.createProxy(path, fullPath, exclusive)
Stephane Barbarie126101e2018-10-11 16:18:48 -0400796 } else {
797 log.Error("cannot index into container with no keys")
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400798 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400799 } else {
800 childRev := rev.GetChildren()[name][0]
801 childNode := childRev.GetNode()
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500802 return childNode.createProxy(path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400803 }
804
805 return nil
806}
807
Stephane Barbariea188d942018-10-16 16:43:04 -0400808func (n *node) makeProxy(path string, fullPath string, exclusive bool) *Proxy {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500809 n.Lock()
810 defer n.Unlock()
Stephane Barbarie126101e2018-10-11 16:18:48 -0400811 r := &root{
812 node: n,
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500813 Callbacks: n.Root.GetCallbacks(),
814 NotificationCallbacks: n.Root.GetNotificationCallbacks(),
Stephane Barbarie126101e2018-10-11 16:18:48 -0400815 DirtyNodes: n.Root.DirtyNodes,
816 KvStore: n.Root.KvStore,
817 Loading: n.Root.Loading,
818 RevisionClass: n.Root.RevisionClass,
819 }
820
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400821 if n.Proxy == nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500822 n.Proxy = NewProxy(r, n, path, fullPath, exclusive)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400823 } else {
824 if n.Proxy.Exclusive {
825 log.Error("node is already owned exclusively")
826 }
827 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500828
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400829 return n.Proxy
830}
831
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400832func (n *node) makeEventBus() *EventBus {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500833 n.Lock()
834 defer n.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400835 if n.EventBus == nil {
836 n.EventBus = NewEventBus()
837 }
838 return n.EventBus
839}
840
841// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Persistence Loading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
842
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500843// LoadLatest accesses the persistent storage to construct the data model based on the stored information
Stephane Barbarie126101e2018-10-11 16:18:48 -0400844func (n *node) LoadLatest(hash string) {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400845 branch := NewBranch(n, "", nil, n.AutoPrune)
846 pr := &PersistedRevision{}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500847 rev := pr.Load(branch, n.GetRoot().KvStore, n.Type, hash)
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400848 n.makeLatest(branch, rev, nil)
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500849 n.SetBranch(NONE, branch)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400850}
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400851
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500852func (n *node) SetProxy(proxy *Proxy) {
853 n.Lock()
854 defer n.Unlock()
855 n.Proxy = proxy
856}
857
858func (n *node) GetProxy() *Proxy {
859 n.Lock()
860 defer n.Unlock()
861 return n.Proxy
862}
863
864func (n *node) GetBranch(key string) *Branch {
865 n.Lock()
866 defer n.Unlock()
867 if branch, exists := n.Branches[key]; exists {
868 return branch
869 }
870 return nil
871}
872
873func (n *node) SetBranch(key string, branch *Branch) {
874 n.Lock()
875 defer n.Unlock()
876 n.Branches[key] = branch
877}
878
879func (n *node) GetRoot() *root {
880 n.Lock()
881 defer n.Unlock()
882 return n.Root
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400883}