blob: 99166e58a508531b78ad4037fb721ea4c9e97525 [file] [log] [blame]
Stephane Barbarieec0919b2018-09-05 14:14: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 */
16package model
17
18import (
19 "bytes"
20 "crypto/md5"
21 "fmt"
khenaidoob9203542018-09-17 22:56:37 -040022 "github.com/opencord/voltha-go/common/log"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040023 "reflect"
24 "sort"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040025)
26
27var (
28 RevisionCache = make(map[string]interface{})
29)
30
31type NonPersistedRevision struct {
32 Config *DataRevision
33 Children map[string][]Revision
34 Hash string
35 Branch *Branch
36 WeakRef string
37}
38
39func NewNonPersistedRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
40 cr := &NonPersistedRevision{}
41 cr.Branch = branch
42 cr.Config = NewDataRevision(data)
43 cr.Children = children
44 cr.Finalize()
45
46 return cr
47}
48
49func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
50 npr.Config = config
51}
52
53func (npr *NonPersistedRevision) GetConfig() *DataRevision {
54 return npr.Config
55}
56
57func (npr *NonPersistedRevision) SetChildren(children map[string][]Revision) {
58 npr.Children = children
59}
60
61func (npr *NonPersistedRevision) GetChildren() map[string][]Revision {
62 return npr.Children
63}
64
65func (npr *NonPersistedRevision) SetHash(hash string) {
66 npr.Hash = hash
67}
68
69func (npr *NonPersistedRevision) GetHash() string {
70 return npr.Hash
71}
72
73func (npr *NonPersistedRevision) ClearHash() {
74 npr.Hash = ""
75}
76
77func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
78 npr.Branch = branch
79}
80
81func (npr *NonPersistedRevision) GetBranch() *Branch {
82 return npr.Branch
83}
84
85func (npr *NonPersistedRevision) GetData() interface{} {
86 if npr.Config == nil {
87 return nil
88 }
89 return npr.Config.Data
90}
91
Stephane Barbarie06c4a742018-10-01 11:09:32 -040092func (npr *NonPersistedRevision) GetNode() *node {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040093 return npr.Branch.Node
94}
95
96func (npr *NonPersistedRevision) Finalize() {
97 npr.SetHash(npr.hashContent())
98
99 if _, exists := RevisionCache[npr.Hash]; !exists {
100 RevisionCache[npr.Hash] = npr
101 }
102 if _, exists := RevisionCache[npr.Config.Hash]; !exists {
103 RevisionCache[npr.Config.Hash] = npr.Config
104 } else {
105 npr.Config = RevisionCache[npr.Config.Hash].(*DataRevision)
106 }
107}
108
109func (npr *NonPersistedRevision) hashContent() string {
110 var buffer bytes.Buffer
111 var childrenKeys []string
112
113 if npr.Config != nil {
114 buffer.WriteString(npr.Config.Hash)
115 }
116
117 for key, _ := range npr.Children {
118 childrenKeys = append(childrenKeys, key)
119 }
120 sort.Strings(childrenKeys)
121
122 if npr.Children != nil && len(npr.Children) > 0 {
123 // Loop through sorted Children keys
124 for _, key := range childrenKeys {
125 for _, child := range npr.Children[key] {
126 if child != nil && child.GetHash() != "" {
127 buffer.WriteString(child.GetHash())
128 }
129 }
130 }
131 }
132
133 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
134}
135
136func (npr *NonPersistedRevision) Get(depth int) interface{} {
137 originalData := npr.GetData()
138 data := reflect.ValueOf(originalData).Interface()
139
140 if depth != 0 {
141 for fieldName, field := range ChildrenFields(npr.GetData()) {
142 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
143 if field.IsContainer {
144 for _, rev := range npr.Children[fieldName] {
145 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400146 foundEntry := false
147 for i := 0; i < childDataHolder.Len(); i++ {
148 if reflect.DeepEqual(childDataHolder.Index(i).Interface(), childData) {
149 foundEntry = true
150 break
151 }
152 }
153 if !foundEntry {
154 // avoid duplicates by adding if the child was not found in the holder
155 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
156 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400157 }
158 } else {
159 rev := npr.Children[fieldName][0]
160 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400161 foundEntry := false
162 for i := 0; i < childDataHolder.Len(); i++ {
163 if reflect.DeepEqual(childDataHolder.Index(i).Interface(), childData) {
164 foundEntry = true
165 break
166 }
167 }
168 if !foundEntry {
169 // avoid duplicates by adding if the child was not found in the holder
170 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
171 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400172 }
173 // Merge child data with cloned object
174 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
175 }
176 }
177 return data
178}
179
180func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400181 // TODO: Need to keep the hash for the old revision.
182 // TODO: This will allow us to get rid of the unnecessary data
183
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400184 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
185 newRev.SetBranch(branch)
186 log.Debugf("newRev config : %+v, npr: %+v", newRev.GetConfig(), npr)
187 newRev.SetConfig(NewDataRevision(data))
188 newRev.Finalize()
189
190 return &newRev
191}
192
193func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
194 newChildren := make(map[string][]Revision)
195 for entryName, childrenEntry := range npr.Children {
196 for _, revisionEntry := range childrenEntry {
197 newEntry := reflect.ValueOf(revisionEntry).Interface().(Revision)
198 newChildren[entryName] = append(newChildren[entryName], newEntry)
199 }
200 }
201 newChildren[name] = children
202
203 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
204 newRev.SetBranch(branch)
205 newRev.SetChildren(newChildren)
206 newRev.Finalize()
207
208 return &newRev
209}
210
211func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariee16186c2018-09-11 10:46:34 -0400212 newRev := reflect.ValueOf(npr).Elem().Interface().(NonPersistedRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400213 newRev.SetBranch(branch)
214 newRev.SetChildren(children)
215 newRev.Finalize()
216
217 return &newRev
218}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400219
220func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
221 //npr.SetConfig(nil)
222}