blob: b62c569a869430c8fbc78e350bd008d058472919 [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 Barbarie4a2564d2018-07-26 11:02:58 -040016package model
17
18import (
19 "bytes"
20 "compress/gzip"
21 "encoding/json"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040022 "github.com/golang/protobuf/proto"
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -040023 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040024 "io/ioutil"
25 "reflect"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040026 "time"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027)
28
29type PersistedRevision struct {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040030 Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040031 Compress bool
32 kvStore *Backend
33}
34
Stephane Barbarieec0919b2018-09-05 14:14:29 -040035func NewPersistedRevision(branch *Branch, data interface{}, children map[string][]Revision) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040036 pr := &PersistedRevision{}
Stephane Barbarie126101e2018-10-11 16:18:48 -040037 pr.kvStore = branch.Node.Root.KvStore
Stephane Barbarieec0919b2018-09-05 14:14:29 -040038 pr.Revision = NewNonPersistedRevision(branch, data, children)
39 pr.Finalize()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040040 return pr
41}
42
Stephane Barbarieec0919b2018-09-05 14:14:29 -040043func (pr *PersistedRevision) Finalize() {
44 //pr.Revision.Finalize()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040045 pr.store()
46}
47
48type revData struct {
49 Children map[string][]string
50 Config string
51}
52
53func (pr *PersistedRevision) store() {
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -040054 if pr.GetBranch().Txid != "" {
55 return
56 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -040057 if ok, _ := pr.kvStore.Get(pr.Revision.GetHash()); ok != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040058 return
59 }
60
61 pr.storeConfig()
62
63 childrenHashes := make(map[string][]string)
Stephane Barbarieec0919b2018-09-05 14:14:29 -040064 for fieldName, children := range pr.GetChildren() {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040065 hashes := []string{}
66 for _, rev := range children {
Stephane Barbarie126101e2018-10-11 16:18:48 -040067 if rev != nil {
68 hashes = append(hashes, rev.GetHash())
69 }
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040070 }
71 childrenHashes[fieldName] = hashes
72 }
73 data := &revData{
74 Children: childrenHashes,
Stephane Barbarieec0919b2018-09-05 14:14:29 -040075 Config: pr.GetConfig().Hash,
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040076 }
77 if blob, err := json.Marshal(data); err != nil {
78 // TODO report error
79 } else {
80 if pr.Compress {
81 var b bytes.Buffer
82 w := gzip.NewWriter(&b)
83 w.Write(blob)
84 w.Close()
85 blob = b.Bytes()
86 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -040087 pr.kvStore.Put(pr.GetHash(), blob)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040088 }
89}
90
Stephane Barbarieec0919b2018-09-05 14:14:29 -040091func (pr *PersistedRevision) Load(branch *Branch, kvStore *Backend, msgClass interface{}, hash string) Revision {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040092 blob, _ := kvStore.Get(hash)
Stephane Barbarieec0919b2018-09-05 14:14:29 -040093
94 start := time.Now()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040095 output := blob.Value.([]byte)
96 var data revData
97 if pr.Compress {
98 b := bytes.NewBuffer(blob.Value.([]byte))
99 if r, err := gzip.NewReader(b); err != nil {
100 // TODO : report error
101 } else {
102 if output, err = ioutil.ReadAll(r); err != nil {
103 // TODO report error
104 }
105 }
106 }
107 if err := json.Unmarshal(output, &data); err != nil {
Stephane Barbarie8c48b5c2018-10-02 09:45:17 -0400108 log.Errorf("problem to unmarshal data - %s", err.Error())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400109 }
110
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400111 stop := time.Now()
112 GetProfiling().AddToInMemoryModelTime(stop.Sub(start).Seconds())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400113 configHash := data.Config
114 configData := pr.loadConfig(kvStore, msgClass, configHash)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400115
116 assembledChildren := make(map[string][]Revision)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400117
118 childrenHashes := data.Children
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400119 node := branch.Node
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400120 for fieldName, child := range ChildrenFields(msgClass) {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400121 var children []Revision
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400122 for _, childHash := range childrenHashes[fieldName] {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400123 childNode := node.MakeNode(reflect.New(child.ClassType).Elem().Interface(), "")
Stephane Barbarie126101e2018-10-11 16:18:48 -0400124 childNode.LoadLatest(childHash)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400125 childRev := childNode.Latest()
126 children = append(children, childRev)
127 }
128 assembledChildren[fieldName] = children
129 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400130
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400131 rev := NewPersistedRevision(branch, configData, assembledChildren)
132 return rev
133}
134
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400135func (pr *PersistedRevision) assignValue(a, b Revision) Revision {
136 a = b
137 return a
138}
139
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400140func (pr *PersistedRevision) storeConfig() {
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400141 if ok, _ := pr.kvStore.Get(pr.GetConfig().Hash); ok != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400142 return
143 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400144 if blob, err := proto.Marshal(pr.GetConfig().Data.(proto.Message)); err != nil {
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400145 // TODO report error
146 } else {
147 if pr.Compress {
148 var b bytes.Buffer
149 w := gzip.NewWriter(&b)
150 w.Write(blob)
151 w.Close()
152 blob = b.Bytes()
153 }
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400154 pr.kvStore.Put(pr.GetConfig().Hash, blob)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400155 }
156}
157
158func (pr *PersistedRevision) loadConfig(kvStore *Backend, msgClass interface{}, hash string) interface{} {
159 blob, _ := kvStore.Get(hash)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400160 start := time.Now()
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400161 output := blob.Value.([]byte)
162
163 if pr.Compress {
164 b := bytes.NewBuffer(blob.Value.([]byte))
165 if r, err := gzip.NewReader(b); err != nil {
166 // TODO : report error
167 } else {
168 if output, err = ioutil.ReadAll(r); err != nil {
169 // TODO report error
170 }
171 }
172 }
173
174 var data reflect.Value
175 if msgClass != nil {
176 data = reflect.New(reflect.TypeOf(msgClass).Elem())
177 if err := proto.Unmarshal(output, data.Interface().(proto.Message)); err != nil {
178 // TODO report error
179 }
180 }
181
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400182 stop := time.Now()
183
184 GetProfiling().AddToInMemoryModelTime(stop.Sub(start).Seconds())
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400185 return data.Interface()
186}
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400187
188func (pr *PersistedRevision) UpdateData(data interface{}, branch *Branch) Revision {
189 newNPR := pr.Revision.UpdateData(data, branch)
190
191 newPR := &PersistedRevision{
192 Revision: newNPR,
193 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400194 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400195 }
196
197 newPR.Finalize()
198
199 return newPR
200}
201
202func (pr *PersistedRevision) UpdateChildren(name string, children []Revision, branch *Branch) Revision {
203 newNPR := pr.Revision.UpdateChildren(name, children, branch)
204
205 newPR := &PersistedRevision{
206 Revision: newNPR,
207 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400208 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400209 }
210
211 newPR.Finalize()
212
213 return newPR
214}
215
216func (pr *PersistedRevision) UpdateAllChildren(children map[string][]Revision, branch *Branch) Revision {
217 newNPR := pr.Revision.UpdateAllChildren(children, branch)
218
219 newPR := &PersistedRevision{
220 Revision: newNPR,
221 Compress: pr.Compress,
khenaidoob9203542018-09-17 22:56:37 -0400222 kvStore: pr.kvStore,
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400223 }
224
225 newPR.Finalize()
226
227 return newPR
228}
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400229
230// Drop takes care of eliminating a revision hash that is no longer needed
231// and its associated config when required
232func (pr *PersistedRevision) Drop(txid string, includeConfig bool) {
233 if pr.kvStore != nil && txid == "" {
234 if includeConfig {
235 log.Debugf("removing rev config - hash: %s", pr.GetConfig().Hash)
236 if err := pr.kvStore.Delete(pr.GetConfig().Hash); err != nil {
237 log.Errorf(
238 "failed to remove rev config - hash: %s, err: %s",
239 pr.GetConfig().Hash,
240 err.Error(),
241 )
242 }
243 }
244
245 log.Debugf("removing rev - hash: %s", pr.GetHash())
246 if err := pr.kvStore.Delete(pr.GetHash()); err != nil {
247 log.Errorf("failed to remove rev - hash: %s, err: %s", pr.GetHash(), err.Error())
248 }
249 } else {
250 if includeConfig {
251 log.Debugf("Attempted to remove revision config:%s linked to transaction:%s", pr.GetConfig().Hash, txid)
252 }
253 log.Debugf("Attempted to remove revision:%s linked to transaction:%s", pr.GetHash(), txid)
254 }
255}