blob: 81d356363cd940cc9715e7222e154c75fb016454 [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"
22 "fmt"
23 "github.com/golang/protobuf/proto"
24 "io/ioutil"
25 "reflect"
26)
27
28type PersistedRevision struct {
29 *Revision
30 Compress bool
31 kvStore *Backend
32}
33
34func NewPersistedRevision(branch *Branch, data interface{}, children map[string][]*Revision) *PersistedRevision {
35 pr := &PersistedRevision{}
36 pr.kvStore = branch.node.root.KvStore
37 pr.Revision = NewRevision(branch, data, children)
38 return pr
39}
40
41func (pr *PersistedRevision) finalize() {
42 pr.Revision.finalize()
43 pr.store()
44}
45
46type revData struct {
47 Children map[string][]string
48 Config string
49}
50
51func (pr *PersistedRevision) store() {
52 if ok, _ := pr.kvStore.Get(pr.Revision.Hash); ok != nil {
53 return
54 }
55
56 pr.storeConfig()
57
58 childrenHashes := make(map[string][]string)
59 for fieldName, children := range pr.Children {
60 hashes := []string{}
61 for _, rev := range children {
62 hashes = append(hashes, rev.Hash)
63 }
64 childrenHashes[fieldName] = hashes
65 }
66 data := &revData{
67 Children: childrenHashes,
68 Config: pr.Config.Hash,
69 }
70 if blob, err := json.Marshal(data); err != nil {
71 // TODO report error
72 } else {
73 if pr.Compress {
74 var b bytes.Buffer
75 w := gzip.NewWriter(&b)
76 w.Write(blob)
77 w.Close()
78 blob = b.Bytes()
79 }
80 pr.kvStore.Put(pr.Hash, blob)
81 }
82}
83
84func (pr *PersistedRevision) load(branch *Branch, kvStore *Backend, msgClass interface{}, hash string) *PersistedRevision {
85 blob, _ := kvStore.Get(hash)
86 output := blob.Value.([]byte)
87 var data revData
88 if pr.Compress {
89 b := bytes.NewBuffer(blob.Value.([]byte))
90 if r, err := gzip.NewReader(b); err != nil {
91 // TODO : report error
92 } else {
93 if output, err = ioutil.ReadAll(r); err != nil {
94 // TODO report error
95 }
96 }
97 }
98 if err := json.Unmarshal(output, &data); err != nil {
99 fmt.Errorf("problem to unmarshal data - %s", err.Error())
100 }
101
102 configHash := data.Config
103 configData := pr.loadConfig(kvStore, msgClass, configHash)
104 assembledChildren := make(map[string][]*Revision)
105
106 childrenHashes := data.Children
107 node := branch.node
108 for fieldName, child := range ChildrenFields(msgClass) {
109 var children []*Revision
110 for _, childHash := range childrenHashes[fieldName] {
111 //fmt.Printf("child class type: %+v", reflect.New(n).Elem().Interface())
112 childNode := node.makeNode(reflect.New(child.ClassType).Elem().Interface(), "")
113 childNode.LoadLatest(kvStore, childHash)
114 childRev := childNode.Latest()
115 children = append(children, childRev)
116 }
117 assembledChildren[fieldName] = children
118 }
119 rev := NewPersistedRevision(branch, configData, assembledChildren)
120 return rev
121}
122
123func (pr *PersistedRevision) storeConfig() {
124 if ok, _ := pr.kvStore.Get(pr.Config.Hash); ok != nil {
125 return
126 }
127 if blob, err := proto.Marshal(pr.Config.Data.(proto.Message)); err != nil {
128 // TODO report error
129 } else {
130 if pr.Compress {
131 var b bytes.Buffer
132 w := gzip.NewWriter(&b)
133 w.Write(blob)
134 w.Close()
135 blob = b.Bytes()
136 }
137 pr.kvStore.Put(pr.Config.Hash, blob)
138 }
139}
140
141func (pr *PersistedRevision) loadConfig(kvStore *Backend, msgClass interface{}, hash string) interface{} {
142 blob, _ := kvStore.Get(hash)
143 output := blob.Value.([]byte)
144
145 if pr.Compress {
146 b := bytes.NewBuffer(blob.Value.([]byte))
147 if r, err := gzip.NewReader(b); err != nil {
148 // TODO : report error
149 } else {
150 if output, err = ioutil.ReadAll(r); err != nil {
151 // TODO report error
152 }
153 }
154 }
155
156 var data reflect.Value
157 if msgClass != nil {
158 data = reflect.New(reflect.TypeOf(msgClass).Elem())
159 if err := proto.Unmarshal(output, data.Interface().(proto.Message)); err != nil {
160 // TODO report error
161 }
162 }
163
164 return data.Interface()
165}