blob: e93d0ff052488581269ede4828761d310a974df3 [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"
Stephane Barbarie126101e2018-10-11 16:18:48 -040022 "github.com/golang/protobuf/proto"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040023 "reflect"
24 "sort"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050025 "sync"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040026)
27
Stephane Barbariedc5022d2018-11-19 15:21:44 -050028type revCacheSingleton struct {
29 sync.RWMutex
30 Cache map[string]interface{}
31}
32
33var revCacheInstance *revCacheSingleton
34var revCacheOnce sync.Once
35
36func GetRevCache() *revCacheSingleton {
37 revCacheOnce.Do(func() {
38 revCacheInstance = &revCacheSingleton{Cache: make(map[string]interface{})}
39 })
40 return revCacheInstance
41}
Stephane Barbarieec0919b2018-09-05 14:14:29 -040042
43type NonPersistedRevision struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050044 mutex sync.RWMutex
45 Root *root
Stephane Barbarieec0919b2018-09-05 14:14:29 -040046 Config *DataRevision
47 Children map[string][]Revision
48 Hash string
49 Branch *Branch
50 WeakRef string
51}
52
Stephane Barbariedc5022d2018-11-19 15:21:44 -050053func NewNonPersistedRevision(root *root, branch *Branch, data interface{}, children map[string][]Revision) Revision {
54 r := &NonPersistedRevision{}
55 r.Root = root
56 r.Branch = branch
57 r.Config = NewDataRevision(root, data)
58 r.Children = children
Stephane Barbariedc5022d2018-11-19 15:21:44 -050059 return r
Stephane Barbarieec0919b2018-09-05 14:14:29 -040060}
61
62func (npr *NonPersistedRevision) SetConfig(config *DataRevision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050063 npr.mutex.Lock()
64 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040065 npr.Config = config
66}
67
68func (npr *NonPersistedRevision) GetConfig() *DataRevision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050069 npr.mutex.Lock()
70 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040071 return npr.Config
72}
73
74func (npr *NonPersistedRevision) SetChildren(children map[string][]Revision) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050075 npr.mutex.Lock()
76 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040077 npr.Children = children
78}
79
80func (npr *NonPersistedRevision) GetChildren() map[string][]Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050081 npr.mutex.Lock()
82 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040083 return npr.Children
84}
85
86func (npr *NonPersistedRevision) SetHash(hash string) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050087 npr.mutex.Lock()
88 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040089 npr.Hash = hash
90}
91
92func (npr *NonPersistedRevision) GetHash() string {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050093 //npr.mutex.Lock()
94 //defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -040095 return npr.Hash
96}
97
98func (npr *NonPersistedRevision) ClearHash() {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050099 npr.mutex.Lock()
100 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400101 npr.Hash = ""
102}
103
104func (npr *NonPersistedRevision) SetBranch(branch *Branch) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500105 npr.mutex.Lock()
106 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400107 npr.Branch = branch
108}
109
110func (npr *NonPersistedRevision) GetBranch() *Branch {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500111 npr.mutex.Lock()
112 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400113 return npr.Branch
114}
115
116func (npr *NonPersistedRevision) GetData() interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500117 npr.mutex.Lock()
118 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400119 if npr.Config == nil {
120 return nil
121 }
122 return npr.Config.Data
123}
124
Stephane Barbarie06c4a742018-10-01 11:09:32 -0400125func (npr *NonPersistedRevision) GetNode() *node {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500126 npr.mutex.Lock()
127 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400128 return npr.Branch.Node
129}
130
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500131func (npr *NonPersistedRevision) Finalize(skipOnExist bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500132 GetRevCache().Lock()
133 defer GetRevCache().Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400134
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500135 npr.Hash = npr.hashContent()
136
137 if _, exists := GetRevCache().Cache[npr.Hash]; !exists {
138 GetRevCache().Cache[npr.Hash] = npr
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400139 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500140 if _, exists := GetRevCache().Cache[npr.Config.Hash]; !exists {
141 GetRevCache().Cache[npr.Config.Hash] = npr.Config
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400142 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500143 npr.Config = GetRevCache().Cache[npr.Config.Hash].(*DataRevision)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400144 }
145}
146
147func (npr *NonPersistedRevision) hashContent() string {
148 var buffer bytes.Buffer
149 var childrenKeys []string
150
151 if npr.Config != nil {
152 buffer.WriteString(npr.Config.Hash)
153 }
154
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500155 for key := range npr.Children {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400156 childrenKeys = append(childrenKeys, key)
157 }
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500158
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400159 sort.Strings(childrenKeys)
160
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500161 if len(npr.Children) > 0 {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400162 // Loop through sorted Children keys
163 for _, key := range childrenKeys {
164 for _, child := range npr.Children[key] {
165 if child != nil && child.GetHash() != "" {
166 buffer.WriteString(child.GetHash())
167 }
168 }
169 }
170 }
171
172 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
173}
174
175func (npr *NonPersistedRevision) Get(depth int) interface{} {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500176 // 1. Clone the data to avoid any concurrent access issues
177 // 2. The current rev might still be pointing to an old config
178 // thus, force the revision to get its latest value
179 latestRev := npr.GetBranch().GetLatest()
180 originalData := proto.Clone(latestRev.GetData().(proto.Message))
181
182 data := originalData
183 // Get back to the interface type
184 //data := reflect.ValueOf(originalData).Interface()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400185
186 if depth != 0 {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500187 for fieldName, field := range ChildrenFields(latestRev.GetData()) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400188 childDataName, childDataHolder := GetAttributeValue(data, fieldName, 0)
189 if field.IsContainer {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500190 for _, rev := range latestRev.GetChildren()[fieldName] {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400191 childData := rev.Get(depth - 1)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400192 foundEntry := false
193 for i := 0; i < childDataHolder.Len(); i++ {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500194 cdh_if := childDataHolder.Index(i).Interface()
195 if cdh_if.(proto.Message).String() == childData.(proto.Message).String() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400196 foundEntry = true
197 break
198 }
199 }
200 if !foundEntry {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500201 // avoid duplicates by adding it only if the child was not found in the holder
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400202 childDataHolder = reflect.Append(childDataHolder, reflect.ValueOf(childData))
203 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400204 }
205 } else {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500206 if revs := latestRev.GetChildren()[fieldName]; revs != nil && len(revs) > 0 {
207 rev := latestRev.GetChildren()[fieldName][0]
Stephane Barbarie126101e2018-10-11 16:18:48 -0400208 if rev != nil {
209 childData := rev.Get(depth - 1)
210 if reflect.TypeOf(childData) == reflect.TypeOf(childDataHolder.Interface()) {
211 childDataHolder = reflect.ValueOf(childData)
212 }
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400213 }
214 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400215 }
216 // Merge child data with cloned object
217 reflect.ValueOf(data).Elem().FieldByName(childDataName).Set(childDataHolder)
218 }
219 }
Stephane Barbarie126101e2018-10-11 16:18:48 -0400220
221 result := data
222
223 if result != nil {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500224 // We need to send back a copy of the retrieved object
225 result = proto.Clone(data.(proto.Message))
Stephane Barbarie126101e2018-10-11 16:18:48 -0400226 }
227
228 return result
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400229}
230
231func (npr *NonPersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500232 npr.mutex.Lock()
233 defer npr.mutex.Unlock()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400234
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500235 newRev := NonPersistedRevision{}
236 newRev.Config = NewDataRevision(npr.Root, data)
237 newRev.Hash = npr.Hash
238 newRev.Branch = branch
239
240 newRev.Children = make(map[string][]Revision)
241 for entryName, childrenEntry := range npr.Children {
242 newRev.Children[entryName] = append(newRev.Children[entryName], childrenEntry...)
243 }
244
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500245 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400246
247 return &newRev
248}
249
250func (npr *NonPersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500251 npr.mutex.Lock()
252 defer npr.mutex.Unlock()
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400253
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500254 newRev := NonPersistedRevision{}
255 newRev.Children = make(map[string][]Revision)
256 for entryName, childrenEntry := range npr.Children {
257 newRev.Children[entryName] = make([]Revision, len(childrenEntry))
258 copy(newRev.Children[entryName], childrenEntry)
259 }
260
261 newRev.Children[name] = make([]Revision, len(children))
262 copy(newRev.Children[name], children)
263
264 newRev.Config = NewDataRevision(npr.Root, npr.Config.Data)
265 newRev.Hash = npr.Hash
266 newRev.Branch = branch
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500267 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400268
269 return &newRev
270}
271
272func (npr *NonPersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500273 npr.mutex.Lock()
274 defer npr.mutex.Unlock()
275
276 newRev := &NonPersistedRevision{}
277 newRev.Config = npr.Config
278 newRev.Hash = npr.Hash
279 newRev.Branch = branch
280 newRev.Children = make(map[string][]Revision)
281 for entryName, childrenEntry := range npr.Children {
282 newRev.Children[entryName] = make([]Revision, len(childrenEntry))
283 copy(newRev.Children[entryName], childrenEntry)
284 }
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500285 newRev.Finalize(false)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400286
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500287 return newRev
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400288}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400289
290func (npr *NonPersistedRevision) Drop(txid string, includeConfig bool) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500291 GetRevCache().Lock()
292 defer GetRevCache().Unlock()
293
294 npr.mutex.Lock()
295 defer npr.mutex.Unlock()
296
297 if includeConfig {
298 delete(GetRevCache().Cache, npr.Config.Hash)
299 }
300 delete(GetRevCache().Cache, npr.Hash)
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400301}
Stephane Barbarie1ab43272018-12-08 21:42:13 -0500302
303func (npr *NonPersistedRevision) LoadFromPersistence(path string, txid string) []Revision {
304 return nil
305}