/
health_tracker.go
159 lines (124 loc) · 4.03 KB
/
health_tracker.go
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
package kvstore
import "github.com/iotaledger/hive.go/ierrors"
const (
// StoreVersionNone is used to load an existing store without a version check (e.g. in the tools).
StoreVersionNone byte = 0
)
type StoreVersionUpdateFunc func(oldVersion byte, newVersion byte) error
var (
ErrStoreVersionCheckNotSupported = ierrors.New("store version check not supported")
ErrStoreVersionUpdateFuncNotGiven = ierrors.New("store version update function not given")
)
type StoreHealthTracker struct {
store KVStore
storeVersion byte
storeVersionUpdateFunc StoreVersionUpdateFunc
}
func NewStoreHealthTracker(store KVStore, storePrefixHealth []byte, storeVersion byte, storeVersionUpdateFunc StoreVersionUpdateFunc) (*StoreHealthTracker, error) {
healthStore, err := store.WithRealm(storePrefixHealth)
if err != nil {
return nil, err
}
s := &StoreHealthTracker{
store: healthStore,
storeVersion: storeVersion,
storeVersionUpdateFunc: storeVersionUpdateFunc,
}
if storeVersion != StoreVersionNone {
if err := s.setStoreVersion(storeVersion); err != nil {
return nil, err
}
}
return s, nil
}
func (s *StoreHealthTracker) MarkCorrupted() error {
if err := s.store.Set([]byte("dbCorrupted"), []byte{}); err != nil {
return ierrors.New("failed to set store health status")
}
return s.store.Flush()
}
func (s *StoreHealthTracker) MarkTainted() error {
if err := s.store.Set([]byte("dbTainted"), []byte{}); err != nil {
return ierrors.New("failed to set store health status")
}
return s.store.Flush()
}
func (s *StoreHealthTracker) MarkHealthy() error {
if err := s.store.Delete([]byte("dbCorrupted")); err != nil {
return ierrors.New("failed to set store health status")
}
return nil
}
func (s *StoreHealthTracker) IsCorrupted() (bool, error) {
contains, err := s.store.Has([]byte("dbCorrupted"))
if err != nil {
return true, ierrors.New("failed to read store health status")
}
return contains, nil
}
func (s *StoreHealthTracker) IsTainted() (bool, error) {
contains, err := s.store.Has([]byte("dbTainted"))
if err != nil {
return true, ierrors.New("failed to read store health status")
}
return contains, nil
}
// StoreVersion returns the store version.
func (s *StoreHealthTracker) StoreVersion() (byte, error) {
value, err := s.store.Get([]byte("dbVersion"))
if err != nil {
return 0, ierrors.New("failed to read store health version")
}
if len(value) < 1 {
return 0, ierrors.New("failed to read store health version")
}
return value[0], nil
}
func (s *StoreHealthTracker) setStoreVersion(version byte) error {
_, err := s.store.Get([]byte("dbVersion"))
if ierrors.Is(err, ErrKeyNotFound) {
// Only create the entry, if it doesn't exist already (fresh store)
if err := s.store.Set([]byte("dbVersion"), []byte{version}); err != nil {
return ierrors.New("failed to set store health version")
}
}
return nil
}
func (s *StoreHealthTracker) CheckCorrectStoreVersion() (bool, error) {
if s.storeVersion == StoreVersionNone {
return false, ErrStoreVersionCheckNotSupported
}
storeVersion, err := s.StoreVersion()
if err != nil {
return false, err
}
return storeVersion == s.storeVersion, nil
}
// UpdateStoreVersion tries to migrate the existing data to the new store version.
// Returns true if the store needs to be updated / was updated.
func (s *StoreHealthTracker) UpdateStoreVersion() (bool, error) {
storeVersion, err := s.StoreVersion()
if err != nil {
return false, err
}
if storeVersion == s.storeVersion {
// already up to date
return false, nil
}
if s.storeVersionUpdateFunc == nil {
return true, ErrStoreVersionUpdateFuncNotGiven
}
if err := s.storeVersionUpdateFunc(storeVersion, s.storeVersion); err != nil {
return true, err
}
if err := s.store.Set([]byte("dbVersion"), []byte{s.storeVersion}); err != nil {
return true, ierrors.New("failed to set store health version")
}
return true, nil
}
func (s *StoreHealthTracker) Flush() error {
return s.store.Flush()
}
func (s *StoreHealthTracker) Close() error {
return s.store.Close()
}