-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathpersistent.go
More file actions
165 lines (127 loc) · 5.74 KB
/
Copy pathpersistent.go
File metadata and controls
165 lines (127 loc) · 5.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/*
* Copyright 2020, 2021, 2022 Hewlett Packard Enterprise Development LP
* Other additional copyright holders may be indicated within.
*
* The entirety of this work is licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package nnf
import (
logr "github.com/sirupsen/logrus"
"github.com/NearNodeFlash/nnf-ec/pkg/persistent"
)
// Persistent Controller API provides an interface for creating, updating, and deleting persistent objects.
type PersistentControllerApi interface {
CreatePersistentObject(obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error
UpdatePersistentObject(obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error
DeletePersistentObject(obj PersistentObjectApi, deleteFunc func() error, startingState, endingState uint32) error
}
type DefaultPersistentController struct{}
func NewDefaultPersistentController() PersistentControllerApi {
return &DefaultPersistentController{}
}
// Persistent Store Provider provides an interface for supplying a Key-Value Store
type PersistentStoreProvider interface {
GetStore() *persistent.Store
}
// Persistent Object API provides interface for creating or updating a persistent object.
type PersistentObjectApi interface {
GetKey() string
GetProvider() PersistentStoreProvider
// GenerateMetadata will generate the metadata when a new persistent object is created. Metadata does not change
// over the object lifetime.
GenerateMetadata() ([]byte, error)
// GenerateStateData is called when any transaction occurs on the persistent object. Usually this is for occurances
// of Entry State and Exit State, where upon a call to CreatePersistentObject or UpdatePersistentObject, the object
// can store state data for either the Starting state or Ending state
GenerateStateData(state uint32) ([]byte, error)
// Rollback occurs when a call to CreatePersistentObject or UpdatePersistentObject fails. We rollback to the
// starting state.
Rollback(startingState uint32) error
}
func (*DefaultPersistentController) CreatePersistentObject(obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error {
metadata, err := obj.GenerateMetadata()
if err != nil {
return err
}
ledger, err := obj.GetProvider().GetStore().NewKey(obj.GetKey(), metadata)
if err != nil {
return err
}
err = executePersistentObjectTransaction(ledger, obj, updateFunc, startingState, endingState)
if closeErr := ledger.Close(err != nil); closeErr != nil {
// If the ledger fails to close we have lost the state of the resource and our only choice is to panic;
panic(closeErr)
}
return err
}
func (*DefaultPersistentController) UpdatePersistentObject(obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error {
ledger, err := obj.GetProvider().GetStore().OpenKey(obj.GetKey())
if err != nil {
return err
}
defer ledger.Close(false)
return executePersistentObjectTransaction(ledger, obj, updateFunc, startingState, endingState)
}
func (*DefaultPersistentController) DeletePersistentObject(obj PersistentObjectApi, deleteFunc func() error, startingState, endingState uint32) error {
ledger, err := obj.GetProvider().GetStore().OpenKey(obj.GetKey())
if err != nil {
return err
}
if err := executePersistentObjectTransaction(ledger, obj, deleteFunc, startingState, endingState); err != nil {
return err
}
return ledger.Close(true)
}
func executePersistentObjectTransaction(ledger *persistent.Ledger, obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error {
data, err := obj.GenerateStateData(startingState)
if err != nil {
logr.WithError(err).Warnf("Object %s failed to generate starting state %d data", obj.GetKey(), startingState)
return err
}
if err := ledger.Log(startingState, data); err != nil {
logr.WithError(err).Warnf("Object %s failed to log starting state %d", obj.GetKey(), startingState)
return err
}
if err := updateFunc(); err != nil {
logr.WithError(err).Warnf("Object %s failed update to state %d", obj.GetKey(), startingState)
if rollbackErr := obj.Rollback(startingState); rollbackErr != nil {
logr.WithError(rollbackErr).Errorf("Object %s failed rollback to state %d", obj.GetKey(), startingState)
}
return err
}
data, err = obj.GenerateStateData(endingState)
if err != nil {
logr.WithError(err).Warnf("Object %s failed to generate ending state %d data", obj.GetKey(), endingState)
return err
}
if err := ledger.Log(endingState, data); err != nil {
logr.WithError(err).Warnf("Object %s failed to log ending state %d", obj.GetKey(), endingState)
return err
}
return nil
}
type MockPersistentController struct{}
func NewMockPersistentController() PersistentControllerApi {
return &MockPersistentController{}
}
func (*MockPersistentController) CreatePersistentObject(obj PersistentObjectApi, createFunc func() error, startingState, endingState uint32) error {
return createFunc()
}
func (*MockPersistentController) UpdatePersistentObject(obj PersistentObjectApi, updateFunc func() error, startingState, endingState uint32) error {
return updateFunc()
}
func (*MockPersistentController) DeletePersistentObject(obj PersistentObjectApi, deleteFunc func() error, startingState, endingState uint32) error {
return deleteFunc()
}