getReplicatorStatueListeners();
34 |
35 | boolean transformLeader(RpcRequests.AppendEntriesRequest request);
36 |
37 | void apply(Task task);
38 |
39 | boolean init();
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/entity/NodeId.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by 周思成 on 2020/3/11 14:20
7 | */
8 |
9 | /**
10 | * A raft node identifier.
11 | *
12 | * @author boyan (boyan@alibaba-inc.com)
13 | *
14 | * 2018-Apr-03 4:08:14 PM
15 | */
16 | public final class NodeId implements Serializable {
17 |
18 | private static final long serialVersionUID = 4428173460056804264L;
19 |
20 | /** Raft group id*/
21 | private final String groupId;
22 | /** Node peer id*/
23 | private final PeerId peerId;
24 | /** cached toString result*/
25 | private String str;
26 |
27 | public NodeId(String groupId, PeerId peerId) {
28 | super();
29 | this.groupId = groupId;
30 | this.peerId = peerId;
31 | }
32 |
33 | public String getGroupId() {
34 | return this.groupId;
35 | }
36 |
37 | @Override
38 | public String toString() {
39 | if (str == null) {
40 | str = "<" + this.groupId + "/" + this.peerId + ">";
41 | }
42 | return str;
43 | }
44 |
45 | public PeerId getPeerId() {
46 | return this.peerId;
47 | }
48 |
49 |
50 |
51 | @Override
52 | public int hashCode() {
53 | final int prime = 31;
54 | int result = 1;
55 | result = prime * result + (this.groupId == null ? 0 : this.groupId.hashCode());
56 | result = prime * result + (this.peerId == null ? 0 : this.peerId.hashCode());
57 | return result;
58 | }
59 |
60 | @Override
61 | public boolean equals(Object obj) {
62 | if (this == obj) {
63 | return true;
64 | }
65 | if (obj == null) {
66 | return false;
67 | }
68 | if (getClass() != obj.getClass()) {
69 | return false;
70 | }
71 | final NodeId other = (NodeId) obj;
72 | if (this.groupId == null) {
73 | if (other.groupId != null) {
74 | return false;
75 | }
76 | } else if (!this.groupId.equals(other.groupId)) {
77 | return false;
78 | }
79 | if (this.peerId == null) {
80 | return other.peerId == null;
81 | } else {
82 | return this.peerId.equals(other.peerId);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/main/java/entity/Options.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.util.Arrays;
4 | import java.util.Map;
5 |
6 | /**
7 | * Created by 周思成 on 2020/3/30 21:07
8 | * yaml options entity
9 | */
10 |
11 | public class Options {
12 |
13 | private CurrentNodeOptions currentNodeOptions;
14 |
15 |
16 | private OtherNodes[] otherNodes;
17 |
18 |
19 | public CurrentNodeOptions getCurrentNodeOptions() {
20 | return currentNodeOptions;
21 | }
22 |
23 | public void setCurrentNodeOptions(CurrentNodeOptions currentNodeOptions) {
24 | this.currentNodeOptions = currentNodeOptions;
25 | }
26 |
27 | public OtherNodes[] getOtherNodes() {
28 | return otherNodes;
29 | }
30 |
31 | public void setOtherNodes(OtherNodes[] otherNodes) {
32 | this.otherNodes = otherNodes;
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | return "Options{" +
38 | "currentNodeOptions=" + currentNodeOptions +
39 | ", otherNodes=" + Arrays.toString(otherNodes) +
40 | '}';
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/main/java/entity/OtherNodes.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/30 21:25
5 | */
6 |
7 | public class OtherNodes{
8 | private String peerId;
9 | private String name;
10 | private String address;
11 | private Integer port;
12 | private int taskPort;
13 |
14 | public int getTaskPort() {
15 | return taskPort;
16 | }
17 |
18 | public void setTaskPort(int taskPort) {
19 | this.taskPort = taskPort;
20 | }
21 |
22 | public String getName() {
23 | return name;
24 | }
25 |
26 | public void setName(String name) {
27 | this.name = name;
28 | }
29 |
30 | public String getAddress() {
31 | return address;
32 | }
33 |
34 | public void setAddress(String address) {
35 | this.address = address;
36 | }
37 |
38 | public Integer getPort() {
39 | return port;
40 | }
41 |
42 | public void setPort(Integer port) {
43 | this.port = port;
44 | }
45 |
46 | public String getPeerId() {
47 | return peerId;
48 | }
49 |
50 | public void setPeerId(String peerId) {
51 | this.peerId = peerId;
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "OtherNodes{" +
57 | "peerId='" + peerId + '\'' +
58 | ", name='" + name + '\'' +
59 | ", address='" + address + '\'' +
60 | ", port='" + port + '\'' +
61 | '}';
62 | }
63 | }
--------------------------------------------------------------------------------
/src/main/java/entity/PeerId.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.io.Serializable;
4 | import java.util.Objects;
5 |
6 | import com.alipay.remoting.util.StringUtils;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import utils.AsciiStringUtil;
10 | import utils.CrcUtil;
11 | import utils.Utils;
12 |
13 |
14 |
15 |
16 | /**
17 | * Represent a participant in a replicating group.
18 | * Created by 周思成 on 2020/3/10 14:51
19 | */
20 |
21 |
22 | public class PeerId implements Serializable,Checksum {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(PeerId.class);
25 |
26 | /** Peer address. */
27 | private Endpoint endpoint;
28 |
29 |
30 | public static final PeerId ANY_PEER = new PeerId();
31 |
32 |
33 | private long checksum;
34 |
35 | /**
36 | * peerName and id are equally the same
37 | */
38 | private String peerName;
39 | private String id;
40 |
41 | private int taskPort;
42 | public PeerId() {
43 |
44 | }
45 |
46 | public int getTaskPort() {
47 | return taskPort;
48 | }
49 |
50 | public void setTaskPort(int taskPort) {
51 | this.taskPort = taskPort;
52 | }
53 |
54 | public String getId() {
55 | return id;
56 | }
57 |
58 | public void setId(String id) {
59 | this.id = id;
60 | }
61 |
62 | public PeerId(String id,String peerName,String address,Integer port,Integer taskPort) {
63 | this.endpoint = new Endpoint(address,port);
64 | this.id = id;
65 | this.peerName = peerName;
66 | this.taskPort = taskPort;
67 | }
68 |
69 | public PeerId copy() {
70 | return new PeerId();
71 | }
72 | @Override
73 | public long checksum() {
74 | if (this.checksum == 0) {
75 | this.checksum = CrcUtil.crc64(AsciiStringUtil.unsafeEncode(toString()));
76 | }
77 | return this.checksum;
78 | }
79 |
80 |
81 | public String getPeerName() {
82 | return peerName;
83 | }
84 |
85 | public void setPeerName(String peerName) {
86 | this.peerName = peerName;
87 | }
88 |
89 | /**
90 | * Create an empty peer.
91 | * @return empty peer
92 | */
93 | public static PeerId emptyPeer() {
94 | return new PeerId();
95 | }
96 |
97 |
98 | public PeerId(Endpoint endpoint) {
99 | this.endpoint = endpoint;
100 | }
101 |
102 | public static Logger getLOG() {
103 | return LOG;
104 | }
105 |
106 | public Endpoint getEndpoint() {
107 | return endpoint;
108 | }
109 |
110 | public void setEndpoint(Endpoint endpoint) {
111 | this.endpoint = endpoint;
112 | }
113 |
114 | public static PeerId getAnyPeer() {
115 | return ANY_PEER;
116 | }
117 |
118 | public long getChecksum() {
119 | return checksum;
120 | }
121 |
122 | public void setChecksum(long checksum) {
123 | this.checksum = checksum;
124 | }
125 |
126 |
127 | @Override
128 | public String toString() {
129 | return "PeerId{" +
130 | "endpoint=" + endpoint +
131 | ", checksum=" + checksum +
132 | '}';
133 | }
134 |
135 | /**
136 | * Parse peerId from string that generated by {@link #toString()}
137 | * This method can support parameter string values are below:
138 | *
139 | *
140 | * PeerId.parse("a:b") = new PeerId("a", "b", 0 , -1)
141 | * PeerId.parse("a:b:c") = new PeerId("a", "b", "c", -1)
142 | * PeerId.parse("a:b::d") = new PeerId("a", "b", 0, "d")
143 | * PeerId.parse("a:b:c:d") = new PeerId("a", "b", "c", "d")
144 | *
145 | *
146 | */
147 | public boolean parse(final String s) {
148 | if (StringUtils.isEmpty(s)) {
149 | return false;
150 | }
151 |
152 | final String[] tmps = StringUtils.split(s, ':');
153 | if (tmps.length < 2 ) {
154 | return false;
155 | }
156 | try {
157 | final int port = Integer.parseInt(tmps[1]);
158 | this.endpoint = new Endpoint(tmps[0], port);
159 |
160 |
161 | return true;
162 | } catch (final Exception e) {
163 | LOG.error("Parse peer from string failed: {}.", s, e);
164 | return false;
165 | }
166 | }
167 |
168 | @Override
169 | public boolean equals(Object o) {
170 | if (this == o) return true;
171 | if (o == null || getClass() != o.getClass()) return false;
172 | PeerId peerId = (PeerId) o;
173 | return taskPort == peerId.taskPort &&
174 | endpoint.equals(peerId.endpoint) &&
175 | Objects.equals(peerName, peerId.peerName) &&
176 | Objects.equals(id, peerId.id);
177 | }
178 |
179 | @Override
180 | public int hashCode() {
181 | return Objects.hash(endpoint, peerName, id, taskPort);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/main/java/entity/RaftError.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/11 16:29
5 | */
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * Raft error code.
12 | * @author Mike
13 | */
14 | public enum RaftError {
15 |
16 | /**
17 | * Unknown error
18 | */
19 | UNKNOWN(-1),
20 |
21 | /**
22 | * Success, no error.
23 | */
24 | SUCCESS(0),
25 |
26 | /**
27 | *
28 | * All Kinds of Timeout(Including Election_timeout, Timeout_now, Stepdown_timeout)
29 | *
30 | *
31 | * ERAFTTIMEDOUT = 10001;
32 | */
33 | ERAFTTIMEDOUT(10001),
34 |
35 | /**
36 | *
37 | * Bad User State Machine
38 | *
39 | *
40 | * ESTATEMACHINE = 10002;
41 | */
42 | ESTATEMACHINE(10002),
43 |
44 | /**
45 | *
46 | * Catchup Failed
47 | *
48 | *
49 | * ECATCHUP = 10003;
50 | */
51 | ECATCHUP(10003),
52 |
53 | /**
54 | *
55 | * Trigger step_down(Not All)
56 | *
57 | *
58 | * ELEADERREMOVED = 10004;
59 | */
60 | ELEADERREMOVED(10004),
61 |
62 | /**
63 | *
64 | * Leader Is Not In The New Configuration
65 | *
66 | *
67 | * ESETPEER = 10005;
68 | */
69 | ESETPEER(10005),
70 |
71 | /**
72 | *
73 | * Shut_down
74 | *
75 | *
76 | * ENODESHUTDOWN = 10006;
77 | */
78 | ENODESHUTDOWN(10006),
79 |
80 | /**
81 | *
82 | * Receive Higher Term Requests
83 | *
84 | *
85 | * EHIGHERTERMREQUEST = 10007;
86 | */
87 | EHIGHERTERMREQUEST(10007),
88 |
89 | /**
90 | *
91 | * Receive Higher Term Response
92 | *
93 | *
94 | * EHIGHERTERMRESPONSE = 10008;
95 | */
96 | EHIGHERTERMRESPONSE(10008),
97 |
98 | /**
99 | *
100 | * Node Is In Error
101 | *
102 | *
103 | * EBADNODE = 10009;
104 | */
105 | EBADNODE(10009),
106 |
107 | /**
108 | *
109 | * Node Votes For Some Candidate
110 | *
111 | *
112 | * EVOTEFORCANDIDATE = 10010;
113 | */
114 | EVOTEFORCANDIDATE(10010),
115 |
116 | /**
117 | *
118 | * Follower(without leader) or Candidate Receives
119 | *
120 | *
121 | * ENEWLEADER = 10011;
122 | */
123 | ENEWLEADER(10011),
124 |
125 | /**
126 | *
127 | * Append_entries/Install_snapshot Request from a new leader
128 | *
129 | *
130 | * ELEADERCONFLICT = 10012;
131 | */
132 | ELEADERCONFLICT(10012),
133 |
134 | /**
135 | *
136 | * Trigger on_leader_stop
137 | *
138 | *
139 | * ETRANSFERLEADERSHIP = 10013;
140 | */
141 | ETRANSFERLEADERSHIP(10013),
142 |
143 | /**
144 | *
145 | * The log at the given index is deleted
146 | *
147 | *
148 | * ELOGDELETED = 10014;
149 | */
150 | ELOGDELETED(10014),
151 |
152 | /**
153 | *
154 | * No available user log to read
155 | *
156 | *
157 | * ENOMOREUSERLOG = 10015;
158 | */
159 | ENOMOREUSERLOG(10015),
160 |
161 | /* other non-raft error codes 1000~10000 */
162 | /**
163 | * Invalid rpc request
164 | */
165 | EREQUEST(1000),
166 |
167 | /**
168 | * Task is stopped
169 | */
170 | ESTOP(1001),
171 |
172 | /**
173 | * Retry again
174 | */
175 | EAGAIN(1002),
176 |
177 | /**
178 | * Interrupted
179 | */
180 | EINTR(1003),
181 |
182 | /**
183 | * Internal exception
184 | */
185 | EINTERNAL(1004),
186 |
187 | /**
188 | * Task is canceled
189 | */
190 | ECANCELED(1005),
191 |
192 | /**
193 | * Host is down
194 | */
195 | EHOSTDOWN(1006),
196 |
197 | /**
198 | * Service is shutdown
199 | */
200 | ESHUTDOWN(1007),
201 |
202 | /**
203 | * Permission issue
204 | */
205 | EPERM(1008),
206 |
207 | /**
208 | * Server is in busy state
209 | */
210 | EBUSY(1009),
211 |
212 | /**
213 | * Timed out
214 | */
215 | ETIMEDOUT(1010),
216 |
217 | /**
218 | * Data is stale
219 | */
220 | ESTALE(1011),
221 |
222 | /**
223 | * Something not found
224 | */
225 | ENOENT(1012),
226 |
227 | /**
228 | * File/folder already exists
229 | */
230 | EEXISTS(1013),
231 |
232 | /**
233 | * IO error
234 | */
235 | EIO(1014),
236 |
237 | /**
238 | * Invalid value.
239 | */
240 | EINVAL(1015),
241 |
242 | /**
243 | * Permission denied
244 | */
245 | EACCES(1016);
246 |
247 | private static final Map RAFT_ERROR_MAP = new HashMap<>();
248 |
249 | static {
250 | for (final RaftError error : RaftError.values()) {
251 | RAFT_ERROR_MAP.put(error.getNumber(), error);
252 | }
253 | }
254 |
255 | public final int getNumber() {
256 | return this.value;
257 | }
258 |
259 | public static RaftError forNumber(final int value) {
260 | return RAFT_ERROR_MAP.getOrDefault(value, UNKNOWN);
261 | }
262 |
263 | public static String describeCode(final int code) {
264 | RaftError e = forNumber(code);
265 | return e != null ? e.name() : "";
266 | }
267 |
268 | private final int value;
269 |
270 | RaftError(final int value) {
271 | this.value = value;
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReadEvent.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/9 20:40
5 | */
6 |
7 | public class ReadEvent {
8 |
9 | public byte[] entry;
10 | public long expectedIndex;
11 | public Closure done;
12 |
13 | public void reset(){
14 | this.entry = null;
15 | this.expectedIndex = 0;
16 | this.done = null;
17 | }
18 |
19 | public ReadEvent(byte[] entry, long expectedIndex, Closure done) {
20 | this.entry = entry;
21 | this.expectedIndex = expectedIndex;
22 | this.done = done;
23 | }
24 | public ReadEvent() {
25 |
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReadTask.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by 周思成 on 2020/5/8 12:39
7 | */
8 |
9 | public class ReadTask implements Serializable {
10 |
11 | private static final long serialVersionUID = -4427655712599189827L;
12 |
13 |
14 | private byte[] taskBytes;
15 |
16 | public byte[] getTaskBytes() {
17 | return taskBytes;
18 | }
19 |
20 | public void setTaskBytes(byte[] taskBytes) {
21 | this.taskBytes = taskBytes;
22 | }
23 |
24 | public ReadTask(byte[] taskBytes) {
25 | this.taskBytes = taskBytes;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReadTaskResponse.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by 周思成 on 2020/5/8 12:39
7 | */
8 |
9 | public class ReadTaskResponse implements Serializable {
10 |
11 | private static final long serialVersionUID = -4427655712599189824L;
12 |
13 |
14 | private boolean response;
15 |
16 | private String msg;
17 |
18 | public ReadTaskResponse(boolean response, String msg) {
19 | this.response = response;
20 | this.msg = msg;
21 | }
22 | public ReadTaskResponse(){
23 |
24 | }
25 |
26 | public boolean isResponse() {
27 | return response;
28 | }
29 |
30 | public void setResponse(boolean response) {
31 | this.response = response;
32 | }
33 |
34 | public String getMsg() {
35 | return msg;
36 | }
37 |
38 | public void setMsg(String msg) {
39 | this.msg = msg;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReadTaskSchedule.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by 周思成 on 2020/5/8 17:26
7 | */
8 |
9 | /**
10 | * A scheduled task for read
11 | */
12 | public class ReadTaskSchedule {
13 |
14 | private List readEventList;
15 | private long index;
16 | private boolean finished =false;
17 |
18 | public List getReadEventList() {
19 | return readEventList;
20 | }
21 |
22 | public void setReadEventList(List readEventList) {
23 | this.readEventList = readEventList;
24 | }
25 |
26 | public long getIndex() {
27 | return index;
28 | }
29 |
30 | public void setIndex(long index) {
31 | this.index = index;
32 | }
33 |
34 | public boolean isFinished() {
35 | return finished;
36 | }
37 |
38 | public void setFinished(boolean finished) {
39 | this.finished = finished;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReadTaskWaiter.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/5/8 13:28
5 | */
6 |
7 | public class ReadTaskWaiter {
8 |
9 | private long currentLogIndex;
10 |
11 | private String currentLeader;
12 |
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/entity/ReplicatorGroupOptions.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import core.NodeImpl;
4 | import utils.TimerManager;
5 |
6 | /**
7 | * Created by 周思成 on 2020/4/14 15:33
8 | */
9 |
10 | public class ReplicatorGroupOptions {
11 |
12 | private long heartbeatTimeoutMs;
13 | private long electionTimeoutMs;
14 | private LogManager logManager;
15 | //private BallotBox ballotBox;
16 | private NodeImpl node;
17 |
18 | public ReplicatorGroupOptions(long heartbeatTimeoutMs,
19 | long electionTimeoutMs,
20 | LogManager logManager
21 | ) {
22 | this.heartbeatTimeoutMs = heartbeatTimeoutMs;
23 | this.electionTimeoutMs = electionTimeoutMs;
24 | this.logManager = logManager;
25 |
26 |
27 | }
28 |
29 | private TimerManager timerManager;
30 |
31 | public TimerManager getTimerManager() {
32 | return this.timerManager;
33 | }
34 |
35 | public void setTimerManager(TimerManager timerManager) {
36 | this.timerManager = timerManager;
37 | }
38 |
39 |
40 |
41 |
42 | public void setHeartbeatTimeoutMs(int heartbeatTimeoutMs) {
43 | this.heartbeatTimeoutMs = heartbeatTimeoutMs;
44 | }
45 |
46 |
47 | public void setElectionTimeoutMs(int electionTimeoutMs) {
48 | this.electionTimeoutMs = electionTimeoutMs;
49 | }
50 |
51 | public LogManager getLogManager() {
52 | return this.logManager;
53 | }
54 |
55 | public void setLogManager(LogManager logManager) {
56 | this.logManager = logManager;
57 | }
58 |
59 | public long getHeartbeatTimeoutMs() {
60 | return heartbeatTimeoutMs;
61 | }
62 |
63 | public long getElectionTimeoutMs() {
64 | return electionTimeoutMs;
65 | }
66 |
67 | public NodeImpl getNode() {
68 | return this.node;
69 | }
70 |
71 | public void setNode(NodeImpl node) {
72 | this.node = node;
73 | }
74 |
75 |
76 | public void setHeartbeatTimeoutMs(long heartbeatTimeoutMs) {
77 | this.heartbeatTimeoutMs = heartbeatTimeoutMs;
78 | }
79 |
80 | @Override
81 | public String toString() {
82 | return "ReplicatorGroupOptions{" +
83 | "heartbeatTimeoutMs=" + heartbeatTimeoutMs +
84 | ", electionTimeoutMs=" + electionTimeoutMs +
85 | ", logManager=" + logManager +
86 | ", node=" + node +
87 | ", timerManager=" + timerManager +
88 | '}';
89 | }
90 |
91 | public void setElectionTimeoutMs(long electionTimeoutMs) {
92 | this.electionTimeoutMs = electionTimeoutMs;
93 | }
94 | }
--------------------------------------------------------------------------------
/src/main/java/entity/ReplicatorType.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/6 7:34
5 | */
6 |
7 | public enum ReplicatorType {
8 | Follower, Learner;
9 |
10 | public final boolean isFollower() {
11 | return this == Follower;
12 | }
13 |
14 | public final boolean isLearner() {
15 | return this == Learner;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/entity/RocksBatch.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/17 12:39
5 | */
6 |
7 | public class RocksBatch {
8 |
9 |
10 | private byte[] key;
11 | private byte[] value;
12 |
13 | public RocksBatch(byte[] key, byte[] value) {
14 | this.key = key;
15 | this.value = value;
16 | }
17 |
18 | public byte[] getKey() {
19 | return key;
20 | }
21 |
22 | public void setKey(byte[] key) {
23 | this.key = key;
24 | }
25 |
26 | public byte[] getValue() {
27 | return value;
28 | }
29 |
30 | public void setValue(byte[] value) {
31 | this.value = value;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/entity/RpcOptions.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/11 14:31
5 | */
6 |
7 | public class RpcOptions {
8 |
9 |
10 | /**
11 | * Rpc connect timeout in milliseconds
12 | * Default: 1000(1s)
13 | */
14 | private int rpcConnectTimeoutMs = 1000;
15 |
16 | /**
17 | * RPC.proto request default timeout in milliseconds
18 | * Default: 5000(5s)
19 | */
20 | private int rpcDefaultTimeout = 5000;
21 |
22 | /**
23 | * Install snapshot RPC.proto request default timeout in milliseconds
24 | * Default: 5 * 60 * 1000(5min)
25 | */
26 | private int rpcInstallSnapshotTimeout = 5 * 60 * 1000;
27 |
28 | /**
29 | * RPC.proto process thread pool size
30 | * Default: 80
31 | */
32 | private int rpcProcessorThreadPoolSize = 80;
33 |
34 | /**
35 | * Whether to enable checksum for RPC.proto.
36 | * Default: false
37 | */
38 | private boolean enableRpcChecksum = false;
39 |
40 |
41 | public int getRpcConnectTimeoutMs() {
42 | return rpcConnectTimeoutMs;
43 | }
44 |
45 | public void setRpcConnectTimeoutMs(int rpcConnectTimeoutMs) {
46 | this.rpcConnectTimeoutMs = rpcConnectTimeoutMs;
47 | }
48 |
49 | public int getRpcDefaultTimeout() {
50 | return rpcDefaultTimeout;
51 | }
52 |
53 | public void setRpcDefaultTimeout(int rpcDefaultTimeout) {
54 | this.rpcDefaultTimeout = rpcDefaultTimeout;
55 | }
56 |
57 | public int getRpcInstallSnapshotTimeout() {
58 | return rpcInstallSnapshotTimeout;
59 | }
60 |
61 | public void setRpcInstallSnapshotTimeout(int rpcInstallSnapshotTimeout) {
62 | this.rpcInstallSnapshotTimeout = rpcInstallSnapshotTimeout;
63 | }
64 |
65 | public int getRpcProcessorThreadPoolSize() {
66 | return rpcProcessorThreadPoolSize;
67 | }
68 |
69 | public void setRpcProcessorThreadPoolSize(int rpcProcessorThreadPoolSize) {
70 | this.rpcProcessorThreadPoolSize = rpcProcessorThreadPoolSize;
71 | }
72 |
73 | public boolean isEnableRpcChecksum() {
74 | return enableRpcChecksum;
75 | }
76 |
77 | public void setEnableRpcChecksum(boolean enableRpcChecksum) {
78 | this.enableRpcChecksum = enableRpcChecksum;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/entity/RpcResult.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/24 16:48
5 | */
6 |
7 | public class RpcResult {
8 |
9 | boolean success = false;
10 |
11 | public boolean isSuccess() {
12 | return success;
13 | }
14 |
15 | public void setSuccess(boolean success) {
16 | this.success = success;
17 | }
18 |
19 | public static RpcResult newRpcResult() {
20 | return new RpcResult();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/entity/StateMachine.java:
--------------------------------------------------------------------------------
1 | //package entity;
2 | //
3 | //
4 | //import exceptions.RaftException;
5 | //
6 | ///**
7 | // * Created by 周思成 on 2020/3/11 14:44
8 | // * @author Mike
9 | // */
10 | //
11 | //public interface StateMachine {
12 | //
13 | // /**
14 | // * Update the StateMachine with a batch a tasks that can be accessed
15 | // * through |iterator|.
16 | // *
17 | // * Invoked when one or more tasks that were passed to Node#apply(Task) have been
18 | // * committed to the raft group (quorum of the group peers have received
19 | // * those tasks and stored them on the backing storage).
20 | // *
21 | // * Once this function returns to the caller, we will regard all the iterated
22 | // * tasks through |iter| have been successfully applied. And if you didn't
23 | // * apply all the the given tasks, we would regard this as a critical error
24 | // * and report a error whose type is ERROR_TYPE_STATE_MACHINE.
25 | // *
26 | // * @param iter iterator of states
27 | // */
28 | // void onApply(final Iterator iter);
29 | //
30 | // /**
31 | // * Invoked once when the raft node was shut down.
32 | // * Default do nothing
33 | // */
34 | // void onShutdown();
35 | //
36 | // /**
37 | // * Invoked when the belonging node becomes the leader of the group at |term|
38 | // * Default: Do nothing
39 | // *
40 | // * @param term new term num
41 | // */
42 | // void onLeaderStart(final long term);
43 | //
44 | //
45 | // /**
46 | // * Invoked when this node steps down from the leader of the replication
47 | // * group and |status| describes detailed information
48 | // *
49 | // * @param status status info
50 | // */
51 | // void onLeaderStop(final Status status);
52 | //
53 | //
54 | // /**
55 | // * This method is called when a critical error was encountered, after this
56 | // * point, no any further modification is allowed to applied to this node
57 | // * until the error is fixed and this node restarts.
58 | // *
59 | // * @param e raft error message
60 | // */
61 | // void onError(final RaftException e);
62 | //
63 | //
64 | // /**
65 | // * This method is called when a follower stops following a leader and its leaderId becomes null,
66 | // * situations including:
67 | // * 1. handle election timeout and start preVote
68 | // * 2. receive requests with higher term such as VoteRequest from a candidate
69 | // * or appendEntries request from a new leader
70 | // * 3. receive timeoutNow request from current leader and start request vote.
71 | // *
72 | // * the parameter ctx gives the information(leaderId, term and status) about the
73 | // * very leader whom the follower followed before.
74 | // * User can reset the node's information as it stops following some leader.
75 | // *
76 | // * @param ctx context of leader change
77 | // */
78 | // void onStopFollowing(final LeaderChangeContext ctx);
79 | //
80 | //
81 | // /**
82 | // * This method is called when a follower or candidate starts following a leader and its leaderId
83 | // * (should be NULL before the method is called) is set to the leader's id,
84 | // * situations including:
85 | // * 1. a candidate receives appendEntries request from a leader
86 | // * 2. a follower(without leader) receives appendEntries from a leader
87 | // *
88 | // * the parameter ctx gives the information(leaderId, term and status) about
89 | // * the very leader whom the follower starts to follow.
90 | // * User can reset the node's information as it starts to follow some leader.
91 | // *
92 | // * @param ctx context of leader change
93 | // */
94 | // void onStartFollowing(final LeaderChangeContext ctx);
95 | //
96 | //}
97 |
--------------------------------------------------------------------------------
/src/main/java/entity/Task.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 |
4 |
5 | import java.io.Serializable;
6 | import java.nio.ByteBuffer;
7 |
8 | /**
9 | * Created by 周思成 on 2020/4/8 16:41
10 | */
11 |
12 | public class Task implements Serializable {
13 |
14 |
15 | private static final long serialVersionUID = -4427655712599189826L;
16 | private ByteBuffer data;
17 |
18 | private Closure done;
19 |
20 | private long expectedTerm = -1;
21 |
22 |
23 | /**
24 | * Creates a task with data/done.
25 | */
26 | public Task(ByteBuffer data, Closure done) {
27 | super();
28 | this.data = data;
29 | this.done = done;
30 | }
31 |
32 | public Task() {
33 |
34 | }
35 | public Task(ByteBuffer data, Closure done, long expectedTerm) {
36 | super();
37 | this.data = data;
38 | this.done = done;
39 | this.expectedTerm = expectedTerm;
40 | }
41 |
42 | public ByteBuffer getData() {
43 | return data;
44 | }
45 |
46 | public void setData(ByteBuffer data) {
47 | this.data = data;
48 | }
49 |
50 | public Closure getDone() {
51 | return done;
52 | }
53 |
54 | public void setDone(Closure done) {
55 | this.done = done;
56 | }
57 |
58 | public long getExpectedTerm() {
59 | return expectedTerm;
60 | }
61 |
62 | public void setExpectedTerm(long expectedTerm) {
63 | this.expectedTerm = expectedTerm;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/entity/TimeOutChecker.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | import core.NodeImpl;
4 | import core.RaftGroupService;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import service.ElectionService;
8 | import utils.Utils;
9 |
10 | import java.util.concurrent.TimeUnit;
11 | import java.util.concurrent.locks.Condition;
12 |
13 | /**
14 | * Created by 周思成 on 2020/3/25 12:36
15 | */
16 |
17 | public class TimeOutChecker implements Runnable{
18 |
19 | private static final Logger LOG = LoggerFactory.getLogger(RaftGroupService.class);
20 |
21 | /**
22 | * 超时时间
23 | */
24 | private long timeOut = NodeImpl.getNodeImple().getOptions().getCurrentNodeOptions().getMaxHeartBeatTime();
25 | //private long timeOut = 1000;
26 |
27 | /**
28 | * 进入线程池的时间
29 | */
30 | private long enterQueueTime;
31 |
32 | /**
33 | * time out closure
34 | */
35 | private TimeOutClosure timeOutClosure;
36 | private String uuid;
37 |
38 | public TimeOutChecker(long enterQueueTime,TimeOutClosure timeOutClosure,String uuid) {
39 | this.timeOutClosure = timeOutClosure;
40 | this.enterQueueTime = enterQueueTime;
41 | this.uuid = uuid;
42 | //this.timeOut = timeOut;
43 | }
44 |
45 | @Override
46 | public void run() {
47 |
48 |
49 |
50 | NodeImpl.getNodeImple().getHeartbeat().getLock().lock();
51 | synchronized(NodeImpl.getNodeImple().getHeartbeat().getChecker()) {
52 | try {
53 | //检查开始运行的时间,是否已经超过timeout时间,如果超出则直接检查
54 | long currentTimeDifferent = Utils.monotonicMs() - enterQueueTime;
55 | LOG.debug("currentTimeDifferent:{} uuid {}",currentTimeDifferent,uuid);
56 | if (currentTimeDifferent > timeOut) {
57 | //在队列里等待的时候就已经超时了,检查node是否超时
58 | LOG.error("Timeout during waiting int queue");
59 | checkTimeOut();
60 | } else {
61 | //还未超时,等待检测超时
62 | try {
63 | LOG.debug("thread wait:"+(currentTimeDifferent));
64 | long u = Utils.monotonicMs();
65 | NodeImpl.getNodeImple().getHeartbeat()
66 | .getChecker().wait(timeOut - currentTimeDifferent);
67 | System.out.println("wait:"+(Utils.monotonicMs()-u));
68 | } catch (InterruptedException e) {
69 | e.printStackTrace();
70 | }
71 | LOG.debug("Thread wake up");
72 | checkTimeOut();
73 |
74 | }
75 | } catch (Exception e) {
76 | LOG.error("Heartbeat timeout checker exception: " + e.getMessage() + "uuid:"+uuid);
77 | e.printStackTrace();
78 | } finally {
79 | NodeImpl.getNodeImple().getHeartbeat().getLock().unlock();
80 | }
81 |
82 |
83 | }
84 |
85 | }
86 |
87 | public long getEnterQueueTime() {
88 | return enterQueueTime;
89 | }
90 |
91 | public void setEnterQueueTime(long enterQueueTime) {
92 | this.enterQueueTime = enterQueueTime;
93 | }
94 | // private void checkNodeStatus() {
95 | //
96 | //
97 | // }
98 |
99 | private void checkTimeOut() {
100 | LOG.debug("CkeckTimeout:{}",Utils.monotonicMs()
101 | - NodeImpl.getNodeImple().getLastReceiveHeartbeatTime().longValue()+ "uuid:"+uuid);
102 | LOG.debug("enterQueueTime:{}",enterQueueTime
103 | - Utils.monotonicMs()+ "uuid:"+uuid);
104 | if ((Utils.monotonicMs()
105 | - NodeImpl.getNodeImple().getLastReceiveHeartbeatTime().longValue()) >= timeOut) {
106 | //超时,执行超时逻辑
107 | LOG.error("Node timeout, start to launch TimeOut actions");
108 | //timeOutClosure.run(null);
109 | ElectionService.checkToStartPreVote();
110 | }else {
111 | //未超时
112 |
113 |
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/src/main/java/entity/TimeOutClosure.java:
--------------------------------------------------------------------------------
1 | package entity;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/1 16:10
5 | */
6 |
7 | public interface TimeOutClosure extends Closure {
8 |
9 |
10 | long getBaseTime();
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/exceptions/ElectionException.java:
--------------------------------------------------------------------------------
1 | package exceptions;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/24 16:19
5 | */
6 |
7 | public class ElectionException extends Throwable {
8 |
9 | private String errMsg;
10 |
11 | public String getErrMsg() {
12 | return errMsg;
13 | }
14 |
15 | public void setErrMsg(String errMsg) {
16 | this.errMsg = errMsg;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/exceptions/LogExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package exceptions;
2 |
3 | import com.lmax.disruptor.ExceptionHandler;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 |
7 | /**
8 | * Created by 周思成 on 2020/4/12 19:57
9 | */
10 |
11 | public class LogExceptionHandler implements ExceptionHandler {
12 | private static final Logger LOG = LoggerFactory.getLogger(LogExceptionHandler.class);
13 |
14 | public interface OnEventException {
15 |
16 | void onException(T event, Throwable ex);
17 | }
18 |
19 | private final String name;
20 | private final OnEventException onEventException;
21 |
22 | public LogExceptionHandler(String name) {
23 | this(name, null);
24 | }
25 |
26 | public LogExceptionHandler(String name, OnEventException onEventException) {
27 | this.name = name;
28 | this.onEventException = onEventException;
29 | }
30 |
31 | @Override
32 | public void handleOnStartException(Throwable ex) {
33 | LOG.error("Fail to start {} disruptor", this.name, ex);
34 | }
35 |
36 | @Override
37 | public void handleOnShutdownException(Throwable ex) {
38 | LOG.error("Fail to shutdown {}r disruptor", this.name, ex);
39 |
40 | }
41 |
42 | @Override
43 | public void handleEventException(Throwable ex, long sequence, T event) {
44 | LOG.error("Handle {} disruptor event error, event is {}", this.name, event, ex);
45 | if (this.onEventException != null) {
46 | this.onEventException.onException(event, ex);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/exceptions/LogStorageException.java:
--------------------------------------------------------------------------------
1 | package exceptions;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/24 16:19
5 | */
6 |
7 | public class LogStorageException extends Throwable {
8 |
9 | private String errMsg;
10 |
11 | public String getErrMsg() {
12 | return errMsg;
13 | }
14 |
15 | public void setErrMsg(String errMsg) {
16 | this.errMsg = errMsg;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/exceptions/RaftException.java:
--------------------------------------------------------------------------------
1 | package exceptions;
2 |
3 | import entity.Status;
4 | import rpc.EnumOutter;
5 |
6 | /**
7 | * Created by 周思成 on 2020/3/11 16:36
8 | */
9 |
10 | public class RaftException extends Throwable{
11 |
12 | private static final long serialVersionUID = -1533343555230409704L;
13 | /** Error status*/
14 | private Status status = Status.OK();
15 | /**
16 | * Error type
17 | */
18 | private EnumOutter.ErrorType type;
19 | public RaftException(Status status) {
20 | this.status = status;
21 | }
22 | public RaftException(EnumOutter.ErrorType type) {
23 | super(type.name());
24 | this.type = type;
25 | }
26 |
27 | public RaftException() {
28 |
29 | }
30 |
31 | public Status getStatus() {
32 | return status;
33 | }
34 |
35 | public void setStatus(Status status) {
36 | this.status = status;
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | return "RaftException{" +
42 | "status=" + status +
43 | '}';
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/rpc/ClientRpcService.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import entity.ReadTask;
4 | import entity.Status;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * Created by 周思成 on 2020/5/8 21:09
10 | */
11 |
12 | public interface ClientRpcService {
13 |
14 | void applied(Status status);
15 |
16 | void appliedBatches(List statusList);
17 |
18 | void readResult(ReadTask readTask);
19 |
20 | void readResults(List readTaskList);
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/rpc/ClientRpcServiceImpl.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import entity.ReadTask;
4 | import entity.Status;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.nio.charset.StandardCharsets;
9 | import java.util.List;
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * Created by 周思成 on 2020/5/8 21:12
14 | */
15 |
16 | public class ClientRpcServiceImpl implements ClientRpcService {
17 |
18 | public static final Logger LOG = LoggerFactory.getLogger(ClientRpcServiceImpl.class);
19 | public static AtomicInteger atomicInteger = new AtomicInteger(0);
20 | @Override
21 | public void applied(Status status) {
22 | LOG.info("Receive status {}",status);
23 | }
24 |
25 | @Override
26 | public void appliedBatches(List statusList) {
27 | LOG.info("Receive statusList {}",statusList);
28 | }
29 |
30 | @Override
31 | public void readResult(ReadTask readTask) {
32 | try {
33 | LOG.info("Receive ReadTask {}", readTask);
34 | String result = new String(readTask.getTaskBytes(), StandardCharsets.UTF_8);
35 | LOG.info("Read result:" + result);
36 | atomicInteger.addAndGet(1);
37 | } catch (Exception e) {
38 | e.printStackTrace();
39 | LOG.error("readResult error:{}",e.getMessage());
40 | }
41 |
42 | }
43 |
44 | @Override
45 | public void readResults(List readTaskList) {
46 | LOG.info("Receive readTaskList {}",readTaskList);
47 | for (ReadTask r :
48 | readTaskList) {
49 | readResult(r);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/rpc/LogEntryCodecFactory.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import entity.LogEntryDecoder;
4 |
5 | /**
6 | * Created by 周思成 on 2020/5/7 12:25
7 | */
8 |
9 | public interface LogEntryCodecFactory {
10 |
11 |
12 | public LogEntryEncoder encoder();
13 |
14 |
15 | public LogEntryDecoder decoder();
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/rpc/LogEntryEncoder.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import com.google.protobuf.ByteString;
4 | import com.google.protobuf.CodedOutputStream;
5 | import entity.LogEntry;
6 | import entity.LogId;
7 | import entity.Status;
8 | import exceptions.RaftException;
9 | import utils.Requires;
10 |
11 | import java.io.IOException;
12 | import java.nio.ByteBuffer;
13 |
14 | /**
15 | * Created by 周思成 on 2020/5/7 11:54
16 | */
17 |
18 | @Deprecated
19 | public class LogEntryEncoder implements entity.LogEntryEncoder {
20 |
21 | public static final LogEntryEncoder INSTANCE = new LogEntryEncoder();
22 |
23 |
24 | @Override
25 | public byte[] encode(LogEntry log) throws RaftException {
26 | Requires.requireNonNull(log,"The log entry is null");
27 | String data = new String(getByteArrayFromByteBuffer(log.getData()));
28 |
29 | return data.getBytes();
30 | }
31 |
32 | // @Override
33 | // public byte[] encode(LogEntry log) throws RaftException {
34 | // Requires.requireNonNull(log,"The log entry is null");
35 | //
36 | // final LogId logId = log.getId();
37 | // final LogOuter.LogEntry.Builder builder = LogOuter.LogEntry.newBuilder();
38 | // builder.setIndex(logId.getIndex());
39 | // builder.setTerm(logId.getTerm());
40 | // builder.setData( ByteString.copyFrom(getByteArrayFromByteBuffer(log.getData())));
41 | // final LogOuter.LogEntry logEntry = builder.build();
42 | // final int bodyLen = logEntry.getSerializedSize();
43 | // final byte[] ret = new byte[LogEntryV2CodecFactory.HEADER_SIZE + bodyLen];
44 | // int i = 0;
45 | // for (; i >> 24);
46 | bytes[1] = (byte)(num >>> 16);
47 | bytes[2] = (byte)(num >>> 8);
48 | bytes[3] = (byte)num;
49 | return bytes;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/rpc/RaftRpcServerFactory.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import com.alipay.remoting.rpc.RpcServer;
4 | import entity.Endpoint;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | import java.util.concurrent.Executor;
9 |
10 | /**
11 | * Created by 周思成 on 2020/3/18 13:03
12 | */
13 |
14 | public class RaftRpcServerFactory {
15 |
16 | public static final Logger LOG = LoggerFactory.getLogger(RaftRpcServerFactory.class);
17 |
18 |
19 | /**
20 | * Creates a raft RPC server with executors to handle requests.
21 | *
22 | * @param endpoint server address to bind
23 | * @param raftExecutor executor to handle RAFT requests.
24 | * @param cliExecutor executor to handle CLI service requests.
25 | * @return a rpc server instance
26 | */
27 | public static RpcServer createRaftRpcServer(final Endpoint endpoint, final Executor raftExecutor
28 | ,final Executor cliExecutor){
29 | final RpcServer rpcServer = new RpcServer(endpoint.getPort(),true,true);
30 | addRaftRequestProcessors(rpcServer, raftExecutor, cliExecutor);
31 | return rpcServer;
32 | }
33 |
34 | public static void addRaftRequestProcessors(RpcServer rpcServer, Executor raftExecutor, Executor cliExecutor) {
35 |
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/rpc/RpcRequestClosure.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import com.google.protobuf.Message;
4 | import entity.Closure;
5 | import entity.Status;
6 | import com.alipay.remoting.AsyncContext;
7 | import com.alipay.remoting.BizContext;
8 |
9 | import com.google.protobuf.Message;
10 |
11 | /**
12 | * Created by 周思成 on 2020/3/13 11:45
13 | */
14 |
15 | /**
16 | * RPC request Closure encapsulates the RPC contexts.
17 | *
18 | * @author boyan (boyan@alibaba-inc.com)
19 | *
20 | * 2018-Mar-28 4:55:24 PM
21 | */
22 | public class RpcRequestClosure implements Closure {
23 |
24 | private final BizContext bizContext;
25 | private final AsyncContext asyncContext;
26 | private boolean respond;
27 |
28 | public RpcRequestClosure(BizContext bizContext, AsyncContext asyncContext) {
29 | super();
30 | this.bizContext = bizContext;
31 | this.asyncContext = asyncContext;
32 | this.respond = false;
33 | }
34 |
35 | public BizContext getBizContext() {
36 | return this.bizContext;
37 | }
38 |
39 | public AsyncContext getAsyncContext() {
40 | return this.asyncContext;
41 | }
42 |
43 | public synchronized void sendResponse(Message msg) {
44 | if (this.respond) {
45 | return;
46 | }
47 | this.asyncContext.sendResponse(msg);
48 | this.respond = true;
49 | }
50 |
51 | @Override
52 | public void run(Status status) {
53 | sendResponse(RpcResponseFactory.newResponse(status));
54 | }
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/src/main/java/rpc/RpcResponseClosure.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 11:51
5 | */
6 |
7 | import com.alipay.sofa.rpc.core.exception.SofaRpcException;
8 | import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback;
9 | import com.alipay.sofa.rpc.core.request.RequestBase;
10 | import com.google.protobuf.Message;
11 | import core.NodeImpl;
12 | import entity.Closure;
13 | import entity.Node;
14 | import entity.TimeOutChecker;
15 | import org.slf4j.Logger;
16 | import org.slf4j.LoggerFactory;
17 | import service.ElectionService;
18 | import service.ElectionServiceImpl;
19 | import utils.Utils;
20 |
21 | import java.util.List;
22 |
23 |
24 | /**
25 | * @author Mike
26 | */
27 | public class RpcResponseClosure implements SofaResponseCallback {
28 |
29 | public static final Logger LOG = LoggerFactory.getLogger(RpcResponseClosure.class);
30 | ElectionService electionService = new ElectionServiceImpl();
31 | @Override
32 | public void onAppResponse(Object o, String s, RequestBase requestBase) {
33 |
34 | LOG.debug("Receive response:requestBase: {} requestString: {}",requestBase.toString(),s);
35 |
36 | if(requestBase.getMethodName()==null){
37 | LOG.error("Receive empty methodName:{}",requestBase.toString());
38 | return;
39 | }
40 |
41 | switch (requestBase.getMethodName()) {
42 | case "handleAppendEntriesRequest":
43 | RpcRequests.AppendEntriesResponse appendEntriesResponse =
44 | (RpcRequests.AppendEntriesResponse)o;
45 | NodeImpl.getNodeImple().handleAppendEntriesResponse(appendEntriesResponse);
46 | break;
47 | case "handlePreVoteRequest":
48 | RpcRequests.RequestPreVoteResponse requestPreVoteResponse =
49 | (RpcRequests.RequestPreVoteResponse)o;
50 | electionService.handlePrevoteResponse(requestPreVoteResponse);
51 | break;
52 | case "handleVoteRequest":
53 | RpcRequests.RequestVoteResponse requestVoteResponse =
54 | (RpcRequests.RequestVoteResponse)o;
55 | electionService.handleElectionResponse(requestVoteResponse);
56 | break;
57 | case "handleToApplyRequest":
58 | RpcRequests.NotifyFollowerToApplyResponse response =
59 | (RpcRequests.NotifyFollowerToApplyResponse)o;
60 | if(!response.getSuccess()){
61 | LOG.error("***critical error*** FSM StateMachine apply failed follower{}"
62 | ,response.getFollowerId());
63 | }else {
64 | NodeImpl.getNodeImple().handleToApplyResponse(response);
65 | }
66 | break;
67 | case "handleReadHeartbeatrequest":
68 | RpcRequests.AppendEntriesResponse appendEntriesResponse1
69 | = (RpcRequests.AppendEntriesResponse)o;
70 | NodeImpl.getNodeImple().handleReadHeartbeatRequestClosure(appendEntriesResponse1);
71 | break;
72 | case "handleApendEntriesRequests":
73 | RpcRequests.AppendEntriesResponses appendEntriesResponses =
74 | (RpcRequests.AppendEntriesResponses)o;
75 |
76 | for (RpcRequests.AppendEntriesResponse a:
77 | appendEntriesResponses.getArgsList() ) {
78 | NodeImpl.getNodeImple().handleAppendEntriesResponse(a);
79 | }
80 | break;
81 | case "handleFollowerStableRequest":
82 | LOG.info("Follower invoke follower stable request success lastIndex:{}"
83 | ,((RpcRequests.NotifyFollowerStableResponse)o).getLastIndex());
84 | break;
85 | default:
86 | LOG.error("RPC Request closure mismatched, requestBase: {} requestString: {}"
87 | ,requestBase.toString(),s);
88 | }
89 | }
90 |
91 | @Override
92 | public void onAppException(Throwable throwable, String s, RequestBase requestBase) {
93 |
94 | }
95 |
96 | @Override
97 | public void onSofaException(SofaRpcException e, String s, RequestBase requestBase) {
98 |
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/rpc/RpcResponseFactory.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 11:49
5 | */
6 |
7 | import entity.RaftError;
8 | import entity.Status;
9 |
10 | /**
11 | * Helper to create error response.
12 | *
13 | * @author boyan (boyan@alibaba-inc.com)
14 | *
15 | * 2018-Mar-28 4:33:50 PM
16 | */
17 | public class RpcResponseFactory {
18 |
19 | /**
20 | * Creates a RPC response from status,return OK response
21 | * when status is null.
22 | *
23 | * @param st status with response
24 | * @return a response instance
25 | */
26 | public static RpcRequests.ErrorResponse newResponse(Status st) {
27 | if (st == null) {
28 | return newResponse(0, "OK");
29 | }
30 | return newResponse(st.getCode(), st.getErrorMsg());
31 | }
32 |
33 | /**
34 | * Creates an error response with parameters.
35 | *
36 | * @param error error with raft info
37 | * @param fmt message with format string
38 | * @param args arguments referenced by the format specifiers in the format
39 | * string
40 | * @return a response instance
41 | */
42 | public static RpcRequests.ErrorResponse newResponse(RaftError error, String fmt, Object... args) {
43 | return newResponse(error.getNumber(), fmt, args);
44 | }
45 |
46 | /**
47 | * Creates an error response with parameters.
48 | *
49 | * @param code error code with raft info
50 | * @param fmt message with format string
51 | * @param args arguments referenced by the format specifiers in the format
52 | * string
53 | * @return a response instance
54 | */
55 | public static RpcRequests.ErrorResponse newResponse(int code, String fmt, Object... args) {
56 | RpcRequests.ErrorResponse.Builder builder = RpcRequests.ErrorResponse.newBuilder();
57 | builder.setErrorCode(code);
58 | if (fmt != null) {
59 | builder.setErrorMsg(String.format(fmt, args));
60 | }
61 | return builder.build();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/rpc/RpcServices.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 |
4 | import entity.RpcResult;
5 |
6 | /**
7 | * Created by 周思成 on 2020/3/24 12:47
8 | */
9 |
10 | public interface RpcServices {
11 |
12 |
13 | public RpcRequests sendRpcRequest(RpcRequests rpcRequests);
14 |
15 | public RpcRequests.RequestPreVoteResponse handlePreVoteRequest(
16 | RpcRequests.RequestPreVoteRequest preVoteRequest);
17 |
18 | public RpcRequests.RequestVoteResponse handleVoteRequest(
19 | RpcRequests.RequestVoteRequest requestVoteRequest);
20 |
21 | public RpcRequests.AppendEntriesResponse handleAppendEntriesRequest(
22 | RpcRequests.AppendEntriesRequest appendEntriesRequest);
23 |
24 | public RpcRequests.AppendEntriesResponses handleApendEntriesRequests(
25 | RpcRequests.AppendEntriesRequests appendEntriesRequests);
26 |
27 | public RpcRequests.NotifyFollowerStableResponse handleFollowerStableRequest(
28 | RpcRequests.NotifyFollowerStableRequest notifyFollowerStableRequest
29 | );
30 |
31 | public RpcRequests.NotifyFollowerToApplyResponse handleToApplyRequest(
32 | RpcRequests.NotifyFollowerToApplyRequest request
33 | );
34 |
35 | public RpcRequests.AppendEntriesResponse handleReadHeartbeatrequest(
36 | RpcRequests.AppendEntriesRequest appendEntriesRequest
37 | );
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/rpc/TaskRpcResponseClosure.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 11:51
5 | */
6 |
7 | import com.alipay.sofa.rpc.core.exception.SofaRpcException;
8 | import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback;
9 | import com.alipay.sofa.rpc.core.request.RequestBase;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 |
14 | /**
15 | * @author Mike
16 | */
17 | public class TaskRpcResponseClosure implements SofaResponseCallback {
18 |
19 | public static final Logger LOG = LoggerFactory.getLogger(TaskRpcResponseClosure.class);
20 |
21 | @Override
22 | public void onAppResponse(Object o, String s, RequestBase requestBase) {
23 |
24 | LOG.info("Receive taskRpcResponse response:requestBase: {} requestString: {}",requestBase.toString(),s);
25 | switch (requestBase.getMethodName()) {
26 | case "":
27 |
28 | }
29 | }
30 |
31 | @Override
32 | public void onAppException(Throwable throwable, String s, RequestBase requestBase) {
33 |
34 | }
35 |
36 | @Override
37 | public void onSofaException(SofaRpcException e, String s, RequestBase requestBase) {
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/rpc/TaskRpcServices.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import entity.ReadTask;
4 | import entity.ReadTaskResponse;
5 | import entity.Task;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * Created by 周思成 on 2020/4/8 17:12
11 | */
12 |
13 | public interface TaskRpcServices {
14 |
15 | void init(String protocol,String ip,String serialization,int port);
16 |
17 | void apply(final Task task);
18 |
19 | void apply(final Task[] tasks);
20 |
21 | ReadTaskResponse handleReadIndexRequest(ReadTask readTask);
22 | List handleReadIndexRequests(List readTask);
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/rpc/TaskServicesImpl.java:
--------------------------------------------------------------------------------
1 | package rpc;
2 |
3 | import com.alipay.sofa.rpc.config.ConsumerConfig;
4 | import com.alipay.sofa.rpc.config.ServerConfig;
5 | import com.sun.org.apache.xml.internal.utils.StringVector;
6 | import core.NodeImpl;
7 | import core.RaftGroupService;
8 | import entity.ReadTask;
9 | import entity.ReadTaskResponse;
10 | import entity.Task;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import java.nio.charset.StandardCharsets;
15 | import java.util.ArrayList;
16 | import java.util.List;
17 |
18 | /**
19 | * Created by 周思成 on 2020/4/8 17:13
20 | */
21 |
22 | public class TaskServicesImpl implements TaskRpcServices {
23 | private static final Logger LOG = LoggerFactory.getLogger(TaskServicesImpl.class);
24 |
25 | @Override
26 | public void init(String protocol,String ip, String serialization,int port) {
27 |
28 | }
29 |
30 | @Override
31 | public void apply(Task task) {
32 | try {
33 | LOG.debug("Receive task:{}", task.getData());
34 | NodeImpl.getNodeImple().apply(task);
35 |
36 | } catch (Exception e) {
37 | e.printStackTrace();
38 | }
39 | }
40 |
41 | @Override
42 | public void apply(Task[] tasks) {
43 | LOG.info("Apply tasks:{} currentThread:{}",tasks.length,Thread.currentThread().getName());
44 | for (Task task : tasks) {
45 | LOG.debug("for :{}",Thread.currentThread().getName());
46 | NodeImpl.getNodeImple().apply(task);
47 | }
48 | }
49 |
50 | @Override
51 | public ReadTaskResponse handleReadIndexRequest(ReadTask readTask) {
52 | LOG.debug("Receive readTask");
53 | return NodeImpl.getNodeImple().addReadTaskEvent(readTask);
54 | }
55 | @Override
56 | public List handleReadIndexRequests(List readTask) {
57 | List readTaskResponses = new ArrayList<>(readTask.size());
58 | for (ReadTask r :
59 | readTask) {
60 | readTaskResponses.add(handleReadIndexRequest(r));
61 | }
62 | return readTaskResponses;
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/rpc/processor/AppendEntriesRequestProcessor.java:
--------------------------------------------------------------------------------
1 | package rpc.processor;
2 |
3 | import com.alipay.remoting.Connection;
4 | import com.alipay.remoting.ConnectionEventProcessor;
5 |
6 | /**
7 | * Created by 周思成 on 2020/3/18 13:43
8 | */
9 |
10 | public class AppendEntriesRequestProcessor implements ConnectionEventProcessor {
11 | @Override
12 | public void onEvent(String s, Connection connection) {
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/service/ElectionService.java:
--------------------------------------------------------------------------------
1 | package service;
2 |
3 | import core.NodeImpl;
4 | import org.slf4j.Logger;
5 | import org.slf4j.LoggerFactory;
6 | import rpc.RpcRequests;
7 | import rpc.RpcServicesImpl;
8 |
9 | /**
10 | * Created by 周思成 on 2020/3/24 16:02
11 | */
12 |
13 | public interface ElectionService {
14 |
15 | public static final Logger LOG = LoggerFactory.getLogger(ElectionService.class);
16 |
17 |
18 | /**
19 | * 检查是否启动election
20 | */
21 | public static void checkToStartPreVote(){
22 | LOG.debug("checkToStartPreVote:"+!NodeImpl.getNodeImple().checkNodeStatePreCandidate());
23 | if ( ! NodeImpl.getNodeImple().checkNodeStatePreCandidate()) {
24 | ElectionService electionService = new ElectionServiceImpl();
25 | electionService.startPrevote();
26 | }
27 | }
28 |
29 | public static void checkToStartElection() {
30 | LOG.debug("checkToStartElection:{}",NodeImpl.getNodeImple().checkIfCurrentNodeCanStartElection());
31 | if (NodeImpl.getNodeImple().checkIfCurrentNodeCanStartElection()) {
32 | //start election
33 | ElectionService electionService = new ElectionServiceImpl();
34 | electionService.election();
35 | }
36 | }
37 |
38 | public void startPrevote();
39 |
40 | public void election();
41 |
42 | public void handlePrevoteResponse(RpcRequests.RequestPreVoteResponse requestPreVoteResponse);
43 |
44 | public void handleElectionResponse(RpcRequests.RequestVoteResponse requestVoteResponse);
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/service/RaftServerService.java:
--------------------------------------------------------------------------------
1 | package service;
2 |
3 | import com.google.protobuf.Message;
4 | import rpc.RpcRequestClosure;
5 | import rpc.RpcRequests;
6 | import rpc.RpcRequests;
7 | import rpc.RpcResponseClosure;
8 |
9 | /**
10 | * Created by 周思成 on 2020/3/12 14:33
11 | * @author Mike
12 | */
13 |
14 | public interface RaftServerService {
15 |
16 |
17 | /**
18 | * Handle pre-vote request.
19 | *
20 | * @param request data of the pre vote
21 | * @return the response message
22 | */
23 | Message handlePreVoteRequest(RpcRequests.RequestVoteRequest request);
24 |
25 | /**
26 | * Handle request-vote request.
27 | *
28 | * @param request data of the vote
29 | * @return the response message
30 | */
31 | Message handleRequestVoteRequest(RpcRequests.RequestVoteRequest request);
32 |
33 | /**
34 | * Handle append-entries request, return response message or
35 | * called done.run() with response.
36 | *
37 | * @param request data of the entries to append
38 | * @param done callback
39 | * @return the response message
40 | */
41 | Message handleAppendEntriesRequest(RpcRequests.AppendEntriesRequest request, RpcRequestClosure done);
42 |
43 |
44 |
45 | /**
46 | * Handle time-out-now request, return response message or
47 | * called done.run() with response.
48 | *
49 | * @param request data of the timeout now request
50 | * @param done callback
51 | * @return the response message
52 | */
53 | Message handleTimeoutNowRequest(RpcRequests.TimeoutNowRequest request, RpcRequestClosure done);
54 |
55 | /**
56 | * Handle read-index request, call the RPC.proto closure with response.
57 | *
58 | * @param request data of the readIndex read
59 | * @param done callback
60 | */
61 | void handleReadIndexRequest(RpcRequests.ReadIndexRequest request, RpcResponseClosure done);
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/service/RaftServiceFactory.java:
--------------------------------------------------------------------------------
1 | package service;
2 |
3 | import config.RaftOptionsLoader;
4 | import entity.LogEntryCodecFactory;
5 | import storage.LogStorage;
6 |
7 | /**
8 | * Created by 周思成 on 2020/3/13 11:57
9 | */
10 |
11 | public interface RaftServiceFactory {
12 |
13 | /**
14 | * Creates a raft log storage.
15 | * @param uri The log storage uri from {@link NodeOptions}
16 | * @param raftOptions the raft options.
17 | * @return storage to store raft log entires.
18 | */
19 | LogStorage createLogStorage(final String uri, final RaftOptionsLoader raftOptions);
20 |
21 |
22 | /**
23 | * Creates a log entry codec factory.
24 | * @return a codec factory to create encoder/decoder for raft log entry.
25 | */
26 | LogEntryCodecFactory createLogEntryCodecFactory();
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/service/RaftServiceFactoryImpl.java:
--------------------------------------------------------------------------------
1 | package service;
2 |
3 | import config.RaftOptionsLoader;
4 | import entity.LogEntryCodecFactory;
5 | import storage.LogStorage;
6 |
7 | /**
8 | * Created by 周思成 on 2020/3/13 14:27
9 | */
10 |
11 | public class RaftServiceFactoryImpl implements RaftServiceFactory {
12 | @Override
13 | public LogStorage createLogStorage(String uri, RaftOptionsLoader raftOptions) {
14 | return null;
15 | }
16 |
17 | @Override
18 | public LogEntryCodecFactory createLogEntryCodecFactory() {
19 | return null;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/storage/LogStorage.java:
--------------------------------------------------------------------------------
1 | package storage;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 15:52
5 | */
6 |
7 | import config.LogStorageOptions;
8 | import core.Lifecycle;
9 | import entity.LogEntry;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * Log entry storage service.
15 | *
16 | * @author boyan (boyan@alibaba-inc.com)
17 | *
18 | * 2018-Mar-12 3:43:54 PM
19 | */
20 | public interface LogStorage {
21 |
22 | /**
23 | * Returns first log index in log.
24 | */
25 | long getFirstLogIndex();
26 |
27 | /**
28 | * Returns last log index in log.
29 | */
30 | long getLastLogIndex();
31 |
32 | /**
33 | * Get logEntry by index.
34 | */
35 | LogEntry getEntry(final long index);
36 |
37 | /**
38 | * Get logEntry's term by index. This method is deprecated, you should use {@link #getEntry(long)} to get the log id's term.
39 | * @deprecated
40 | */
41 | @Deprecated
42 | long getTerm(final long index);
43 |
44 | /**
45 | * Append entries to log.
46 | */
47 | boolean appendEntry(final LogEntry entry);
48 |
49 | /**
50 | * Append entries to log, return append success number.
51 | */
52 | int appendEntries(final List entries);
53 |
54 | /**
55 | * Delete logs from storage's head, [first_log_index, first_index_kept) will
56 | * be discarded.
57 | */
58 | boolean truncatePrefix(final long firstIndexKept);
59 |
60 | /**
61 | * Delete uncommitted logs from storage's tail, (last_index_kept, last_log_index]
62 | * will be discarded.
63 | */
64 | boolean truncateSuffix(final long lastIndexKept);
65 |
66 | /**
67 | * Drop all the existing logs and reset next log index to |next_log_index|.
68 | * This function is called after installing snapshot from leader.
69 | */
70 | boolean reset(final long nextLogIndex);
71 |
72 |
73 | boolean init();
74 | }
--------------------------------------------------------------------------------
/src/main/java/utils/ArrayDeque.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | /**
7 | * Extend array list to add peek/poll first/last element.
8 | *
9 | * @author boyan (boyan@alibaba-inc.com)
10 | *
11 | * 2018-Apr-11 11:14:38 AM
12 | * @param
13 | */
14 | public class ArrayDeque extends java.util.ArrayList {
15 |
16 | private static final long serialVersionUID = -4929318149975955629L;
17 |
18 | /**
19 | * Get the first element of list.
20 | */
21 | public static E peekFirst(List list) {
22 | return list.get(0);
23 | }
24 |
25 | /**
26 | * Remove the first element from list and return it.
27 | */
28 | public static E pollFirst(List list) {
29 | return list.remove(0);
30 | }
31 |
32 | /**
33 | * Get the last element of list.
34 | */
35 | public static E peekLast(List list) {
36 | return list.get(list.size() - 1);
37 | }
38 |
39 | /**
40 | * Remove the last element from list and return it.
41 | */
42 | public static E pollLast(List list) {
43 | return list.remove(list.size() - 1);
44 | }
45 |
46 | /**
47 | * Get the first element of list.
48 | */
49 | public E peekFirst() {
50 | return peekFirst(this);
51 | }
52 |
53 | /**
54 | * Get the last element of list.
55 | */
56 | public E peekLast() {
57 | return peekLast(this);
58 | }
59 |
60 | /**
61 | * Remove the first element from list and return it.
62 | */
63 | public E pollFirst() {
64 | return pollFirst(this);
65 | }
66 |
67 | /**
68 | * Remove the last element from list and return it.
69 | */
70 | public E pollLast() {
71 | return pollLast(this);
72 | }
73 |
74 | /**
75 | * Expose this methods so we not need to create a new subList just to
76 | * remove a range of elements.
77 | *
78 | * Removes from this deque all of the elements whose index is between
79 | * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
80 | * Shifts any succeeding elements to the left (reduces their index).
81 | * This call shortens the deque by {@code (toIndex - fromIndex)} elements.
82 | * (If {@code toIndex==fromIndex}, this operation has no effect.)
83 | *
84 | * @throws IndexOutOfBoundsException if {@code fromIndex} or
85 | * {@code toIndex} is out of range
86 | * ({@code fromIndex < 0 ||
87 | * fromIndex >= size() ||
88 | * toIndex > size() ||
89 | * toIndex < fromIndex})
90 | */
91 | @Override
92 | public void removeRange(int fromIndex, int toIndex) {
93 | super.removeRange(fromIndex, toIndex);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/utils/AsciiStringUtil.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/10 15:43
5 | */
6 |
7 |
8 |
9 | /**
10 | * @author jiachun.fjc
11 | */
12 | public final class AsciiStringUtil {
13 |
14 | public static byte[] unsafeEncode(final CharSequence in) {
15 | final int len = in.length();
16 | final byte[] out = new byte[len];
17 | for (int i = 0; i < len; i++) {
18 | out[i] = (byte) in.charAt(i);
19 | }
20 | return out;
21 | }
22 |
23 | // public static String unsafeDecode(final byte[] in) {
24 | // final int len = in.length;
25 | // final char[] out = new char[len];
26 | // for (int i = 0; i < len; i++) {
27 | // out[i] = (char) (in[i] & 0xFF);
28 | // }
29 | // return UnsafeUtil.moveToString(out);
30 | // }
31 |
32 | // public static String unsafeDecode(final ByteString in) {
33 | // final int len = in.size();
34 | // final char[] out = new char[len];
35 | // for (int i = 0; i < len; i++) {
36 | // out[i] = (char) (in.byteAt(i) & 0xFF);
37 | // }
38 | // return UnsafeUtil.moveToString(out);
39 | // }
40 |
41 | private AsciiStringUtil() {
42 | }
43 | }
--------------------------------------------------------------------------------
/src/main/java/utils/Bits.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 16:49
5 | */
6 |
7 | /**
8 | * Moved from java.io.Bits
9 | *
10 | * @author boyan (boyan@alibaba-inc.com)
11 | */
12 | public class Bits {
13 | public static int getInt(byte[] b, int off) {
14 | return (b[off + 3] & 0xFF) + ((b[off + 2] & 0xFF) << 8) + ((b[off + 1] & 0xFF) << 16) + (b[off] << 24);
15 | }
16 |
17 | public static float getFloat(byte[] b, int off) {
18 | return Float.intBitsToFloat(getInt(b, off));
19 | }
20 |
21 | public static long getLong(byte[] b, int off) {
22 | return (b[off + 7] & 0xFFL) + ((b[off + 6] & 0xFFL) << 8) + ((b[off + 5] & 0xFFL) << 16)
23 | + ((b[off + 4] & 0xFFL) << 24) + ((b[off + 3] & 0xFFL) << 32) + ((b[off + 2] & 0xFFL) << 40)
24 | + ((b[off + 1] & 0xFFL) << 48) + ((long) b[off] << 56);
25 | }
26 |
27 | public static double getDouble(byte[] b, int off) {
28 | return Double.longBitsToDouble(getLong(b, off));
29 | }
30 |
31 | public static void putInt(byte[] b, int off, int val) {
32 | b[off + 3] = (byte) val;
33 | b[off + 2] = (byte) (val >>> 8);
34 | b[off + 1] = (byte) (val >>> 16);
35 | b[off] = (byte) (val >>> 24);
36 | }
37 |
38 | public static void putShort(byte[] b, int off, short val) {
39 | b[off + 1] = (byte) val;
40 | b[off] = (byte) (val >>> 8);
41 | }
42 |
43 | public static short getShort(byte[] b, int off) {
44 | return (short) ((b[off + 1] & 0xFF) + (b[off] << 8));
45 | }
46 |
47 | public static void putFloat(byte[] b, int off, float val) {
48 | putInt(b, off, Float.floatToIntBits(val));
49 | }
50 |
51 | public static void putLong(byte[] b, int off, long val) {
52 | b[off + 7] = (byte) val;
53 | b[off + 6] = (byte) (val >>> 8);
54 | b[off + 5] = (byte) (val >>> 16);
55 | b[off + 4] = (byte) (val >>> 24);
56 | b[off + 3] = (byte) (val >>> 32);
57 | b[off + 2] = (byte) (val >>> 40);
58 | b[off + 1] = (byte) (val >>> 48);
59 | b[off] = (byte) (val >>> 56);
60 | }
61 |
62 | public static void putDouble(byte[] b, int off, double val) {
63 | putLong(b, off, Double.doubleToLongBits(val));
64 | }
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/src/main/java/utils/BootYaml.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import entity.Options;
4 | import org.yaml.snakeyaml.Yaml;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.FileNotFoundException;
9 | import java.io.InputStream;
10 | import java.util.Map;
11 |
12 | /**
13 | * Created by 周思成 on 2020/3/27 11:18
14 | */
15 |
16 | public class BootYaml {
17 |
18 |
19 | public static Options getYaml(String yamlName) throws FileNotFoundException {
20 | Yaml yaml = new Yaml();// 这个需要的jar为:org.yaml.snakeyaml
21 |
22 | File file = new File(yamlName);
23 | //MailConfig 这个是这个主函数所在的类的类名
24 | // InputStream resourceAsStream = BootYaml.class.getClassLoader()
25 | // .getResourceAsStream(yamlName);
26 |
27 | InputStream resourceAsStream = new FileInputStream(file);
28 | //加载流,获取yaml文件中的配置数据,然后转换为Map,
29 | // Map obj = (Map) yaml.load(resourceAsStream);
30 | // return obj;
31 | //Options obj = (Options) yaml.load(resourceAsStream);
32 | return yaml.loadAs(resourceAsStream,Options.class);
33 |
34 | }
35 |
36 | public static void main(String[] args) {
37 | Yaml yaml = new Yaml();// 这个需要的jar为:org.yaml.snakeyaml
38 |
39 | //MailConfig 这个是这个主函数所在的类的类名
40 | InputStream resourceAsStream = BootYaml.class.getClassLoader()
41 | .getResourceAsStream("properties.yml");
42 |
43 | //加载流,获取yaml文件中的配置数据,然后转换为Map,
44 | //Options obj = (Options) yaml.load(resourceAsStream);
45 | Options obj = yaml.loadAs(resourceAsStream,Options.class);
46 | System.out.println(obj.getCurrentNodeOptions().getClientAddress());
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/utils/CatchUpClosure.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/14 16:29
5 | */
6 |
7 | import entity.Closure;
8 | import entity.Status;
9 |
10 | import java.util.concurrent.ScheduledFuture;
11 |
12 | /**
13 | * A catchup closure for peer to catch up.
14 | *
15 | * @author boyan (boyan@alibaba-inc.com)
16 | *
17 | * 2018-Apr-04 2:15:05 PM
18 | */
19 | public abstract class CatchUpClosure implements Closure {
20 |
21 | private long maxMargin;
22 | private ScheduledFuture> timer;
23 | private boolean hasTimer;
24 | private boolean errorWasSet;
25 |
26 | private final Status status = Status.OK();
27 |
28 | public Status getStatus() {
29 | return this.status;
30 | }
31 |
32 | public long getMaxMargin() {
33 | return this.maxMargin;
34 | }
35 |
36 | public void setMaxMargin(long maxMargin) {
37 | this.maxMargin = maxMargin;
38 | }
39 |
40 | public ScheduledFuture> getTimer() {
41 | return this.timer;
42 | }
43 |
44 | public void setTimer(ScheduledFuture> timer) {
45 | this.timer = timer;
46 | this.hasTimer = true;
47 | }
48 |
49 | public boolean hasTimer() {
50 | return this.hasTimer;
51 | }
52 |
53 | public boolean isErrorWasSet() {
54 | return this.errorWasSet;
55 | }
56 |
57 | public void setErrorWasSet(boolean errorWasSet) {
58 | this.errorWasSet = errorWasSet;
59 | }
60 | }
--------------------------------------------------------------------------------
/src/main/java/utils/Copiable.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 16:45
5 | */
6 |
7 | public interface Copiable {
8 |
9 | /**
10 | * Copy current object(deep-clone).
11 | */
12 | T copy();
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/utils/CrcUtil.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/10 15:32
5 | */
6 |
7 | import java.nio.ByteBuffer;
8 |
9 | /**
10 | * CRC utilities to compute CRC64 checksum.
11 | *
12 | * @author boyan(boyan@antfin.com)
13 | */
14 | public final class CrcUtil {
15 |
16 | private static final ThreadLocal CRC_64_THREAD_LOCAL = ThreadLocal.withInitial(CRC64::new);
17 |
18 | /**
19 | * Compute CRC64 checksum for byte[].
20 | *
21 | * @param array source array
22 | * @return checksum value
23 | */
24 | public static long crc64(final byte[] array) {
25 | if (array == null) {
26 | return 0;
27 | }
28 | return crc64(array, 0, array.length);
29 | }
30 |
31 | /**
32 | * Compute CRC64 checksum for byte[].
33 | *
34 | * @param array source array
35 | * @param offset starting position in the source array
36 | * @param length the number of array elements to be computed
37 | * @return checksum value
38 | */
39 | public static long crc64(final byte[] array, final int offset, final int length) {
40 | final CRC64 crc64 = CRC_64_THREAD_LOCAL.get();
41 | crc64.update(array, offset, length);
42 | final long ret = crc64.getValue();
43 | crc64.reset();
44 | return ret;
45 | }
46 |
47 | /**
48 | * Compute CRC64 checksum for {@code ByteBuffer}.
49 | *
50 | * @param buf source {@code ByteBuffer}
51 | * @return checksum value
52 | */
53 | public static long crc64(final ByteBuffer buf) {
54 | final int pos = buf.position();
55 | final int rem = buf.remaining();
56 | if (rem <= 0) {
57 | return 0;
58 | }
59 | // Currently we have not used DirectByteBuffer yet.
60 | if (buf.hasArray()) {
61 | return crc64(buf.array(), pos + buf.arrayOffset(), rem);
62 | }
63 | final byte[] b = new byte[rem];
64 | buf.mark();
65 | buf.get(b);
66 | buf.reset();
67 | return crc64(b);
68 | }
69 |
70 | private CrcUtil() {
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/utils/DisruptorBuilder.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import com.alipay.remoting.NamedThreadFactory;
4 | import com.lmax.disruptor.BlockingWaitStrategy;
5 | import com.lmax.disruptor.EventFactory;
6 | import com.lmax.disruptor.WaitStrategy;
7 | import com.lmax.disruptor.dsl.Disruptor;
8 | import com.lmax.disruptor.dsl.ProducerType;
9 |
10 | import java.util.concurrent.ThreadFactory;
11 |
12 | /**
13 | * Created by 周思成 on 2020/4/9 21:11
14 | */
15 |
16 | public class DisruptorBuilder {
17 | private EventFactory eventFactory;
18 | private Integer ringBufferSize;
19 | private ThreadFactory threadFactory = new NamedThreadFactory("Disruptor",true);
20 | private ProducerType producerType = ProducerType.MULTI;
21 | private WaitStrategy waitStrategy = new BlockingWaitStrategy();
22 |
23 | private DisruptorBuilder() {
24 | }
25 |
26 | public static DisruptorBuilder newInstance() {
27 | return new DisruptorBuilder<>();
28 | }
29 |
30 | public EventFactory getEventFactory() {
31 | return this.eventFactory;
32 | }
33 |
34 | public DisruptorBuilder setEventFactory(final EventFactory eventFactory) {
35 | this.eventFactory = eventFactory;
36 | return this;
37 | }
38 |
39 | public int getRingBufferSize() {
40 | return this.ringBufferSize;
41 | }
42 |
43 | public DisruptorBuilder setRingBufferSize(final int ringBufferSize) {
44 | this.ringBufferSize = ringBufferSize;
45 | return this;
46 | }
47 |
48 | public ThreadFactory getThreadFactory() {
49 | return this.threadFactory;
50 | }
51 |
52 | public DisruptorBuilder setThreadFactory(final ThreadFactory threadFactory) {
53 | this.threadFactory = threadFactory;
54 | return this;
55 | }
56 |
57 | public ProducerType getProducerType() {
58 | return this.producerType;
59 | }
60 |
61 | public DisruptorBuilder setProducerType(final ProducerType producerType) {
62 | this.producerType = producerType;
63 | return this;
64 | }
65 |
66 | public WaitStrategy getWaitStrategy() {
67 | return this.waitStrategy;
68 | }
69 |
70 | public DisruptorBuilder setWaitStrategy(final WaitStrategy waitStrategy) {
71 | this.waitStrategy = waitStrategy;
72 | return this;
73 | }
74 |
75 | public Disruptor build() {
76 | Requires.requireNonNull(this.ringBufferSize, " Ring buffer size not set");
77 | Requires.requireNonNull(this.eventFactory, "Event factory not set");
78 | return new Disruptor<>(this.eventFactory, this.ringBufferSize, this.threadFactory, this.producerType,
79 | this.waitStrategy);
80 | }
81 |
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/utils/Ints.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 22:58
5 | */
6 |
7 | public class Ints {
8 |
9 | /**
10 | * Fast method of finding the next power of 2 greater than or equal to the supplied value.
11 | *
12 | * If the value is {@code <= 0} then 1 will be returned.
13 | * This method is not suitable for {@link Integer#MIN_VALUE} or numbers greater than 2^30.
14 | *
15 | * @param value from which to search for next power of 2
16 | * @return The next power of 2 or the value itself if it is a power of 2
17 | */
18 | public static int findNextPositivePowerOfTwo(final int value) {
19 | return value <= 0 ? 1 : value >= 0x40000000 ? 0x40000000 : 1 << (32 - Integer.numberOfLeadingZeros(value - 1));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/utils/LogThreadPoolExecutor.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 |
6 | import java.util.concurrent.*;
7 |
8 | /**
9 | * Created by 周思成 on 2020/3/13 22:15
10 | */
11 |
12 | public class LogThreadPoolExecutor extends ThreadPoolExecutor {
13 |
14 | private static final Logger LOG = LoggerFactory.getLogger(LogThreadPoolExecutor.class);
15 |
16 | private final String name;
17 |
18 | public LogThreadPoolExecutor(int coreThreads, int maximumThreads
19 | , long keepAliveSeconds, TimeUnit unit, BlockingQueue workQueue
20 | , ThreadFactory threadFactory, RejectedExecutionHandler handler, String poolName) {
21 |
22 | super(coreThreads,maximumThreads,keepAliveSeconds,unit,workQueue,threadFactory,handler);
23 | this.name = poolName;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/utils/NonReentrantLock.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/14 16:21
5 | */
6 |
7 | import java.util.concurrent.TimeUnit;
8 | import java.util.concurrent.locks.AbstractQueuedSynchronizer;
9 | import java.util.concurrent.locks.Condition;
10 | import java.util.concurrent.locks.Lock;
11 |
12 | /**
13 | * Non reentrant lock, copied from netty project.
14 | */
15 | public final class NonReentrantLock extends AbstractQueuedSynchronizer implements Lock {
16 |
17 | private static final long serialVersionUID = -833780837233068610L;
18 |
19 | private Thread owner;
20 |
21 | @Override
22 | public void lock() {
23 | acquire(1);
24 | }
25 |
26 | @Override
27 | public void lockInterruptibly() throws InterruptedException {
28 | acquireInterruptibly(1);
29 | }
30 |
31 | @Override
32 | public boolean tryLock() {
33 | return tryAcquire(1);
34 | }
35 |
36 | @Override
37 | public boolean tryLock(final long time, final TimeUnit unit) throws InterruptedException {
38 | return tryAcquireNanos(1, unit.toNanos(time));
39 | }
40 |
41 | @Override
42 | public void unlock() {
43 | release(1);
44 | }
45 |
46 | public boolean isHeldByCurrentThread() {
47 | return isHeldExclusively();
48 | }
49 |
50 | public Thread getOwner() {
51 | return this.owner;
52 | }
53 |
54 | @Override
55 | public Condition newCondition() {
56 | return new ConditionObject();
57 | }
58 |
59 | @Override
60 | protected boolean tryAcquire(final int acquires) {
61 | if (compareAndSetState(0, 1)) {
62 | this.owner = Thread.currentThread();
63 | return true;
64 | }
65 | return false;
66 | }
67 |
68 | @Override
69 | protected boolean tryRelease(final int releases) {
70 | if (Thread.currentThread() != this.owner) {
71 | throw new IllegalMonitorStateException("Owner is " + this.owner);
72 | }
73 | this.owner = null;
74 | setState(0);
75 | return true;
76 | }
77 |
78 | @Override
79 | protected boolean isHeldExclusively() {
80 | return getState() != 0 && this.owner == Thread.currentThread();
81 | }
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/src/main/java/utils/RandomTimeUtil.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/24 14:36
5 | */
6 |
7 | public class RandomTimeUtil {
8 |
9 |
10 | public static long newRandomTime(long begin,long end){
11 | long rtn = begin + (long)(Math.random() * (end - begin));
12 | // 如果返回的是开始时间和结束时间,则递归调用本函数查找随机值
13 | if(rtn == begin || rtn == end){
14 | return newRandomTime(begin,end);
15 | }
16 | return rtn;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/utils/Recyclable.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/12 15:18
5 | */
6 |
7 | public interface Recyclable {
8 | /**
9 | * Recycle this instance.
10 | */
11 | boolean recycle();
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/utils/RecycleUtil.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Recycle tool for {@link Recyclable}.
5 | *
6 | * @author jiachun.fjc
7 | */
8 | public final class RecycleUtil {
9 |
10 | /**
11 | * Recycle designated instance.
12 | */
13 | public static boolean recycle(final Object obj) {
14 | return obj instanceof Recyclable && ((Recyclable) obj).recycle();
15 | }
16 |
17 | private RecycleUtil() {
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/utils/Requires.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/13 15:27
5 | */
6 | /**
7 | * Simple static methods to be called at the start of your own methods to verify
8 | * correct arguments and state.
9 | *
10 | * @author jiachun.fjc
11 | */
12 | public final class Requires {
13 |
14 | /**
15 | * Checks that the specified object reference is not {@code null}.
16 | *
17 | * @param obj the object reference to check for nullity
18 | * @param the type of the reference
19 | * @return {@code obj} if not {@code null}
20 | * @throws NullPointerException if {@code obj} is {@code null}
21 | */
22 | public static T requireNonNull(T obj) {
23 | if (obj == null) {
24 | throw new NullPointerException();
25 | }
26 | return obj;
27 | }
28 |
29 | /**
30 | * Checks that the specified object reference is not {@code null} and
31 | * throws a customized {@link NullPointerException} if it is.
32 | *
33 | * @param obj the object reference to check for nullity
34 | * @param message detail message to be used in the event that a {@code
35 | * NullPointerException} is thrown
36 | * @param the type of the reference
37 | * @return {@code obj} if not {@code null}
38 | * @throws NullPointerException if {@code obj} is {@code null}
39 | */
40 | public static T requireNonNull(T obj, String message) {
41 | if (obj == null) {
42 | throw new NullPointerException(message);
43 | }
44 | return obj;
45 | }
46 |
47 | /**
48 | * Ensures the truth of an expression involving one or more parameters
49 | * to the calling method.
50 | *
51 | * @param expression a boolean expression
52 | * @throws IllegalArgumentException if {@code expression} is false
53 | */
54 | public static void requireTrue(boolean expression) {
55 | if (!expression) {
56 | throw new IllegalArgumentException();
57 | }
58 | }
59 |
60 | /**
61 | * Ensures the truth of an expression involving one or more parameters
62 | * to the calling method.
63 | *
64 | * @param expression a boolean expression
65 | * @param message the exception message to use if the check fails;
66 | * will be converted to a string using
67 | * {@link String#valueOf(Object)}
68 | * @throws IllegalArgumentException if {@code expression} is false
69 | */
70 | public static void requireTrue(boolean expression, Object message) {
71 | if (!expression) {
72 | throw new IllegalArgumentException(String.valueOf(message));
73 | }
74 | }
75 |
76 | /**
77 | * Ensures the truth of an expression involving one or more parameters
78 | * to the calling method.
79 | *
80 | * @param expression a boolean expression
81 | * @param fmt the exception message with format string
82 | * @param args arguments referenced by the format specifiers in the format
83 | * string
84 | * @throws IllegalArgumentException if {@code expression} is false
85 | */
86 | public static void requireTrue(boolean expression, String fmt, Object... args) {
87 | if (!expression) {
88 | throw new IllegalArgumentException(String.format(fmt, args));
89 | }
90 | }
91 |
92 | private Requires() {
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/utils/ThreadId.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/14 15:34
5 | */
6 |
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collections;
12 | import java.util.List;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * Replicator id with lock.
17 | *
18 | * @author boyan (boyan@alibaba-inc.com)
19 | *
20 | * 2018-Mar-29 10:59:47 AM
21 | */
22 | public class ThreadId {
23 |
24 | private static final Logger LOG = LoggerFactory.getLogger(ThreadId.class);
25 |
26 | private static final int TRY_LOCK_TIMEOUT_MS = 10;
27 |
28 | private final Object data;
29 | private final NonReentrantLock lock = new NonReentrantLock();
30 | private final List pendingErrors = Collections.synchronizedList(new ArrayList<>());
31 | private final OnError onError;
32 | private volatile boolean destroyed;
33 |
34 | /**
35 | * @author boyan (boyan@alibaba-inc.com)
36 | *
37 | * 2018-Mar-29 11:01:54 AM
38 | */
39 | public interface OnError {
40 |
41 | /**
42 | * Error callback, it will be called in lock, but should take care of unlocking it.
43 | *
44 | * @param id the thread id
45 | * @param data the data
46 | * @param errorCode the error code
47 | */
48 | void onError(final ThreadId id, final Object data, final int errorCode);
49 | }
50 |
51 | public ThreadId(final Object data, final OnError onError) {
52 | super();
53 | this.data = data;
54 | this.onError = onError;
55 | this.destroyed = false;
56 | }
57 |
58 | public Object getData() {
59 | return this.data;
60 | }
61 |
62 | public Object lock() {
63 | if (this.destroyed) {
64 | return null;
65 | }
66 | try {
67 | while (!this.lock.tryLock(TRY_LOCK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
68 | if (this.destroyed) {
69 | return null;
70 | }
71 | }
72 | } catch (final InterruptedException e) {
73 | Thread.currentThread().interrupt(); // reset
74 | return null;
75 | }
76 | // Got the lock, double checking state.
77 | if (this.destroyed) {
78 | // should release lock
79 | this.lock.unlock();
80 | return null;
81 | }
82 | return this.data;
83 | }
84 |
85 | public void unlock() {
86 | if (!this.lock.isHeldByCurrentThread()) {
87 | LOG.warn("Fail to unlock with {}, the lock is held by {} and current thread is {}.", this.data,
88 | this.lock.getOwner(), Thread.currentThread());
89 | return;
90 | }
91 | // calls all pending errors before unlock
92 | boolean doUnlock = true;
93 | try {
94 | final List errors;
95 | synchronized (this.pendingErrors) {
96 | errors = new ArrayList<>(this.pendingErrors);
97 | this.pendingErrors.clear();
98 | }
99 | for (final Integer code : errors) {
100 | // The lock will be unlocked in onError.
101 | doUnlock = false;
102 | if (this.onError != null) {
103 | this.onError.onError(this, this.data, code);
104 | }
105 | }
106 | } finally {
107 | if (doUnlock) {
108 | this.lock.unlock();
109 | }
110 | }
111 | }
112 |
113 | public void join() {
114 | while (!this.destroyed) {
115 | Thread.yield();
116 | }
117 | }
118 |
119 | @Override
120 | public String toString() {
121 | return this.data.toString();
122 | }
123 |
124 | public void unlockAndDestroy() {
125 | if (this.destroyed) {
126 | return;
127 | }
128 | this.destroyed = true;
129 | if (!this.lock.isHeldByCurrentThread()) {
130 | LOG.warn("Fail to unlockAndDestroy with {}, the lock is held by {} and current thread is {}.", this.data,
131 | this.lock.getOwner(), Thread.currentThread());
132 | return;
133 | }
134 | this.lock.unlock();
135 | }
136 |
137 | /**
138 | * Set error code, if it tryLock success, run the onError callback
139 | * with code immediately, else add it into pending errors and will
140 | * be called before unlock.
141 | *
142 | * @param errorCode error code
143 | */
144 | public void setError(final int errorCode) {
145 | if (this.destroyed) {
146 | return;
147 | }
148 | if (this.lock.tryLock()) {
149 | if (this.destroyed) {
150 | this.lock.unlock();
151 | return;
152 | }
153 | if (this.onError != null) {
154 | // The lock will be unlocked in onError.
155 | this.onError.onError(this, this.data, errorCode);
156 | }
157 | } else {
158 | this.pendingErrors.add(errorCode);
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/src/main/java/utils/ThreadPoolUtil.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | import java.util.concurrent.*;
4 |
5 | /**
6 | * Created by 周思成 on 2020/3/13 22:08
7 | */
8 |
9 | public class ThreadPoolUtil {
10 |
11 | /**
12 | * The default rejected execution handler
13 | */
14 | private static final RejectedExecutionHandler defaultHandler = new ThreadPoolExecutor.AbortPolicy();
15 |
16 | public static PoolBuilder newBuilder() {
17 | return new PoolBuilder();
18 | }
19 |
20 |
21 | /**
22 | * Creates a new {@code MetricThreadPoolExecutor} or {@code LogThreadPoolExecutor}
23 | * with the given initial parameters.
24 | *
25 | * @param poolName the name of the thread pool
26 | * @param coreThreads the number of threads to keep in the pool, even if they are
27 | * idle, unless {@code allowCoreThreadTimeOut} is set.
28 | * @param maximumThreads the maximum number of threads to allow in the pool
29 | * @param keepAliveSeconds when the number of threads is greater than the core, this
30 | * is the maximum time (seconds) that excess idle threads will
31 | * wait for new tasks before terminating.
32 | * @param workQueue the queue to use for holding tasks before they are executed.
33 | * This queue will hold only the {@code Runnable} tasks submitted
34 | * by the {@code execute} method.
35 | * @param threadFactory the factory to use when the executor creates a new thread
36 | * @param handler the handler to use when execution is blocked because the
37 | * thread bounds and queue capacities are reached
38 | * @throws IllegalArgumentException if one of the following holds:
39 | * {@code corePoolSize < 0}
40 | * {@code keepAliveSeconds < 0}
41 | * {@code maximumPoolSize <= 0}
42 | * {@code maximumPoolSize < corePoolSize}
43 | * @throws NullPointerException if {@code workQueue}
44 | * or {@code threadFactory} or {@code handler} is null
45 | */
46 | public static ThreadPoolExecutor newThreadPool(final String poolName,
47 | final int coreThreads, final int maximumThreads,
48 | final long keepAliveSeconds,
49 | final BlockingQueue workQueue,
50 | final ThreadFactory threadFactory,
51 | final RejectedExecutionHandler handler) {
52 | final TimeUnit unit = TimeUnit.SECONDS;
53 |
54 | return new LogThreadPoolExecutor(coreThreads, maximumThreads, keepAliveSeconds, unit, workQueue,
55 | threadFactory, handler, poolName);
56 |
57 | }
58 |
59 |
60 | private ThreadPoolUtil() {
61 | }
62 |
63 |
64 | public static class PoolBuilder {
65 | private String poolName;
66 |
67 | private Integer coreThreads;
68 | private Integer maximumThreads;
69 | private Long keepAliveSeconds;
70 | private BlockingQueue workQueue;
71 | private ThreadFactory threadFactory;
72 | private RejectedExecutionHandler handler = ThreadPoolUtil.defaultHandler;
73 |
74 | public PoolBuilder poolName(final String poolName) {
75 | this.poolName = poolName;
76 | return this;
77 | }
78 |
79 |
80 |
81 | public PoolBuilder coreThreads(final Integer coreThreads) {
82 | this.coreThreads = coreThreads;
83 | return this;
84 | }
85 |
86 | public PoolBuilder maximumThreads(final Integer maximumThreads) {
87 | this.maximumThreads = maximumThreads;
88 | return this;
89 | }
90 |
91 | public PoolBuilder keepAliveSeconds(final Long keepAliveSeconds) {
92 | this.keepAliveSeconds = keepAliveSeconds;
93 | return this;
94 | }
95 |
96 | public PoolBuilder workQueue(final BlockingQueue workQueue) {
97 | this.workQueue = workQueue;
98 | return this;
99 | }
100 |
101 | public PoolBuilder threadFactory(final ThreadFactory threadFactory) {
102 | this.threadFactory = threadFactory;
103 | return this;
104 | }
105 |
106 | public PoolBuilder rejectedHandler(final RejectedExecutionHandler handler) {
107 | this.handler = handler;
108 | return this;
109 | }
110 |
111 | public ThreadPoolExecutor build() {
112 | Requires.requireNonNull(this.poolName, "poolName");
113 |
114 | Requires.requireNonNull(this.coreThreads, "coreThreads");
115 | Requires.requireNonNull(this.maximumThreads, "maximumThreads");
116 | Requires.requireNonNull(this.keepAliveSeconds, "keepAliveSeconds");
117 | Requires.requireNonNull(this.workQueue, "workQueue");
118 | Requires.requireNonNull(this.threadFactory, "threadFactory");
119 | Requires.requireNonNull(this.handler, "handler");
120 |
121 | return ThreadPoolUtil.newThreadPool(this.poolName, this.coreThreads,
122 | this.maximumThreads, this.keepAliveSeconds, this.workQueue, this.threadFactory, this.handler);
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/src/main/java/utils/TimeHelper.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/3/12 13:49
5 | */
6 | import org.joda.time.DateTime;
7 | /**
8 | * 全局时间工具
9 | * 单例模式
10 | */
11 | public class TimeHelper {
12 |
13 | private static DateTime dateTime = new DateTime();
14 |
15 | private TimeHelper(){}
16 |
17 | public static DateTime getDateTime(){
18 | return dateTime;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/utils/TimerManager.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | /**
4 | * Created by 周思成 on 2020/4/5 23:49
5 | */
6 |
7 | import com.alipay.remoting.NamedThreadFactory;
8 | import core.Lifecycle;
9 |
10 | import java.util.concurrent.Executors;
11 | import java.util.concurrent.ScheduledExecutorService;
12 | import java.util.concurrent.ScheduledFuture;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | /**
16 | * The global timer manager.
17 | *
18 | * @author boyan (boyan@alibaba-inc.com)
19 | *
20 | * 2018-Mar-30 3:24:34 PM
21 | */
22 | public class TimerManager implements Lifecycle {
23 |
24 | private ScheduledExecutorService executor;
25 |
26 | @Override
27 | public boolean init(Integer coreSize) {
28 | this.executor = Executors.newScheduledThreadPool(coreSize, new NamedThreadFactory(
29 | "JRaft-Node-ScheduleThreadPool-", true));
30 | return true;
31 | }
32 |
33 | @Override
34 | public void shutdown() {
35 | if (this.executor != null) {
36 | this.executor.shutdownNow();
37 | this.executor = null;
38 | }
39 | }
40 |
41 | private void checkStarted() {
42 | if (this.executor == null) {
43 | throw new IllegalStateException("Please init timer manager.");
44 | }
45 | }
46 |
47 | public ScheduledFuture> schedule(final Runnable command, final long delay, final TimeUnit unit) {
48 | checkStarted();
49 | return this.executor.schedule(command, delay, unit);
50 | }
51 |
52 | public ScheduledFuture> scheduleAtFixedRate(final Runnable command, final long initialDelay, final long period,
53 | final TimeUnit unit) {
54 | checkStarted();
55 | return this.executor.scheduleAtFixedRate(command, initialDelay, period, unit);
56 | }
57 |
58 | public ScheduledFuture> scheduleWithFixedDelay(final Runnable command, final long initialDelay, final long delay,
59 | final TimeUnit unit) {
60 | checkStarted();
61 | return this.executor.scheduleWithFixedDelay(command, initialDelay, delay, unit);
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/src/main/java/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package utils;
2 |
3 | //import com.alipay.remoting.NamedThreadFactory;
4 | import com.alipay.sofa.rpc.common.struct.NamedThreadFactory;
5 | import entity.Closure;
6 | import entity.Status;
7 | import io.netty.util.internal.SystemPropertyUtil;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.concurrent.Future;
12 | import java.util.concurrent.SynchronousQueue;
13 | import java.util.concurrent.ThreadPoolExecutor;
14 | import java.util.concurrent.TimeUnit;
15 | import java.util.regex.Pattern;
16 |
17 | /**
18 | * Created by 周思成 on 2020/3/10 15:18
19 | * @author Mike
20 | */
21 |
22 | public class Utils {
23 |
24 |
25 | /**
26 | * ANY IP address 0.0.0.0
27 | */
28 | public static final String IP_ANY = "0.0.0.0";
29 |
30 |
31 | private static final Logger LOG = LoggerFactory.getLogger(Utils.class);
32 |
33 | /**
34 | * The configured number of available processors. The default is {@link Runtime#availableProcessors()}.
35 | * This can be overridden by setting the system property "jraft.available_processors".
36 | */
37 | private static final int CPUS = SystemPropertyUtil.getInt(
38 | "jraft.available_processors", Runtime
39 | .getRuntime().availableProcessors());
40 |
41 | /**
42 | * Default jraft closure executor pool minimum size, CPUs by default.
43 | */
44 | public static final int MIN_CLOSURE_EXECUTOR_POOL_SIZE = SystemPropertyUtil.getInt(
45 | "jraft.closure.threadpool.size.min",
46 | cpus());
47 |
48 | /**
49 | * Default jraft closure executor pool maximum size.
50 | */
51 | public static final int MAX_CLOSURE_EXECUTOR_POOL_SIZE = SystemPropertyUtil.getInt(
52 | "jraft.closure.threadpool.size.max",
53 | Math.max(100, cpus() * 5));
54 |
55 | /**
56 | * Default jraft append-entries executor(send) pool size.
57 | */
58 | public static final int APPEND_ENTRIES_THREADS_SEND = SystemPropertyUtil
59 | .getInt(
60 | "jraft.append.entries.threads.send",
61 | Math.max(
62 | 16,
63 | Ints.findNextPositivePowerOfTwo(cpus() * 2)));
64 |
65 | /**
66 | * Default jraft max pending tasks of append-entries per thread, 65536 by default.
67 | */
68 | public static final int MAX_APPEND_ENTRIES_TASKS_PER_THREAD = SystemPropertyUtil
69 | .getInt(
70 | "jraft.max.append.entries.tasks.per.thread",
71 | 32768);
72 |
73 | /**
74 | * Whether use {@link com.alipay.sofa.jraft.util.concurrent.MpscSingleThreadExecutor}, true by default.
75 | */
76 | public static final boolean USE_MPSC_SINGLE_THREAD_EXECUTOR = SystemPropertyUtil.getBoolean(
77 | "jraft.use.mpsc.single.thread.executor",
78 | true);
79 |
80 | /**
81 | * Global thread pool to run closure.
82 | */
83 | private static ThreadPoolExecutor CLOSURE_EXECUTOR = ThreadPoolUtil
84 | .newBuilder()
85 | .poolName("JRAFT_CLOSURE_EXECUTOR")
86 |
87 | .coreThreads(
88 | MIN_CLOSURE_EXECUTOR_POOL_SIZE)
89 | .maximumThreads(
90 | MAX_CLOSURE_EXECUTOR_POOL_SIZE)
91 | .keepAliveSeconds(60L)
92 | .workQueue(new SynchronousQueue<>())
93 | .threadFactory(
94 | new NamedThreadFactory(
95 | "JRaft-Closure-Executor-", true))
96 | .build();
97 |
98 | private static final Pattern GROUP_ID_PATTER = Pattern
99 | .compile("^[a-zA-Z][a-zA-Z0-9\\-_]*$");
100 |
101 | /**
102 | * Get system CPUs count.
103 | */
104 | public static int cpus() {
105 | return CPUS;
106 | }
107 | public static long monotonicMs() {
108 | return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
109 | }
110 |
111 | /**
112 | * Run a task in thread pool,returns the future object.
113 | */
114 | public static Future> runInThread(final Runnable runnable) {
115 | return CLOSURE_EXECUTOR.submit(runnable);
116 | }
117 |
118 | public static Future> runInThreadPool(final Runnable runnable) {
119 | return CLOSURE_EXECUTOR.submit(runnable);
120 | }
121 |
122 | public static Future> runClosureInThread(final Closure done, final Status status) {
123 | if (done == null) {
124 | return null;
125 | }
126 | return runInThread(() -> {
127 | try {
128 | done.run(status);
129 | } catch (final Throwable t) {
130 | LOG.error("Fail to run done closure", t);
131 | }
132 | });
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/utils/ZeroByteStringHelper.java:
--------------------------------------------------------------------------------
1 | //package com.google.protobuf;
2 | //
3 | //import com.google.protobuf.ByteString;
4 | //import com.google.protobuf.RopeByteString;
5 | //
6 | //import java.io.IOException;
7 | //import java.nio.ByteBuffer;
8 | //import java.util.List;
9 | //
10 | ///**
11 | // * Created by 周思成 on 2020/4/17 15:26
12 | // */
13 | //public class ZeroByteStringHelper {
14 | //
15 | // /**
16 | // * Wrap a byte array into a ByteString.
17 | // */
18 | // public static ByteString wrap(final byte[] bs) {
19 | // return ByteString.wrap(bs);
20 | // }
21 | //
22 | // /**
23 | // * Wrap a byte array into a ByteString.
24 | // * @param bs the byte array
25 | // * @param offset read start offset in array
26 | // * @param len read data length
27 | // *@return the result byte string.
28 | // */
29 | // public static ByteString wrap(final byte[] bs, final int offset, final int len) {
30 | // return ByteString.wrap(bs, offset, len);
31 | // }
32 | //
33 | // /**
34 | // * Wrap a byte buffer into a ByteString.
35 | // */
36 | // public static ByteString wrap(final ByteBuffer buf) {
37 | // return ByteString.wrap(buf);
38 | // }
39 | //
40 | // /**
41 | // * Carry the byte[] from {@link ByteString}, if failed,
42 | // * then call {@link ByteString#toByteArray()}.
43 | // *
44 | // * @param byteString the byteString source data
45 | // * @return carried bytes
46 | // */
47 | // public static byte[] getByteArray(final ByteString byteString) {
48 | // final BytesCarrier carrier = new BytesCarrier();
49 | // try {
50 | // byteString.writeTo(carrier);
51 | // if (carrier.isValid()) {
52 | // return carrier.getValue();
53 | // }
54 | // } catch (final IOException ignored) {
55 | // // ignored
56 | // }
57 | // return byteString.toByteArray();
58 | // }
59 | //
60 | // /**
61 | // * Concatenate the given strings while performing various optimizations to
62 | // * slow the growth rate of tree depth and tree node count. The result is
63 | // * either a {@link com.google.protobuf.ByteString.LeafByteString} or a
64 | // * {@link RopeByteString} depending on which optimizations, if any, were
65 | // * applied.
66 | // *
67 | // * Small pieces of length less than {@link
68 | // * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in
69 | // * BAP95. Large pieces are referenced without copy.
70 | // *
71 | // *
Most of the operation here is inspired by the now-famous paper
73 | // *
74 | // * @param left string on the left
75 | // * @param right string on the right
76 | // * @return concatenation representing the same sequence as the given strings
77 | // */
78 | // public static ByteString concatenate(final ByteString left, final ByteString right) {
79 | // return RopeByteString.concatenate(left, right);
80 | // }
81 | //
82 | // /**
83 | // * @see #concatenate(ByteString, ByteString)
84 | // */
85 | // public static ByteString concatenate(final List byteBuffers) {
86 | // final int size = byteBuffers.size();
87 | // if (size == 0) {
88 | // return null;
89 | // }
90 | // if (size == 1) {
91 | // return wrap(byteBuffers.get(0));
92 | // }
93 | //
94 | // ByteString left = null;
95 | // for (final ByteBuffer buf : byteBuffers) {
96 | // if (buf.remaining() > 0) {
97 | // if (left == null) {
98 | // left = wrap(buf);
99 | // } else {
100 | // left = concatenate(left, wrap(buf));
101 | // }
102 | // }
103 | // }
104 | // return left;
105 | // }
106 | //}
107 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/service.RaftServiceFactory:
--------------------------------------------------------------------------------
1 | service.RaftServiceFactoryImpl
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoderiGenius/RocksRaft/e1365c67cceb5549d31d12f9452584bb15e786e2/src/main/resources/log4j.properties
--------------------------------------------------------------------------------
/src/main/resources/properties.yml:
--------------------------------------------------------------------------------
1 | currentNodeOptions:
2 | electionTimeOut: 1000
3 | maxHeartBeatTime: 1000
4 | rpcProtocol: bolt
5 | serialization: protobuf
6 | port: 12200
7 | taskPort: 12201
8 | taskExecuteMethod: callback
9 | daemon: false
10 | groupId: raft
11 | address: localhost
12 | name: raft-1
13 | peerId: raft-1
14 | logStoragePath: src/main/resources/Rocksdb1
15 | logStorageName: log
16 | clientAddress: localhost
17 | clientPort: 12299
18 | otherNodes:
19 | - {peerId: raft-2,
20 | name: raft-2,
21 | address: localhost,
22 | taskPort: 12221,
23 | port: 12220}
24 | - {peerId: raft-3,
25 | name: raft-3,
26 | address: localhost,
27 | taskPort: 12231,
28 | port: 12230}
29 | # - {peerId: raft-4,
30 | # name: raft-4,
31 | # address: 192.168.1.10,
32 | # taskPort: 12201,
33 | # port: 12000}
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/resources/properties2.yml:
--------------------------------------------------------------------------------
1 | currentNodeOptions:
2 | electionTimeOut: 3000
3 | maxHeartBeatTime: 1000
4 | rpcProtocol: bolt
5 | serialization: protobuf
6 | port: 12220
7 | taskPort: 12221
8 | taskExecuteMethod: callback
9 | daemon: false
10 | groupId: raft
11 | address: localhost
12 | name: raft-2
13 | peerId: raft-2
14 | logStoragePath: src/main/resources/Rocksdb1
15 | logStorageName: log2
16 | clientAddress: localhost
17 | clientPort: 12299
18 | otherNodes:
19 | - {peerId: raft-1,
20 | name: raft-1,
21 | address: localhost,
22 | taskPort: 12201,
23 | port: 12200}
24 | - {peerId: raft-3,
25 | name: raft-3,
26 | address: localhost,
27 | taskPort: 12231,
28 | port: 12230}
29 | # - {peerId: raft-4,
30 | # name: raft-4,
31 | # address: 192.168.1.10,
32 | # taskPort: 12201,
33 | # port: 12000}
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/resources/properties3.yml:
--------------------------------------------------------------------------------
1 | currentNodeOptions:
2 | electionTimeOut: 3000
3 | maxHeartBeatTime: 1000
4 | rpcProtocol: bolt
5 | serialization: protobuf
6 | port: 12230
7 | taskPort: 12231
8 | taskExecuteMethod: callback
9 | daemon: false
10 | groupId: raft
11 | address: localhost
12 | name: raft-3
13 | peerId: raft-3
14 | logStoragePath: src/main/resources/Rocksdb1
15 | logStorageName: log3
16 | clientAddress: localhost
17 | clientPort: 12299
18 | otherNodes:
19 | - {peerId: raft-2,
20 | name: raft-2,
21 | address: localhost,
22 | taskPort: 12221,
23 | port: 12220}
24 | - {peerId: raft-1,
25 | name: raft-1,
26 | address: localhost,
27 | taskPort: 12201,
28 | port: 12200}
29 | # - {peerId: raft-4,
30 | # name: raft-4,
31 | # address: 192.168.1.10,
32 | # taskPort: 12201,
33 | # port: 12000}
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/resources/protobuf/RPC.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | option java_package = "rpc";
3 | package protobuf;
4 | option java_outer_classname = "RpcRequests";
5 | import "raft.proto";
6 |
7 | message PingRequest {
8 | int64 send_timestamp = 1;
9 | }
10 | enum AppendEntriesStatus{
11 | APPROVED = 0;
12 | FAILED = 1;
13 | }
14 | message AppendEntriesRequests{
15 | repeated AppendEntriesRequest args = 1;
16 |
17 |
18 | }
19 |
20 | message AppendEntriesResponses{
21 | repeated AppendEntriesResponse args = 1;
22 | AppendEntriesStatus appendEntriesStatus = 2;
23 | }
24 |
25 | message ErrorResponse{
26 | int64 errorCode = 1;
27 | string errorMsg = 2;
28 | }
29 |
30 | message TimeoutNowRequest{
31 | string server_id = 1;
32 | string peer_id = 2;
33 | int64 term = 3;
34 | }
35 | message TimeoutNowResponse{
36 | int64 term = 1;
37 | bool success = 2;
38 | }
39 |
40 | message RequestVoteRequest {
41 | string server_id = 1;
42 | string peer_id = 2;
43 | int64 term = 3;
44 | int64 committed_log_term = 4;
45 | int64 committed_log_index = 5;
46 | bool pre_vote = 6;
47 | };
48 | message RequestVoteResponse {
49 | int64 term = 1;
50 | bool granted = 2;
51 | string peer_name = 3;
52 | };
53 |
54 |
55 | message RequestPreVoteRequest {
56 | string server_id = 1;
57 | string peer_id = 2;
58 | int64 pre_term = 3;
59 | int64 committed_log_index = 4;
60 | int64 committed_log_term = 5;
61 | bool pre_vote = 6;
62 | string peer_name = 7;
63 | };
64 | message RequestPreVoteResponse {
65 | int64 term = 1;
66 | bool granted = 2;
67 | string peer_name = 3;
68 | };
69 |
70 | message AppendEntriesRequestHeader {
71 |
72 | string server_id = 1;
73 | string peer_id = 2;
74 | };
75 |
76 |
77 | message AppendEntriesRequest {
78 | string group_id = 1;
79 | string server_id = 2;
80 | string peer_id = 3;
81 | int64 term = 4;
82 | int64 prev_log_term = 5;
83 | int64 prev_log_index = 6;
84 | EntryMeta entries = 7;
85 | int64 committed_index = 8;
86 | bytes data = 9;
87 | string address = 10;
88 | int32 port = 11;
89 | int32 taskPort = 12;
90 | int64 readIndex=13;
91 | string dataString = 14;
92 | };
93 |
94 | message AppendEntriesResponse {
95 | int64 term = 1;
96 | bool success = 2;
97 | int64 last_log_index = 3;
98 | string address = 4;
99 | int32 port = 5;
100 | string peerId = 6;
101 | int64 readIndex = 7;
102 | string reason = 8;
103 | };
104 | message ReadIndexRequest {
105 | string group_id = 1;
106 | string server_id = 2;
107 | bytes entries = 3;
108 | string peer_id = 4;
109 | };
110 |
111 | message ReadIndexResponse {
112 | int64 index = 1;
113 | bool success = 2;
114 | };
115 |
116 | message NotifyFollowerStableRequest{
117 | int64 lastIndex = 1;
118 | int64 firstIndex = 2;
119 | string peerId = 3;
120 | bool success = 4;
121 |
122 | }
123 | message NotifyFollowerStableResponse{
124 | int64 lastIndex = 1;
125 | int64 firstIndex = 2;
126 | int64 term = 3;
127 | bool success = 4;
128 | }
129 |
130 |
131 | message NotifyFollowerToApplyRequest{
132 | int64 lastIndex = 1;
133 | int64 firstIndex = 2;
134 | string peerId = 3;
135 | bool success = 4;
136 |
137 | }
138 | message NotifyFollowerToApplyResponse{
139 | int64 lastIndex = 1;
140 | int64 firstIndex = 2;
141 | int64 term = 3;
142 | string followerId = 4;
143 | bool success = 5;
144 | }
--------------------------------------------------------------------------------
/src/main/resources/protobuf/enum.proto:
--------------------------------------------------------------------------------
1 | syntax="proto3";
2 | package protobuf;
3 |
4 | option java_package="rpc";
5 | option java_outer_classname = "EnumOutter";
6 |
7 | enum EntryType {
8 | ENTRY_TYPE_UNKNOWN = 0;
9 | ENTRY_TYPE_NO_OP = 1;
10 | ENTRY_TYPE_DATA = 2;
11 | ENTRY_TYPE_CONFIGURATION= 3;
12 | };
13 |
14 | enum ErrorType {
15 | ERROR_TYPE_NONE = 0;
16 | ERROR_TYPE_LOG = 1;
17 | ERROR_TYPE_STABLE = 2;
18 | ERROR_TYPE_SNAPSHOT = 3;
19 | ERROR_TYPE_STATE_MACHINE = 4;
20 | ERROR_TYPE_META = 5;
21 | };
22 |
--------------------------------------------------------------------------------
/src/main/resources/protobuf/logOuter.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package protobuf;
3 |
4 | option java_package = "rpc";
5 | option java_outer_classname = "LogOuter";
6 |
7 | message LogEntry{
8 | int64 term=1;
9 | int64 index=2;
10 | bytes data=3;
11 |
12 | }
--------------------------------------------------------------------------------
/src/main/resources/protobuf/raft.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 | package protobuf;
3 | import "enum.proto";
4 | option java_package = "rpc";
5 | option java_outer_classname = "RaftOutter";
6 |
7 | message EntryMeta{
8 | int64 term = 1;
9 | EntryType type = 2;
10 | string peers = 3;
11 | int64 data_len = 4;
12 | string old_peers = 5;
13 |
14 | int64 checksum = 6;
15 | string learners = 7;
16 | string old_learners = 8;
17 | }
--------------------------------------------------------------------------------
/src/main/resources/protobuf/rpc.bat:
--------------------------------------------------------------------------------
1 | protoc --java_out=./ ./RPC.proto
--------------------------------------------------------------------------------
/src/test/java/TestHeartbeatChecker.java:
--------------------------------------------------------------------------------
1 | //import com.alipay.sofa.rpc.common.annotation.JustForTest;
2 | //
3 | ///**
4 | // * Created by 周思成 on 2020/4/23 0:45
5 | // */
6 | //import core.HeartbeatThreadFactory;
7 | //import core.NodeImpl;
8 | //import entity.ElectionTimeOutClosure;
9 | //import entity.Heartbeat;
10 | //import entity.TimeOutChecker;
11 | //import org.junit.Test;
12 | //import org.slf4j.Logger;
13 | //import org.slf4j.LoggerFactory;
14 | //import utils.Utils;
15 | //
16 | //import java.util.concurrent.LinkedBlockingDeque;
17 | //import java.util.concurrent.ThreadPoolExecutor;
18 | //import java.util.concurrent.TimeUnit;
19 | //import java.util.concurrent.atomic.AtomicLong;
20 | //
21 | //public class TestHeartbeatChecker {
22 | // public static final Logger LOG = LoggerFactory.getLogger(NodeImpl.class);
23 | //
24 | // @Test
25 | // public void testHeartbeat() {
26 | //// Heartbeat heartbeat = new Heartbeat(1, 2
27 | //// , 0, TimeUnit.MILLISECONDS, new LinkedBlockingDeque<>()
28 | //// , new HeartbeatThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());
29 | ////
30 | //// heartbeat.setChecker(
31 | //// new TimeOutChecker( Utils.monotonicMs(), new ElectionTimeOutClosure(),""));
32 | //
33 | // LOG.debug("123");
34 | // LOG.info("123123");
35 | // LOG.error("123123123");
36 | // LOG.warn("12312312312312");
37 | // AtomicLong atomicLong = new AtomicLong(3/2+1);
38 | // LOG.info(atomicLong.get()+"");
39 | // }
40 | //}
41 |
--------------------------------------------------------------------------------
/src/test/java/TestTimeManager.java:
--------------------------------------------------------------------------------
1 | //import com.google.protobuf.ZeroByteStringHelper;
2 | //import org.junit.Test;
3 | //import rpc.RpcRequests;
4 | //import utils.TimerManager;
5 | //
6 | //import java.nio.ByteBuffer;
7 | //import java.util.concurrent.TimeUnit;
8 | //
9 | ///**
10 | // * Created by 周思成 on 2020/4/23 18:41
11 | // */
12 | //
13 | //public class TestTimeManager {
14 | //
15 | // TimerManager timerManager = new TimerManager();
16 | // @Test
17 | // public void Test() throws InterruptedException {
18 | //// Runnable runnable = () -> {
19 | //// System.out.println(123);
20 | //// try {
21 | //// Test();
22 | //// } catch (InterruptedException e) {
23 | //// e.printStackTrace();
24 | //// }
25 | //// //timerManager.schedule(runnable,1000, TimeUnit.MILLISECONDS);
26 | //// }
27 | //// ;
28 | // RpcRequests.AppendEntriesRequest.Builder builder = RpcRequests.AppendEntriesRequest.newBuilder();
29 | // ByteBuffer byteBuffer = ByteBuffer.wrap("123".getBytes());
30 | // ByteBuffer byteBuffer1 = null;
31 | // builder.setData(ZeroByteStringHelper.wrap(byteBuffer1));
32 | // RpcRequests.AppendEntriesRequest appendEntriesRequest = builder.build();
33 | // String t = new String(ZeroByteStringHelper.getByteArray(appendEntriesRequest.getData()));
34 | // System.out.println(t);
35 | //
36 | //// timerManager.init(100);
37 | //// timerManager.schedule(runnable,1000, TimeUnit.MILLISECONDS);
38 | //// Thread.currentThread().join();
39 | // }
40 | //}
41 |
--------------------------------------------------------------------------------
/论文github开源版.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CoderiGenius/RocksRaft/e1365c67cceb5549d31d12f9452584bb15e786e2/论文github开源版.pdf
--------------------------------------------------------------------------------