1 module hunt.raft.Logunstable;
2 
3 import hunt.raft.Msg;
4 
5 import hunt.logging;
6 
7 import std.experimental.allocator;
8 import std.format;
9 
10 class unstable
11 {
12 	Snapshot* 	_snap;
13 	Entry[]		_entries;
14 	ulong		_offset;
15 
16 	bool maybeFirstIndex(out ulong index)
17 	{
18 		if(_snap != null)
19 		{
20 			index = _snap.Metadata.Index + 1;
21 			return true;
22 		}
23 		index = 0;
24 		return false;
25 	}
26 
27 	bool maybeLastIndex(out ulong index)
28 	{
29 		if(_entries.length != 0)
30 		{
31 			index = _offset + _entries.length - 1;
32 			return true;
33 		}
34 
35 		if(_snap != null)
36 		{
37 			index = _snap.Metadata.Index;
38 			return true;
39 		}
40 
41 		index = 0;
42 		return false;
43 	}
44 
45 
46 	bool maybeTerm(ulong i , out ulong term)
47 	{
48 		if( i < _offset)
49 		{
50 			if(_snap == null)
51 			{	
52 				term = 0;
53 				return false;
54 			}
55 
56 			if(_snap.Metadata.Index == i)
57 			{
58 				term = _snap.Metadata.Term;
59 				return true;
60 			}
61 
62 			term = 0;
63 			return false;
64 		}
65 
66 		ulong last = 0;
67 		if(!maybeLastIndex(last))
68 		{
69 			term = 0;
70 			return false;
71 		}
72 
73 		if(i > last)
74 		{
75 			term = 0;
76 			return false;
77 		}
78 
79 		term = _entries[cast(uint)(i - _offset)].Term;
80 		return true;
81 	}
82 
83 	void stableTo(ulong i , ulong t)
84 	{
85 		ulong gt = 0;
86 		if(!maybeTerm(i , gt))
87 			return;
88 
89 		if( gt == t && i >= _offset)
90 		{
91 			_entries = _entries[ cast(uint)(i + 1 - _offset) .. $ ];
92 			_offset = i + 1;
93 			shrinkEntriesArray();
94 		}
95 	}
96 
97 	void shrinkEntriesArray()
98 	{
99 		if(_entries.length == 0)
100 		{	
101 			return;
102 		}
103 		else if( _entries.capacity > _entries.length)
104 		{
105 			_entries = _entries.dup;
106 		}
107 	}
108 
109 
110 	void stableSnapTo(ulong i) {
111 		if (_snap != null && _snap.Metadata.Index == i) {
112 			_snap = null;
113 		}
114 	}
115 
116 	void restore(Snapshot s)
117 	{
118 		_offset = s.Metadata.Index + 1;
119 		_entries.length = 0;
120 		_snap = theAllocator.make!Snapshot(s);
121 	}
122 
123 	void truncateAndAppend(Entry[] ents)
124 	{
125 		auto after = ents[0].Index;
126 		if(after == _offset + _entries.length)
127 		{
128 			_entries ~= ents;
129 		}
130 		else if(after <= _offset)
131 		{
132 			logInfo("replace the unstable entries from index " , after);
133 			_entries = ents;
134 			_offset = after;
135 		}
136 		else{
137 			logInfo("truncate the unstable entries before index " , after);
138 			_entries = slice(_offset , after);
139 			_entries ~= ents;
140 		}
141 	}
142 
143 
144 	Entry[] slice(ulong lo , ulong hi)
145 	{
146 		mustCheckOutOfBounds(lo , hi);
147 		return _entries[cast(uint)(lo - _offset) .. cast(uint)(hi - _offset)];
148 	}
149 
150 	void mustCheckOutOfBounds(ulong lo , ulong hi)
151 	{
152 		if( lo > hi)
153 		{
154 			logError(format("invalid unstable.slice %d > %d", lo, hi));
155 		}
156 
157 		auto upper = _offset + _entries.length;
158 		if( lo < _offset || hi > upper)
159 		{
160 			logError(format("unstable.slice[%d,%d) out of bound [%d,%d]", lo, hi, 
161 					_offset, upper));
162 		}
163 	}
164 }