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 }