1 module hunt.raft.Storage;
2 
3 import hunt.raft.Msg;
4 import hunt.raft.Util;
5 
6 import hunt.logging;
7 
8 
9 
10 enum ErrCompacted = "requested index is unavailable due to compaction";
11 enum ErrSnapOutOfDate = "requested index is older than the existing snapshot";
12 enum ErrUnavailable = "requested entry at index is unavailable";
13 enum ErrSnapshotTemporarilyUnavailable = "snapshot is temporarily unavailable";
14 enum ErrNil = string.init;
15 
16 alias ErrString = string;
17 
18 
19 interface Storage
20 {
21 	ErrString InitalState(out  HardState hs , out  ConfState cs);
22 	ErrString Entries(ulong lo , ulong hi , ulong maxSize ,out Entry []entries);
23 	ErrString Term(ulong i , out ulong term);
24 	ErrString LastIndex(out ulong index);
25 	ErrString FirstIndex(out ulong index);
26 	ErrString GetSnap(out Snapshot ss);
27 }
28 
29 
30 
31 
32 class MemoryStorage : Storage
33 {
34 	HardState 	_hs;
35 	Snapshot 	_ss;
36 	Entry[]		_ents;
37 
38 	this()
39 	{
40 		_ents.length = 1;
41 	}
42 
43 	ErrString InitalState(out HardState hs , out ConfState cs)
44 	{
45 		hs = _hs;
46 		cs = _ss.Metadata.CS;
47 		return ErrNil;
48 	}
49 
50 	ErrString setHadrdState(in ref HardState hs)
51 	{
52 		_hs = hs;
53 		return ErrNil;
54 	}
55 
56 	ErrString Entries(ulong lo , ulong hi , ulong maxSize , out Entry []entries)
57 	{
58 		ulong offset = _ents[0].Index;
59 		if( lo <= offset)
60 			return ErrCompacted;
61 
62 		if( hi > lastIndex() + 1 )
63 			logError("entries' hi(" , hi , ") is out of bound lastindex(" , lastIndex() , ")");
64 			
65 		if (_ents.length == 1)
66 			return ErrUnavailable;
67 	
68 		entries = _ents[ cast(uint)(lo - offset) .. cast(uint)(hi - offset) ];
69 		entries = limitSize(entries ,maxSize);
70 		return ErrNil;
71 	}
72 
73 	ErrString Term(ulong i , out ulong term)
74 	{
75 		ulong offset = _ents[0].Index;
76 		term = 0;
77 		if ( i < offset)
78 			return ErrCompacted;
79 		if (i - offset >= _ents.length)
80 			return ErrUnavailable;
81 
82 		term = _ents[ cast(uint)(i - offset)].Term;
83 		return ErrNil;
84 	}
85 
86 	ErrString LastIndex(out ulong last)
87 	{
88 		last =  lastIndex();
89 		return ErrNil;
90 	}
91 
92 	ulong lastIndex()
93 	{
94 		return _ents[0].Index + _ents.length - 1;
95 	}
96 
97 	ErrString FirstIndex(out ulong first)
98 	{
99 		first = firstIndex();
100 		return ErrNil;
101 	}
102 
103 	ulong firstIndex()
104 	{
105 		return _ents[0].Index + 1;
106 	}
107 	
108 	ErrString GetSnap(out Snapshot ss)
109 	{
110 		ss = _ss;
111 		return ErrNil;
112 	}
113 
114 	ErrString ApplySnapshot( Snapshot snap)
115 	{
116 		auto Index = _ss.Metadata.Index;
117 		auto snapIndex = snap.Metadata.Index;
118 		if (Index >= snapIndex)
119 			return ErrSnapOutOfDate;
120 
121 		_ss = snap;
122 		Entry ent = { Term: snap.Metadata.Term ,Index:snap.Metadata.Index};
123 		_ents.length = 0;
124 		_ents ~= ent;
125 		return ErrNil;
126 	}
127 
128 	ErrString CreateSnapshot(ulong i , ConfState *cs , string data ,out Snapshot snap)
129 	{
130 
131 		if( i <= _ss.Metadata.Index)
132 			return ErrSnapOutOfDate;
133 
134 		auto offset = _ents[0].Index;
135 		if ( i > lastIndex())
136 			logError("snapshot " , i , "is out of bound lastindex(" , lastIndex() , ")");
137 
138 		_ss.Metadata.Index = i;
139 		_ss.Metadata.Term = _ents[cast(uint)(i - offset)].Term;
140 		if( cs != null)
141 			_ss.Metadata.CS = *cs;
142 
143 		_ss.Data = data;
144 		snap = _ss;
145 		return ErrNil;
146 	}
147 
148 	ErrString Compact(ulong compactIndex)
149 	{
150 		auto offset = _ents[0].Index;
151 		if(compactIndex <= offset)
152 			return ErrCompacted;
153 
154 		if(compactIndex > lastIndex())
155 			logError("compact ", compactIndex ," is out of bound lastindex(" , lastIndex() , ")");
156 
157 		uint i = cast(uint)(compactIndex - offset);
158 		Entry[] ents;
159 		ents.length = 1;
160 		ents[0].Index = _ents[i].Index;
161 		ents[0].Term = _ents[i].Term;
162 		ents ~= _ents[i+1 .. $];
163 		_ents = ents;
164 
165 		return ErrNil;
166 	}
167 
168 
169 
170 	ErrString Append(Entry[] entries)
171 	{
172 		if (entries.length == 0)
173 			return ErrNil;
174 
175 		auto first = firstIndex();
176 		auto last = entries[0].Index + entries.length -1;
177 		if( last < first)
178 			return ErrNil;
179 
180 		if(first > entries[0].Index)
181 			entries = entries[cast(uint)(first - entries[0].Index) .. $];
182 
183 		auto offset = entries[0].Index - _ents[0].Index;
184 
185 		if(_ents.length > offset)
186 		{
187 			_ents = _ents[0 .. cast(uint)offset];
188 			_ents ~= entries;
189 		}
190 		else if(_ents.length == offset)
191 		{
192 			_ents ~= entries;
193 		}
194 		else{
195 			logError("missing log entry [last:" ,lastIndex() ,
196 				", append at: " , entries[0].Index , "]");
197 		}
198 
199 		return ErrNil;
200 
201 	}
202 }