1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package raft
16
17 import (
18 "errors"
19 "sync"
20
21 pb "go.etcd.io/etcd/raft/v3/raftpb"
22 )
23
24
25
26 var ErrCompacted = errors.New("requested index is unavailable due to compaction")
27
28
29
30 var ErrSnapOutOfDate = errors.New("requested index is older than the existing snapshot")
31
32
33
34 var ErrUnavailable = errors.New("requested entry at index is unavailable")
35
36
37
38 var ErrSnapshotTemporarilyUnavailable = errors.New("snapshot is temporarily unavailable")
39
40
41
42
43
44
45
46 type Storage interface {
47
48
49
50 InitialState() (pb.HardState, pb.ConfState, error)
51
52
53
54 Entries(lo, hi, maxSize uint64) ([]pb.Entry, error)
55
56
57
58
59 Term(i uint64) (uint64, error)
60
61 LastIndex() (uint64, error)
62
63
64
65
66 FirstIndex() (uint64, error)
67
68
69
70
71 Snapshot() (pb.Snapshot, error)
72 }
73
74
75
76 type MemoryStorage struct {
77
78
79
80 sync.Mutex
81
82 hardState pb.HardState
83 snapshot pb.Snapshot
84
85 ents []pb.Entry
86 }
87
88
89 func NewMemoryStorage() *MemoryStorage {
90 return &MemoryStorage{
91
92 ents: make([]pb.Entry, 1),
93 }
94 }
95
96
97 func (ms *MemoryStorage) InitialState() (pb.HardState, pb.ConfState, error) {
98 return ms.hardState, ms.snapshot.Metadata.ConfState, nil
99 }
100
101
102 func (ms *MemoryStorage) SetHardState(st pb.HardState) error {
103 ms.Lock()
104 defer ms.Unlock()
105 ms.hardState = st
106 return nil
107 }
108
109
110 func (ms *MemoryStorage) Entries(lo, hi, maxSize uint64) ([]pb.Entry, error) {
111 ms.Lock()
112 defer ms.Unlock()
113 offset := ms.ents[0].Index
114 if lo <= offset {
115 return nil, ErrCompacted
116 }
117 if hi > ms.lastIndex()+1 {
118 getLogger().Panicf("entries' hi(%d) is out of bound lastindex(%d)", hi, ms.lastIndex())
119 }
120
121 if len(ms.ents) == 1 {
122 return nil, ErrUnavailable
123 }
124
125 ents := ms.ents[lo-offset : hi-offset]
126 return limitSize(ents, maxSize), nil
127 }
128
129
130 func (ms *MemoryStorage) Term(i uint64) (uint64, error) {
131 ms.Lock()
132 defer ms.Unlock()
133 offset := ms.ents[0].Index
134 if i < offset {
135 return 0, ErrCompacted
136 }
137 if int(i-offset) >= len(ms.ents) {
138 return 0, ErrUnavailable
139 }
140 return ms.ents[i-offset].Term, nil
141 }
142
143
144 func (ms *MemoryStorage) LastIndex() (uint64, error) {
145 ms.Lock()
146 defer ms.Unlock()
147 return ms.lastIndex(), nil
148 }
149
150 func (ms *MemoryStorage) lastIndex() uint64 {
151 return ms.ents[0].Index + uint64(len(ms.ents)) - 1
152 }
153
154
155 func (ms *MemoryStorage) FirstIndex() (uint64, error) {
156 ms.Lock()
157 defer ms.Unlock()
158 return ms.firstIndex(), nil
159 }
160
161 func (ms *MemoryStorage) firstIndex() uint64 {
162 return ms.ents[0].Index + 1
163 }
164
165
166 func (ms *MemoryStorage) Snapshot() (pb.Snapshot, error) {
167 ms.Lock()
168 defer ms.Unlock()
169 return ms.snapshot, nil
170 }
171
172
173
174 func (ms *MemoryStorage) ApplySnapshot(snap pb.Snapshot) error {
175 ms.Lock()
176 defer ms.Unlock()
177
178
179 msIndex := ms.snapshot.Metadata.Index
180 snapIndex := snap.Metadata.Index
181 if msIndex >= snapIndex {
182 return ErrSnapOutOfDate
183 }
184
185 ms.snapshot = snap
186 ms.ents = []pb.Entry{{Term: snap.Metadata.Term, Index: snap.Metadata.Index}}
187 return nil
188 }
189
190
191
192
193
194 func (ms *MemoryStorage) CreateSnapshot(i uint64, cs *pb.ConfState, data []byte) (pb.Snapshot, error) {
195 ms.Lock()
196 defer ms.Unlock()
197 if i <= ms.snapshot.Metadata.Index {
198 return pb.Snapshot{}, ErrSnapOutOfDate
199 }
200
201 offset := ms.ents[0].Index
202 if i > ms.lastIndex() {
203 getLogger().Panicf("snapshot %d is out of bound lastindex(%d)", i, ms.lastIndex())
204 }
205
206 ms.snapshot.Metadata.Index = i
207 ms.snapshot.Metadata.Term = ms.ents[i-offset].Term
208 if cs != nil {
209 ms.snapshot.Metadata.ConfState = *cs
210 }
211 ms.snapshot.Data = data
212 return ms.snapshot, nil
213 }
214
215
216
217
218 func (ms *MemoryStorage) Compact(compactIndex uint64) error {
219 ms.Lock()
220 defer ms.Unlock()
221 offset := ms.ents[0].Index
222 if compactIndex <= offset {
223 return ErrCompacted
224 }
225 if compactIndex > ms.lastIndex() {
226 getLogger().Panicf("compact %d is out of bound lastindex(%d)", compactIndex, ms.lastIndex())
227 }
228
229 i := compactIndex - offset
230 ents := make([]pb.Entry, 1, 1+uint64(len(ms.ents))-i)
231 ents[0].Index = ms.ents[i].Index
232 ents[0].Term = ms.ents[i].Term
233 ents = append(ents, ms.ents[i+1:]...)
234 ms.ents = ents
235 return nil
236 }
237
238
239
240
241 func (ms *MemoryStorage) Append(entries []pb.Entry) error {
242 if len(entries) == 0 {
243 return nil
244 }
245
246 ms.Lock()
247 defer ms.Unlock()
248
249 first := ms.firstIndex()
250 last := entries[0].Index + uint64(len(entries)) - 1
251
252
253 if last < first {
254 return nil
255 }
256
257 if first > entries[0].Index {
258 entries = entries[first-entries[0].Index:]
259 }
260
261 offset := entries[0].Index - ms.ents[0].Index
262 switch {
263 case uint64(len(ms.ents)) > offset:
264 ms.ents = append([]pb.Entry{}, ms.ents[:offset]...)
265 ms.ents = append(ms.ents, entries...)
266 case uint64(len(ms.ents)) == offset:
267 ms.ents = append(ms.ents, entries...)
268 default:
269 getLogger().Panicf("missing log entry [last: %d, append at: %d]",
270 ms.lastIndex(), entries[0].Index)
271 }
272 return nil
273 }
274
View as plain text