├── .gitignore
├── LICENSE
├── README.md
├── api
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── daydreamer
│ │ └── raft
│ │ └── api
│ │ ├── callback
│ │ └── CommitHook.java
│ │ ├── collection
│ │ ├── MemorySafeLinkedBlockingQueue.java
│ │ ├── RejectPolicy.java
│ │ └── impl
│ │ │ ├── AbortRejectPolicy.java
│ │ │ ├── DiscardOldestRejectPolicy.java
│ │ │ └── DiscardRejectPolicy.java
│ │ ├── entity
│ │ ├── Request.java
│ │ ├── Response.java
│ │ ├── base
│ │ │ ├── CommittedResponse.java
│ │ │ ├── ErrorResponse.java
│ │ │ ├── LogEntry.java
│ │ │ ├── MemberChangeEntry.java
│ │ │ └── Payload.java
│ │ ├── constant
│ │ │ ├── LogType.java
│ │ │ ├── MemberChange.java
│ │ │ └── ResponseCode.java
│ │ ├── request
│ │ │ ├── AppendEntriesRequest.java
│ │ │ ├── EntryCommittedRequest.java
│ │ │ ├── HeartbeatRequest.java
│ │ │ ├── PrevoteRequest.java
│ │ │ ├── VoteCommitRequest.java
│ │ │ └── VoteRequest.java
│ │ └── response
│ │ │ ├── AppendEntriesResponse.java
│ │ │ ├── ClientErrorResponse.java
│ │ │ ├── EntryCommittedResponse.java
│ │ │ ├── HeartbeatResponse.java
│ │ │ ├── PrevoteResponse.java
│ │ │ ├── ServerErrorResponse.java
│ │ │ ├── VoteCommitResponse.java
│ │ │ └── VoteResponse.java
│ │ ├── exception
│ │ └── InvalidResponseException.java
│ │ └── grpc
│ │ ├── Message.java
│ │ ├── MessageOrBuilder.java
│ │ ├── RequestRpc.java
│ │ └── RequesterGrpc.java
│ └── proto
│ └── grpc.proto
├── common
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── daydreamer
│ │ └── raft
│ │ └── common
│ │ ├── annotation
│ │ ├── SPI.java
│ │ ├── SPIIgnoredInject.java
│ │ ├── SPIImplement.java
│ │ ├── SPIMethodInit.java
│ │ └── SPISetter.java
│ │ ├── constant
│ │ └── LogConstant.java
│ │ ├── entity
│ │ ├── Holder.java
│ │ ├── RaftConfig.java
│ │ └── SimpleFuture.java
│ │ ├── filter
│ │ ├── LogFilter.java
│ │ └── impl
│ │ │ └── FilterChain.java
│ │ ├── loader
│ │ ├── GroupAware.java
│ │ ├── RaftServiceLoader.java
│ │ ├── ServiceFactory.java
│ │ └── impl
│ │ │ ├── AdaptiveServiceFactory.java
│ │ │ ├── ConfigServiceFactory.java
│ │ │ └── SPIServiceFactory.java
│ │ ├── service
│ │ ├── ActiveProperties.java
│ │ └── PropertiesReader.java
│ │ ├── threadpool
│ │ ├── ThreadPoolFactory.java
│ │ └── impl
│ │ │ ├── AdaptiveThreadPoolFactory.java
│ │ │ └── CacheThreadPoolFactory.java
│ │ └── utils
│ │ ├── MD5Utils.java
│ │ └── MsgUtils.java
│ └── resources
│ ├── META-INF
│ └── raft
│ │ ├── com.daydreamer.raft.common.filter.LogFilter
│ │ ├── com.daydreamer.raft.common.loader.ServiceFactory
│ │ └── com.daydreamer.raft.common.threadpool.ThreadPoolFactory
│ └── log4j.properties
├── example
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── com
│ │ └── daydreamer
│ │ └── raft
│ │ └── example
│ │ ├── LeaderElectionExample.java
│ │ ├── LogAppendExample.java
│ │ └── MemberChangeExample.java
│ └── resources
│ ├── example-server0.properties
│ ├── example-server1.properties
│ └── example-server2.properties
├── persistence
├── pom.xml
└── src
│ └── main
│ ├── java
│ └── org
│ │ └── daydreamer
│ │ └── persistence
│ │ ├── PersistenceService.java
│ │ └── impl
│ │ └── FileSystemPersistence.java
│ └── resources
│ └── META-INF
│ └── raft
│ └── org.daydreamer.persistence.PersistenceService
├── pom.xml
├── protocol
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── daydreamer
│ │ │ └── raft
│ │ │ └── protocol
│ │ │ ├── chain
│ │ │ ├── LogPostProcessor.java
│ │ │ ├── LogPostProcessorHolder.java
│ │ │ └── impl
│ │ │ │ ├── MemberChangeLogPostProcessor.java
│ │ │ │ └── PersistentLogPostProcessor.java
│ │ │ ├── constant
│ │ │ ├── LogErrorCode.java
│ │ │ ├── NodeRole.java
│ │ │ ├── NodeStatus.java
│ │ │ └── RaftProperty.java
│ │ │ ├── core
│ │ │ ├── AbstractFollowerNotifier.java
│ │ │ ├── AbstractRaftServer.java
│ │ │ ├── CommitHookManager.java
│ │ │ ├── LogSender.java
│ │ │ ├── Protocol.java
│ │ │ ├── RaftMemberManager.java
│ │ │ └── impl
│ │ │ │ ├── AsynCommitHookManager.java
│ │ │ │ ├── DefaultLogSender.java
│ │ │ │ ├── GrpcFollowerNotifier.java
│ │ │ │ ├── GrpcRaftServer.java
│ │ │ │ ├── GrpcRequestServerCore.java
│ │ │ │ ├── MemberManager.java
│ │ │ │ ├── RaftPropertiesReader.java
│ │ │ │ └── RaftProtocol.java
│ │ │ ├── entity
│ │ │ └── Member.java
│ │ │ ├── exception
│ │ │ └── LogException.java
│ │ │ ├── filter
│ │ │ └── InnerLogFilter.java
│ │ │ ├── handler
│ │ │ ├── RequestHandler.java
│ │ │ ├── RequestHandlerHolder.java
│ │ │ └── impl
│ │ │ │ ├── AppendEntriesRequestHandler.java
│ │ │ │ ├── DefaultRequestHandler.java
│ │ │ │ ├── HeartbeatRequestHandler.java
│ │ │ │ ├── LogCommittedRequestHandler.java
│ │ │ │ ├── PrevoteRequestHandler.java
│ │ │ │ ├── VoteCommitRequestHandler.java
│ │ │ │ └── VoteRequestHandler.java
│ │ │ └── storage
│ │ │ ├── ReplicatedStateMachine.java
│ │ │ └── impl
│ │ │ ├── DelegateReplicatedStateMachine.java
│ │ │ └── MemoryReplicatedStateMachine.java
│ └── resources
│ │ └── META-INF
│ │ └── raft
│ │ ├── com.daydreamer.raft.common.filter.LogFilter
│ │ ├── com.daydreamer.raft.protocol.chain.LogPostProcessor
│ │ ├── com.daydreamer.raft.protocol.core.AbstractFollowerNotifier
│ │ ├── com.daydreamer.raft.protocol.core.AbstractRaftServer
│ │ ├── com.daydreamer.raft.protocol.core.LogSender
│ │ ├── com.daydreamer.raft.protocol.core.RaftMemberManager
│ │ ├── com.daydreamer.raft.protocol.handler.RequestHandler
│ │ └── com.daydreamer.raft.protocol.storage.ReplicatedStateMachine
│ └── test
│ └── java
│ └── com
│ └── daydreamer
│ └── raft
│ └── protocol
│ └── storage
│ └── impl
│ └── MemoryReplicatedStateMachineTest.java
└── transport
├── pom.xml
└── src
└── main
├── java
└── com
│ └── daydreamer
│ └── raft
│ └── transport
│ ├── connection
│ ├── Closeable.java
│ ├── Connection.java
│ ├── ResponseCallBack.java
│ └── impl
│ │ ├── grpc
│ │ └── GrpcConnection.java
│ │ └── http
│ │ └── HttpConnection.java
│ ├── constant
│ └── ResponseRepository.java
│ └── factory
│ ├── ConnectionFactory.java
│ └── impl
│ └── GrpcConnectionFactory.java
└── resources
└── META-INF
└── raft
└── com.daydreamer.raft.transport.factory.ConnectionFactory
/.gitignore:
--------------------------------------------------------------------------------
1 | # Except this file !.gitignore
2 | .classpath
3 | .project
4 | .settings
5 | target
6 | .idea
7 | .vscode
8 | .DS_Store
9 | .factorypath
10 | /logs
11 | *.iml
12 | *.log
13 | node_modules
14 | test/derby.log
15 | derby.log
16 | work
17 | test/logs
18 | derby.log
19 | yarn.lock
20 | .flattened-pom.xml
21 |
--------------------------------------------------------------------------------
/api/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | raft
7 | org.daydreamer
8 | 1.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | api
13 | ${ddr-raft.version}
14 |
15 |
16 | 1.8
17 | 1.8
18 | 2.6
19 | 2.8.6
20 | 1.30.2
21 | 3.16.3
22 | 1.17.0
23 | 1.3.2
24 |
25 |
26 |
27 |
28 | io.grpc
29 | grpc-netty-shaded
30 | ${grpc.version}
31 |
32 |
33 | io.grpc
34 | grpc-protobuf
35 | ${grpc.version}
36 |
37 |
38 | io.grpc
39 | grpc-stub
40 | ${grpc.version}
41 |
42 |
43 | com.google.api.grpc
44 | proto-google-common-protos
45 | ${proto-common.version}
46 |
47 |
48 | com.google.protobuf
49 | protobuf-java
50 | ${proto.version}
51 |
52 |
53 | io.grpc
54 | protoc-gen-grpc-java
55 | ${grpc.version}
56 | pom
57 |
58 |
59 | javax.annotation
60 | javax.annotation-api
61 | ${javax.version}
62 |
63 |
64 |
65 |
66 |
67 |
68 | kr.motd.maven
69 | os-maven-plugin
70 | 1.6.2
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/callback/CommitHook.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.callback;
2 |
3 | import com.daydreamer.raft.api.entity.base.LogEntry;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * it will be invoked after log committed
9 | */
10 | public interface CommitHook {
11 |
12 | /**
13 | * it will be invoked after log committed
14 | *
15 | * @param logEntry committed log
16 | */
17 | void handleCommittedLog(LogEntry logEntry);
18 | }
19 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/collection/MemorySafeLinkedBlockingQueue.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.collection;
2 |
3 | import com.daydreamer.raft.api.collection.impl.AbortRejectPolicy;
4 |
5 | import java.util.Collection;
6 | import java.util.concurrent.LinkedBlockingQueue;
7 | import java.util.concurrent.TimeUnit;
8 |
9 | /**
10 | * @author Daydreamer
11 | */
12 | public class MemorySafeLinkedBlockingQueue extends LinkedBlockingQueue {
13 |
14 | /**
15 | * default reject policy
16 | */
17 | private static final RejectPolicy DEFAULT_REJECT_POLICY = new AbortRejectPolicy<>();
18 |
19 | /**
20 | * default min memory at least
21 | */
22 | private static final long DEFAULT_MIN_MEMORY_AT_LEAST = 200 * 1024;
23 |
24 | /**
25 | * leave 200m at least
26 | */
27 | private long minMemoryAtLeast = DEFAULT_MIN_MEMORY_AT_LEAST;
28 |
29 | /**
30 | * reject policy
31 | */
32 | private RejectPolicy rejectPolicy = DEFAULT_REJECT_POLICY;
33 |
34 | public MemorySafeLinkedBlockingQueue(long minMemoryAtLeast) {
35 | this.minMemoryAtLeast = minMemoryAtLeast;
36 | }
37 |
38 | public MemorySafeLinkedBlockingQueue() {
39 | }
40 |
41 | public MemorySafeLinkedBlockingQueue(RejectPolicy rejectPolicy) {
42 | this.rejectPolicy = rejectPolicy;
43 | }
44 |
45 | public MemorySafeLinkedBlockingQueue(long minMemoryAtLeast, RejectPolicy rejectPolicy) {
46 | this.minMemoryAtLeast = minMemoryAtLeast;
47 | this.rejectPolicy = rejectPolicy;
48 | }
49 |
50 | public MemorySafeLinkedBlockingQueue(int capacity, long minMemoryAtLeast, RejectPolicy rejectPolicy) {
51 | super(capacity);
52 | this.minMemoryAtLeast = minMemoryAtLeast;
53 | this.rejectPolicy = rejectPolicy;
54 | }
55 |
56 | public MemorySafeLinkedBlockingQueue(Collection extends E> c, long minMemoryAtLeast, RejectPolicy rejectPolicy) {
57 | super(c);
58 | this.minMemoryAtLeast = minMemoryAtLeast;
59 | this.rejectPolicy = rejectPolicy;
60 | }
61 |
62 | /**
63 | * is there free memory
64 | *
65 | * @return whether allow to operate
66 | */
67 | private boolean hasFreeMemory() {
68 | return Runtime.getRuntime().freeMemory() > minMemoryAtLeast;
69 | }
70 |
71 | @Override
72 | public void put(final E e) throws InterruptedException {
73 | if (hasFreeMemory()) {
74 | super.put(e);
75 | } else {
76 | rejectPolicy.reject(e, this);
77 | }
78 | }
79 |
80 | public long getMinMemoryAtLeast() {
81 | return minMemoryAtLeast;
82 | }
83 |
84 | public void setMinMemoryAtLeast(long minMemoryAtLeast) {
85 | this.minMemoryAtLeast = minMemoryAtLeast;
86 | }
87 |
88 | @Override
89 | public boolean offer(final E e, final long timeout, final TimeUnit unit) throws InterruptedException {
90 | if (!hasFreeMemory()) {
91 | return false;
92 | }
93 | return super.offer(e, timeout, unit);
94 | }
95 |
96 | @Override
97 | public boolean offer(final E e) {
98 | if (!hasFreeMemory()) {
99 | rejectPolicy.reject(e, this);
100 | return false;
101 | }
102 | return super.offer(e);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/collection/RejectPolicy.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.collection;
2 |
3 | import java.util.Queue;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public interface RejectPolicy {
9 |
10 | void reject(E ele, Queue queue);
11 | }
12 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/collection/impl/AbortRejectPolicy.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.collection.impl;
2 |
3 | import com.daydreamer.raft.api.collection.RejectPolicy;
4 |
5 | import java.util.Queue;
6 | import java.util.concurrent.RejectedExecutionException;
7 |
8 | /**
9 | * @author Daydreamer
10 | */
11 | public class AbortRejectPolicy implements RejectPolicy {
12 |
13 | @Override
14 | public void reject(E ele, Queue queue) {
15 | throw new RejectedExecutionException("No more memory can be used!");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/collection/impl/DiscardOldestRejectPolicy.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.collection.impl;
2 |
3 | import com.daydreamer.raft.api.collection.RejectPolicy;
4 |
5 | import java.util.Queue;
6 |
7 | /**
8 | * @author Daydreamer
9 | */
10 | public class DiscardOldestRejectPolicy implements RejectPolicy {
11 |
12 | @Override
13 | public void reject(E ele, Queue queue) {
14 | queue.poll();
15 | queue.add(ele);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/collection/impl/DiscardRejectPolicy.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.collection.impl;
2 |
3 | import com.daydreamer.raft.api.collection.RejectPolicy;
4 |
5 | import java.util.Queue;
6 |
7 | /**
8 | * @author Daydreamer
9 | */
10 | public class DiscardRejectPolicy implements RejectPolicy {
11 | @Override
12 | public void reject(E ele, Queue queue) {
13 | // nothing to do
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/Request.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity;
2 |
3 | import java.io.Serializable;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 | import java.util.concurrent.atomic.AtomicLong;
7 |
8 | /**
9 | * @author Daydreamer
10 | *
11 | * payload of request
12 | */
13 | public abstract class Request implements Serializable {
14 |
15 | private static final long serialVersionUID = 11988178431L;
16 |
17 | /**
18 | * next request id
19 | */
20 | private static final AtomicLong NEXT_REQUEST_ID = new AtomicLong(0);
21 |
22 | /**
23 | * request id
24 | */
25 | private long requestId = NEXT_REQUEST_ID.getAndIncrement();
26 |
27 | /**
28 | * data header
29 | */
30 | private Map headers = new HashMap();
31 |
32 | public Map getHeaders() {
33 | return headers;
34 | }
35 |
36 | public long getRequestId() {
37 | return requestId;
38 | }
39 |
40 | public void setHeaders(Map headers) {
41 | this.headers = headers;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/Response.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity;
2 |
3 |
4 | import com.daydreamer.raft.api.entity.constant.ResponseCode;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * @author Daydreamer
10 | *
11 | * payload of response
12 | */
13 | public abstract class Response implements Serializable {
14 |
15 | private int resultCode = ResponseCode.SUCCESS_CODE;
16 |
17 | private String message;
18 |
19 | private String requestId;
20 |
21 | public int getResultCode() {
22 | return resultCode;
23 | }
24 |
25 | public void setResultCode(int resultCode) {
26 | this.resultCode = resultCode;
27 | }
28 |
29 | public String getMessage() {
30 | return message;
31 | }
32 |
33 | public void setMessage(String message) {
34 | this.message = message;
35 | }
36 |
37 | public String getRequestId() {
38 | return requestId;
39 | }
40 |
41 | public void setRequestId(String requestId) {
42 | this.requestId = requestId;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/base/CommittedResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.base;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public abstract class CommittedResponse extends Response {
9 |
10 | private boolean accepted;
11 |
12 | public CommittedResponse(boolean accepted) {
13 | this.accepted = accepted;
14 | }
15 |
16 | public boolean isAccepted() {
17 | return accepted;
18 | }
19 |
20 | public void setAccepted(boolean accepted) {
21 | this.accepted = accepted;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/base/ErrorResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.base;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public abstract class ErrorResponse extends Response {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/base/LogEntry.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.base;
2 |
3 | import java.io.Serializable;
4 | import java.util.Objects;
5 |
6 | /**
7 | * @author Daydreamer
8 | */
9 | public class LogEntry implements Serializable {
10 |
11 | /**
12 | * term
13 | */
14 | private int term;
15 |
16 | /**
17 | * log id
18 | */
19 | private long logId;
20 |
21 | /**
22 | * data
23 | */
24 | private Payload payload;
25 |
26 | public LogEntry(int term, long logId, Payload payload) {
27 | this.term = term;
28 | this.logId = logId;
29 | this.payload = payload;
30 | }
31 |
32 | public LogEntry(int term, long logId) {
33 | this.term = term;
34 | this.logId = logId;
35 | }
36 |
37 | public int getTerm() {
38 | return term;
39 | }
40 |
41 | public void setTerm(int term) {
42 | this.term = term;
43 | }
44 |
45 | public long getLogId() {
46 | return logId;
47 | }
48 |
49 | public void setLogId(long logId) {
50 | this.logId = logId;
51 | }
52 |
53 | public Payload getPayload() {
54 | return payload;
55 | }
56 |
57 | public void setPayload(Payload payload) {
58 | this.payload = payload;
59 | }
60 |
61 | @Override
62 | public boolean equals(Object o) {
63 | if (this == o) {
64 | return true;
65 | }
66 | if (!(o instanceof LogEntry)) {
67 | return false;
68 | }
69 | LogEntry logEntry = (LogEntry) o;
70 | return term == logEntry.term && logId == logEntry.logId;
71 | }
72 |
73 | @Override
74 | public int hashCode() {
75 | return Objects.hash(term, logId);
76 | }
77 |
78 | @Override
79 | public String toString() {
80 | return "LogEntry{" + "term=" + term + ", logId=" + logId + ", log type=" + payload.getLogType() + '}';
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/base/MemberChangeEntry.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.base;
2 |
3 | import com.daydreamer.raft.api.entity.constant.MemberChange;
4 |
5 | import java.io.Serializable;
6 |
7 | /**
8 | * @author Daydreamer
9 | */
10 | public class MemberChangeEntry implements Serializable {
11 |
12 | private String address;
13 |
14 | private MemberChange memberChange;
15 |
16 | public MemberChangeEntry(String address, MemberChange memberChange) {
17 | this.address = address;
18 | this.memberChange = memberChange;
19 | }
20 |
21 | public String getAddress() {
22 | return address;
23 | }
24 |
25 | public void setAddress(String address) {
26 | this.address = address;
27 | }
28 |
29 | public MemberChange getMemberChange() {
30 | return memberChange;
31 | }
32 |
33 | public void setMemberChange(MemberChange memberChange) {
34 | this.memberChange = memberChange;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/base/Payload.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.base;
2 |
3 | import com.daydreamer.raft.api.entity.constant.LogType;
4 |
5 | import java.io.Serializable;
6 | import java.util.Map;
7 |
8 | /**
9 | * @author Daydreamer
10 | */
11 | public class Payload implements Serializable {
12 |
13 | private Map metadata;
14 |
15 | private LogType logType;
16 |
17 | public Payload() {
18 | }
19 |
20 | public Payload(Map object, LogType logType) {
21 | this.metadata = object;
22 | this.logType = logType;
23 | }
24 |
25 | public Map getMetadata() {
26 | return metadata;
27 | }
28 |
29 | public void setMetadata(Map metadata) {
30 | this.metadata = metadata;
31 | }
32 |
33 | public LogType getLogType() {
34 | return logType;
35 | }
36 |
37 | public void setLogType(LogType logType) {
38 | this.logType = logType;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/constant/LogType.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.constant;
2 |
3 | /**
4 | * @author Daydreamer
5 | *
6 | * type of raft log
7 | */
8 | public enum LogType {
9 |
10 | /**
11 | * read log
12 | */
13 | READ,
14 |
15 | /**
16 | * write log
17 | */
18 | WRITE,
19 |
20 | /**
21 | * no-op
22 | */
23 | NO_OP,
24 |
25 | /**
26 | * member change
27 | */
28 | MEMBER_CHANGE
29 | }
30 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/constant/MemberChange.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.constant;
2 |
3 | /**
4 | * @author Daydreamer
5 | */
6 | public enum MemberChange {
7 |
8 | /**
9 | * add
10 | */
11 | ADD,
12 |
13 | /**
14 | * remove
15 | */
16 | REMOVE
17 | }
18 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/constant/ResponseCode.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.constant;
2 |
3 | /**
4 | * @author Daydreamer
5 | *
6 | * reponse code of response
7 | */
8 | public class ResponseCode {
9 |
10 | private ResponseCode() {}
11 |
12 | /**
13 | * success
14 | */
15 | public static final int SUCCESS_CODE = 200;
16 |
17 | /**
18 | * error from client
19 | */
20 | public static final int ERROR_CLIENT = 400;
21 |
22 | /**
23 | * error from server
24 | */
25 | public static final int ERROR_SERVER = 500;
26 | }
27 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/AppendEntriesRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 | import com.daydreamer.raft.api.entity.base.LogEntry;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author Daydreamer
10 | */
11 | public class AppendEntriesRequest extends Request {
12 |
13 | /**
14 | * last committed or uncommitted log id
15 | */
16 | private long lastLogId;
17 |
18 | /**
19 | * last committed or uncommitted log term
20 | */
21 | private int lastTerm;
22 |
23 | /**
24 | * log from last committed log in follower to current committed log in leader
25 | */
26 | private List logEntries;
27 |
28 | /**
29 | * current term
30 | */
31 | private int currentTerm;
32 |
33 | /**
34 | * current committed or uncommitted log id
35 | */
36 | private long currentLogId;
37 |
38 | /**
39 | * whether it is payload
40 | */
41 | private boolean payload;
42 |
43 | public List getLogEntries() {
44 | return logEntries;
45 | }
46 |
47 | public void setLogEntries(List logEntries) {
48 | this.logEntries = logEntries;
49 | }
50 |
51 | public int getCurrentTerm() {
52 | return currentTerm;
53 | }
54 |
55 | public void setCurrentTerm(int currentTerm) {
56 | this.currentTerm = currentTerm;
57 | }
58 |
59 | public long getCurrentLogId() {
60 | return currentLogId;
61 | }
62 |
63 | public void setCurrentLogId(long currentLogId) {
64 | this.currentLogId = currentLogId;
65 | }
66 |
67 | public boolean isPayload() {
68 | return payload;
69 | }
70 |
71 | public void setPayload(boolean payload) {
72 | this.payload = payload;
73 | }
74 |
75 | public List getLogEntry() {
76 | return logEntries;
77 | }
78 |
79 | public void setLogEntry(List logEntries) {
80 | this.logEntries = logEntries;
81 | }
82 |
83 | public long getLastLogId() {
84 | return lastLogId;
85 | }
86 |
87 | public void setLastLogId(long lastLogId) {
88 | this.lastLogId = lastLogId;
89 | }
90 |
91 | public int getLastTerm() {
92 | return lastTerm;
93 | }
94 |
95 | public void setLastTerm(int lastTerm) {
96 | this.lastTerm = lastTerm;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/EntryCommittedRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class EntryCommittedRequest extends Request {
9 |
10 | private long logId;
11 |
12 | private int term;
13 |
14 | public EntryCommittedRequest(long logId, int term) {
15 | this.logId = logId;
16 | this.term = term;
17 | }
18 |
19 | public long getLogId() {
20 | return logId;
21 | }
22 |
23 | public void setLogId(long logId) {
24 | this.logId = logId;
25 | }
26 |
27 | public int getTerm() {
28 | return term;
29 | }
30 |
31 | public void setTerm(int term) {
32 | this.term = term;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/HeartbeatRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * heart beat
9 | */
10 | public class HeartbeatRequest extends Request {
11 |
12 | private int term;
13 |
14 | private long logId;
15 |
16 | public HeartbeatRequest(int term, long logId) {
17 | this.term = term;
18 | this.logId = logId;
19 | }
20 |
21 | public long getLogId() {
22 | return logId;
23 | }
24 |
25 | public void setLogId(long logId) {
26 | this.logId = logId;
27 | }
28 |
29 | public int getTerm() {
30 | return term;
31 | }
32 |
33 | public void setTerm(int term) {
34 | this.term = term;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/PrevoteRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class PrevoteRequest extends Request {
9 |
10 | /**
11 | * term from client
12 | */
13 | private int term;
14 |
15 | /**
16 | * log index
17 | */
18 | private long logIndex;
19 |
20 | public PrevoteRequest() {
21 | }
22 |
23 | public PrevoteRequest(int term, long logIndex) {
24 | this.term = term;
25 | this.logIndex = logIndex;
26 | }
27 |
28 | public long getLogIndex() {
29 | return logIndex;
30 | }
31 |
32 | public void setLogIndex(long logIndex) {
33 | this.logIndex = logIndex;
34 | }
35 |
36 | public int getTerm() {
37 | return term;
38 | }
39 |
40 | public void setTerm(int term) {
41 | this.term = term;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/VoteCommitRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * if success to get half of all, then commit and tell follower
9 | */
10 | public class VoteCommitRequest extends Request {
11 |
12 | private int term;
13 |
14 | private long logId;
15 |
16 | public VoteCommitRequest() {
17 | }
18 |
19 | public VoteCommitRequest(int term, long logId) {
20 | this.term = term;
21 | this.logId = logId;
22 | }
23 |
24 | public int getTerm() {
25 | return term;
26 | }
27 |
28 | public void setTerm(int term) {
29 | this.term = term;
30 | }
31 |
32 | public long getLogId() {
33 | return logId;
34 | }
35 |
36 | public void setLogId(long logId) {
37 | this.logId = logId;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/request/VoteRequest.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.request;
2 |
3 | import com.daydreamer.raft.api.entity.Request;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * request to vote
9 | */
10 | public class VoteRequest extends Request {
11 |
12 | private int term;
13 |
14 | private long logIndex;
15 |
16 | public VoteRequest() {
17 | }
18 |
19 | public VoteRequest(int term, long logIndex) {
20 | this.term = term;
21 | this.logIndex = logIndex;
22 | }
23 |
24 | public int getTerm() {
25 | return term;
26 | }
27 |
28 | public void setTerm(int term) {
29 | this.term = term;
30 | }
31 |
32 | public long getLogIndex() {
33 | return logIndex;
34 | }
35 |
36 | public void setLogIndex(long logIndex) {
37 | this.logIndex = logIndex;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/AppendEntriesResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class AppendEntriesResponse extends Response {
9 |
10 | /**
11 | * whether accepted
12 | */
13 | private boolean accepted;
14 |
15 | public AppendEntriesResponse(boolean accepted) {
16 | this.accepted = accepted;
17 | }
18 |
19 | public boolean isAccepted() {
20 | return accepted;
21 | }
22 |
23 | public void setAccepted(boolean accepted) {
24 | this.accepted = accepted;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/ClientErrorResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.base.ErrorResponse;
4 |
5 |
6 | /**
7 | * @author Daydreamer
8 | *
9 | * Client error
10 | */
11 | public class ClientErrorResponse extends ErrorResponse {
12 |
13 | public ClientErrorResponse(String msg, int code) {
14 | super.setMessage(msg);
15 | super.setResultCode(code);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/EntryCommittedResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.base.CommittedResponse;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class EntryCommittedResponse extends CommittedResponse {
9 |
10 | public EntryCommittedResponse(boolean accepted) {
11 | super(accepted);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/HeartbeatResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class HeartbeatResponse extends Response {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/PrevoteResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class PrevoteResponse extends Response {
9 |
10 | private boolean agree;
11 |
12 | public PrevoteResponse() {
13 | }
14 |
15 | public PrevoteResponse(boolean agree) {
16 | this.agree = agree;
17 | }
18 |
19 | public boolean isAgree() {
20 | return agree;
21 | }
22 |
23 | public void setAgree(boolean agree) {
24 | this.agree = agree;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/ServerErrorResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.base.ErrorResponse;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * Server error, often unknown error
9 | */
10 | public class ServerErrorResponse extends ErrorResponse {
11 | public ServerErrorResponse(String msg, int code) {
12 | super.setMessage(msg);
13 | super.setResultCode(code);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/VoteCommitResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.base.CommittedResponse;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class VoteCommitResponse extends CommittedResponse {
9 |
10 | public VoteCommitResponse(boolean accepted) {
11 | super(accepted);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/entity/response/VoteResponse.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.entity.response;
2 |
3 | import com.daydreamer.raft.api.entity.Response;
4 |
5 | /**
6 | * @author Daydreamer
7 | *
8 | * response to vote
9 | */
10 | public class VoteResponse extends Response {
11 |
12 | /**
13 | * whether to vote for client
14 | */
15 | private boolean isVoted;
16 |
17 | public VoteResponse(boolean isVoted) {
18 | this.isVoted = isVoted;
19 | }
20 |
21 | public boolean isVoted() {
22 | return isVoted;
23 | }
24 |
25 | public void setVoted(boolean voted) {
26 | isVoted = voted;
27 | }
28 |
29 | @Override
30 | public String toString() {
31 | return "VoteResponse{" + "isVoted=" + isVoted + '}';
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/exception/InvalidResponseException.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.api.exception;
2 |
3 | import com.daydreamer.raft.api.entity.base.ErrorResponse;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | public class InvalidResponseException extends Exception {
9 |
10 | private ErrorResponse errorResponse;
11 |
12 | public InvalidResponseException(ErrorResponse errorResponse) {
13 | this.errorResponse = errorResponse;
14 | }
15 |
16 | public InvalidResponseException(String message, Throwable cause, ErrorResponse errorResponse) {
17 | super(message, cause);
18 | this.errorResponse = errorResponse;
19 | }
20 |
21 | public InvalidResponseException(String message, ErrorResponse errorResponse) {
22 | super(message);
23 | this.errorResponse = errorResponse;
24 | }
25 |
26 | public ErrorResponse getErrorResponse() {
27 | return errorResponse;
28 | }
29 |
30 | public void setErrorResponse(ErrorResponse errorResponse) {
31 | this.errorResponse = errorResponse;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/grpc/MessageOrBuilder.java:
--------------------------------------------------------------------------------
1 | // Generated by the protocol buffer compiler. DO NOT EDIT!
2 | // source: grpc.proto
3 |
4 | package com.daydreamer.raft.api.grpc;
5 |
6 | public interface MessageOrBuilder extends
7 | // @@protoc_insertion_point(interface_extends:Message)
8 | com.google.protobuf.MessageOrBuilder {
9 |
10 | /**
11 | *
12 | * payload
13 | *
14 | *
15 | * string data = 1;
16 | * @return The data.
17 | */
18 | String getData();
19 | /**
20 | *
21 | * payload
22 | *
23 | *
24 | * string data = 1;
25 | * @return The bytes for data.
26 | */
27 | com.google.protobuf.ByteString
28 | getDataBytes();
29 |
30 | /**
31 | *
32 | * conn id
33 | *
34 | *
35 | * string id = 2;
36 | * @return The id.
37 | */
38 | String getId();
39 | /**
40 | *
41 | * conn id
42 | *
43 | *
44 | * string id = 2;
45 | * @return The bytes for id.
46 | */
47 | com.google.protobuf.ByteString
48 | getIdBytes();
49 |
50 | /**
51 | *
52 | * request or response type
53 | *
54 | *
55 | * string type = 3;
56 | * @return The type.
57 | */
58 | String getType();
59 | /**
60 | *
61 | * request or response type
62 | *
63 | *
64 | * string type = 3;
65 | * @return The bytes for type.
66 | */
67 | com.google.protobuf.ByteString
68 | getTypeBytes();
69 | }
70 |
--------------------------------------------------------------------------------
/api/src/main/java/com/daydreamer/raft/api/grpc/RequestRpc.java:
--------------------------------------------------------------------------------
1 | // Generated by the protocol buffer compiler. DO NOT EDIT!
2 | // source: grpc.proto
3 |
4 | package com.daydreamer.raft.api.grpc;
5 |
6 | public final class RequestRpc {
7 | private RequestRpc() {}
8 | public static void registerAllExtensions(
9 | com.google.protobuf.ExtensionRegistryLite registry) {
10 | }
11 |
12 | public static void registerAllExtensions(
13 | com.google.protobuf.ExtensionRegistry registry) {
14 | registerAllExtensions(
15 | (com.google.protobuf.ExtensionRegistryLite) registry);
16 | }
17 | static final com.google.protobuf.Descriptors.Descriptor
18 | internal_static_Message_descriptor;
19 | static final
20 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
21 | internal_static_Message_fieldAccessorTable;
22 |
23 | public static com.google.protobuf.Descriptors.FileDescriptor
24 | getDescriptor() {
25 | return descriptor;
26 | }
27 | private static com.google.protobuf.Descriptors.FileDescriptor
28 | descriptor;
29 | static {
30 | String[] descriptorData = {
31 | "\n\ngrpc.proto\032\031google/protobuf/any.proto\"" +
32 | "1\n\007Message\022\014\n\004data\030\001 \001(\t\022\n\n\002id\030\002 \001(\t\022\014\n\004" +
33 | "type\030\003 \001(\t2,\n\tRequester\022\037\n\007request\022\010.Mes" +
34 | "sage\032\010.Message\"\000B2\n\"com.daydreamer.raft." +
35 | "transport.grpcB\nRequestRpcP\001b\006proto3"
36 | };
37 | descriptor = com.google.protobuf.Descriptors.FileDescriptor
38 | .internalBuildGeneratedFileFrom(descriptorData,
39 | new com.google.protobuf.Descriptors.FileDescriptor[] {
40 | com.google.protobuf.AnyProto.getDescriptor(),
41 | });
42 | internal_static_Message_descriptor =
43 | getDescriptor().getMessageTypes().get(0);
44 | internal_static_Message_fieldAccessorTable = new
45 | com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
46 | internal_static_Message_descriptor,
47 | new String[] { "Data", "Id", "Type", });
48 | com.google.protobuf.AnyProto.getDescriptor();
49 | }
50 |
51 | // @@protoc_insertion_point(outer_class_scope)
52 | }
53 |
--------------------------------------------------------------------------------
/api/src/main/proto/grpc.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | import "google/protobuf/any.proto";
4 |
5 | option java_multiple_files = true;
6 | option java_package = "com.daydreamer.raft.transport.grpc";
7 | option java_outer_classname = "RequestRpc";
8 |
9 | /**
10 | service
11 | */
12 | service Requester {
13 | rpc request (Message) returns (Message){
14 |
15 | }
16 | }
17 |
18 | /**
19 | base message
20 | */
21 | message Message {
22 | string data = 1; // payload
23 | string id = 2; // conn id
24 | string type = 3; // request or response type
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | raft
7 | org.daydreamer
8 | 1.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | common
13 | ${ddr-raft.version}
14 |
15 |
16 | 2.6
17 | 2.8.6
18 | 5.5.2
19 | 1.7.21
20 |
21 |
22 |
23 |
24 | commons-lang
25 | commons-lang
26 | ${commons-lang.version}
27 |
28 |
29 | com.google.code.gson
30 | gson
31 | ${gson.version}
32 |
33 |
34 | org.daydreamer
35 | api
36 | ${ddr-raft.version}
37 |
38 |
39 |
40 |
41 | org.junit.jupiter
42 | junit-jupiter-engine
43 | ${junit.version}
44 |
45 |
46 |
47 |
48 | org.slf4j
49 | slf4j-log4j12
50 | ${slf4j.version}
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/annotation/SPI.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | @Documented
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Target({ElementType.TYPE})
11 | public @interface SPI {
12 |
13 | /**
14 | * default implement key
15 | *
16 | * @return default implement key
17 | */
18 | String value();
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/annotation/SPIIgnoredInject.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.annotation;
2 |
3 | /**
4 | * @author Daydreamer
5 | *
6 | * Ignore setter for setter method
7 | */
8 | public @interface SPIIgnoredInject {
9 | }
10 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/annotation/SPIImplement.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | @Documented
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Target({ElementType.TYPE})
11 | public @interface SPIImplement {
12 |
13 | /**
14 | * key of current implement
15 | *
16 | * @return key
17 | */
18 | String value();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/annotation/SPIMethodInit.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.annotation;
2 |
3 |
4 | import java.lang.annotation.*;
5 |
6 | /**
7 | * @author Daydreamer
8 | *
9 | * Invoke after properties set
10 | */
11 | @Documented
12 | @Retention(RetentionPolicy.RUNTIME)
13 | @Target({ElementType.METHOD})
14 | public @interface SPIMethodInit {
15 | }
16 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/annotation/SPISetter.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | @Documented
9 | @Retention(RetentionPolicy.RUNTIME)
10 | @Target({ElementType.METHOD})
11 | public @interface SPISetter {
12 |
13 | /**
14 | * dependency key
15 | *
16 | * @return key
17 | */
18 | String value();
19 | }
20 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/constant/LogConstant.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.constant;
2 |
3 | /**
4 | * @author Daydreamer
5 | */
6 | public class LogConstant {
7 |
8 | private LogConstant() {}
9 |
10 | /**
11 | * inner log which will not trigger hook
12 | */
13 | public static final String INNER_LOG_TAG = "ddr.log.inner.filter.tag";
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/entity/Holder.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.entity;
2 |
3 | /**
4 | * @author Daydreamer
5 | */
6 | public class Holder {
7 |
8 | private Object object;
9 |
10 | private Class> clazz;
11 |
12 | public Holder() {
13 | }
14 |
15 | public Holder(Class> clazz) {
16 | this.clazz = clazz;
17 | }
18 |
19 | public Holder(Object object, Class> clazz) {
20 | this.object = object;
21 | this.clazz = clazz;
22 | }
23 |
24 | public Object getObject() {
25 | return object;
26 | }
27 |
28 | public void setObject(Object object) {
29 | this.object = object;
30 | }
31 |
32 | public Class> getClazz() {
33 | return clazz;
34 | }
35 |
36 | public void setClazz(Class> clazz) {
37 | this.clazz = clazz;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/entity/RaftConfig.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.entity;
2 |
3 | import com.daydreamer.raft.common.annotation.SPI;
4 | import com.daydreamer.raft.common.service.ActiveProperties;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * @author Daydreamer
10 | *
11 | * config about raft
12 | *
13 | * voteBaseTime + ramdom() < heartInterval < abnormalActiveInterval
14 | */
15 | @SPI("raftConfig")
16 | public class RaftConfig implements ActiveProperties {
17 |
18 | /**
19 | * member ip exclude current node
20 | */
21 | private List memberAddresses;
22 |
23 | /**
24 | * server ip
25 | */
26 | private String serverAddr;
27 |
28 | /**
29 | * current node will tell follower to keep if current node is leader and timeout
30 | */
31 | private int heartInterval = 1000;
32 |
33 | /**
34 | * current node will ask votes if timeout
35 | */
36 | private int abnormalActiveInterval = 10000;
37 |
38 | /**
39 | * base interval between two elections
40 | */
41 | private int voteBaseTime = 3000;
42 |
43 | /**
44 | * base wait time in candidate
45 | */
46 | private int candidateStatusTimeout = 5000;
47 |
48 | /**
49 | * write fail, then retry writeRetryTimes
50 | */
51 | private int writeRetryTimes = 2;
52 |
53 | /**
54 | * reject any write request if current node is follower
55 | */
56 | private boolean followerRejectWrite = false;
57 |
58 | /**
59 | * the count of core thread for default thread pool
60 | * {@link com.daydreamer.raft.common.threadpool.impl.CacheThreadPoolFactory}
61 | */
62 | private int defaultThreadPoolCoreThread = 2;
63 |
64 | /**
65 | * the count of max thread for default thread pool
66 | * {@link com.daydreamer.raft.common.threadpool.impl.CacheThreadPoolFactory}
67 | */
68 | private int defaultThreadPoolMaxThread = 2;
69 |
70 | /**
71 | * log data dir
72 | */
73 | private String dataDir = System.getProperty("user.home");
74 |
75 | /**
76 | * persistent log
77 | */
78 | private boolean persistent = false;
79 |
80 | public boolean isFollowerRejectWrite() {
81 | return followerRejectWrite;
82 | }
83 |
84 | public void setFollowerRejectWrite(boolean followerRejectWrite) {
85 | this.followerRejectWrite = followerRejectWrite;
86 | }
87 |
88 | public int getDefaultThreadPoolCoreThread() {
89 | return defaultThreadPoolCoreThread;
90 | }
91 |
92 | public void setDefaultThreadPoolCoreThread(int defaultThreadPoolCoreThread) {
93 | this.defaultThreadPoolCoreThread = defaultThreadPoolCoreThread;
94 | }
95 |
96 | public String getDataDir() {
97 | return dataDir;
98 | }
99 |
100 | public boolean isPersistent() {
101 | return persistent;
102 | }
103 |
104 | public void setPersistent(boolean persistent) {
105 | this.persistent = persistent;
106 | }
107 |
108 | public void setDataDir(String dataDir) {
109 | this.dataDir = dataDir;
110 | }
111 |
112 | public int getDefaultThreadPoolMaxThread() {
113 | return defaultThreadPoolMaxThread;
114 | }
115 |
116 | public void setDefaultThreadPoolMaxThread(int defaultThreadPoolMaxThread) {
117 | this.defaultThreadPoolMaxThread = defaultThreadPoolMaxThread;
118 | }
119 |
120 | public String getServerAddr() {
121 | return serverAddr;
122 | }
123 |
124 | public void setServerAddr(String serverAddr) {
125 | this.serverAddr = serverAddr;
126 | }
127 |
128 | public int getWriteRetryTimes() {
129 | return writeRetryTimes;
130 | }
131 |
132 | public void setWriteRetryTimes(int writeRetryTimes) {
133 | this.writeRetryTimes = writeRetryTimes;
134 | }
135 |
136 | public int getCandidateStatusTimeout() {
137 | return candidateStatusTimeout;
138 | }
139 |
140 | public void setCandidateStatusTimeout(int candidateStatusTimeout) {
141 | this.candidateStatusTimeout = candidateStatusTimeout;
142 | }
143 |
144 | public int getVoteBaseTime() {
145 | return voteBaseTime;
146 | }
147 |
148 | public void setVoteBaseTime(int voteBaseTime) {
149 | this.voteBaseTime = voteBaseTime;
150 | }
151 |
152 | public int getAbnormalActiveInterval() {
153 | return abnormalActiveInterval;
154 | }
155 |
156 | public void setAbnormalActiveInterval(int abnormalActiveInterval) {
157 | this.abnormalActiveInterval = abnormalActiveInterval;
158 | }
159 |
160 | public List getMemberAddresses() {
161 | return memberAddresses;
162 | }
163 |
164 | public void setMemberAddresses(List memberAddresses) {
165 | this.memberAddresses = memberAddresses;
166 | }
167 |
168 | public int getHeartInterval() {
169 | return heartInterval;
170 | }
171 |
172 | public void setHeartInterval(int heartInterval) {
173 | this.heartInterval = heartInterval;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/entity/SimpleFuture.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.entity;
2 |
3 | import java.util.concurrent.Callable;
4 | import java.util.concurrent.ExecutorService;
5 | import java.util.concurrent.Future;
6 | import java.util.concurrent.LinkedBlockingQueue;
7 | import java.util.concurrent.ThreadPoolExecutor;
8 | import java.util.concurrent.TimeUnit;
9 | import java.util.concurrent.locks.Condition;
10 | import java.util.concurrent.locks.ReentrantLock;
11 |
12 | /**
13 | * @author Daydreamer
14 | *
15 | * future
16 | */
17 | public class SimpleFuture implements Future {
18 |
19 | private T data;
20 |
21 | private Exception throwable;
22 |
23 | /**
24 | * single thread pool
25 | */
26 | private ExecutorService executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.MICROSECONDS, new LinkedBlockingQueue<>(),
27 | r -> {
28 | Thread thread = new Thread(r);
29 | thread.setName("Future-Thread");
30 | thread.setDaemon(true);
31 | return thread;
32 | });
33 |
34 | private volatile boolean isCancel = false;
35 |
36 | private volatile boolean finish = false;
37 |
38 | public SimpleFuture(Callable callable) {
39 | Runnable task = () -> {
40 | try {
41 | data = callable.call();
42 | } catch (Exception e) {
43 | // nothing to do
44 | throwable = e;
45 | }
46 | finish = true;
47 | // close
48 | executor.shutdown();
49 | };
50 | executor.execute(task);
51 | }
52 |
53 | @Override
54 | public synchronized boolean cancel(boolean mayInterruptIfRunning) {
55 | if (isCancel) {
56 | return isCancel;
57 | }
58 | isCancel = mayInterruptIfRunning;
59 | notifyAll();
60 | // clear
61 | executor.shutdown();
62 | return isCancel;
63 | }
64 |
65 | @Override
66 | public boolean isCancelled() {
67 | return isCancel;
68 | }
69 |
70 | @Override
71 | public boolean isDone() {
72 | return finish;
73 | }
74 |
75 | @Override
76 | public synchronized T get() throws InterruptedException {
77 | while (!finish) {
78 | wait(200);
79 | }
80 | return data;
81 | }
82 |
83 | @Override
84 | public synchronized T get(long timeout, TimeUnit unit) throws InterruptedException {
85 | long begin = System.currentTimeMillis();
86 | long remain = unit.toMillis(timeout);
87 | while (remain > 0 && !finish) {
88 | wait(200);
89 | remain = remain - (System.currentTimeMillis() - begin);
90 | }
91 | return data;
92 | }
93 |
94 | /**
95 | * if exception
96 | *
97 | * @return exception
98 | */
99 | public synchronized Exception getException() throws InterruptedException {
100 | while (!finish) {
101 | wait(200);
102 | }
103 | return throwable;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/filter/LogFilter.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.filter;
2 |
3 | import com.daydreamer.raft.api.entity.base.LogEntry;
4 | import com.daydreamer.raft.api.callback.CommitHook;
5 | import com.daydreamer.raft.common.annotation.SPI;
6 |
7 | /**
8 | * @author Daydreamer
9 | *
10 | * it will be invoked after log committed, before {@link CommitHook}
11 | */
12 | @SPI("filterChain")
13 | public interface LogFilter {
14 |
15 | /**
16 | * filter log
17 | *
18 | * @param logEntry log
19 | * @return whether to filter current log
20 | */
21 | boolean filter(LogEntry logEntry);
22 | }
23 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/filter/impl/FilterChain.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.filter.impl;
2 |
3 | import com.daydreamer.raft.api.entity.base.LogEntry;
4 | import com.daydreamer.raft.common.annotation.SPIImplement;
5 | import com.daydreamer.raft.common.annotation.SPIMethodInit;
6 | import com.daydreamer.raft.common.filter.LogFilter;
7 | import com.daydreamer.raft.common.loader.GroupAware;
8 | import com.daydreamer.raft.common.loader.RaftServiceLoader;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | @SPIImplement("filterChain")
14 | public class FilterChain implements LogFilter, GroupAware {
15 |
16 | private final List filters = new ArrayList<>();
17 |
18 | private String groupKey;
19 |
20 | @SPIMethodInit
21 | private void init() {
22 | List all = RaftServiceLoader.getLoader(groupKey, LogFilter.class).getAll();
23 | if (all != null) {
24 | filters.addAll(all);
25 | filters.remove(this);
26 | }
27 | }
28 |
29 | @Override
30 | public void setGroupKey(String key) {
31 | this.groupKey = key;
32 | }
33 |
34 | @Override
35 | public boolean filter(LogEntry logEntry) {
36 | for (LogFilter filter : filters) {
37 | // if anyone return false, then reject
38 | if (!filter.filter(logEntry)) {
39 | return false;
40 | }
41 | }
42 | return true;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/loader/GroupAware.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.loader;
2 |
3 | /**
4 | * @author Daydreamer
5 | *
6 | * In order to get group key
7 | */
8 | public interface GroupAware {
9 |
10 | void setGroupKey(String key);
11 | }
12 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/loader/ServiceFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.loader;
2 |
3 | import com.daydreamer.raft.common.annotation.SPI;
4 |
5 | /**
6 | * @author Daydreamer
7 | */
8 | @SPI("adaptiveServiceFactory")
9 | public interface ServiceFactory extends GroupAware{
10 |
11 | T getDependency(Class type, String name);
12 | }
13 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/loader/impl/AdaptiveServiceFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.loader.impl;
2 |
3 | import com.daydreamer.raft.common.annotation.SPIImplement;
4 | import com.daydreamer.raft.common.annotation.SPIMethodInit;
5 | import com.daydreamer.raft.common.loader.RaftServiceLoader;
6 | import com.daydreamer.raft.common.loader.ServiceFactory;
7 | import java.util.List;
8 |
9 | /**
10 | * @author Daydreamer
11 | */
12 | @SPIImplement("adaptiveServiceFactory")
13 | public class AdaptiveServiceFactory implements ServiceFactory {
14 |
15 | private List serviceFactories;
16 |
17 | private String groupKey;
18 |
19 | public AdaptiveServiceFactory() {
20 |
21 | }
22 |
23 | @SPIMethodInit
24 | private void init() {
25 | RaftServiceLoader loader = RaftServiceLoader.getLoader(groupKey, ServiceFactory.class);
26 | serviceFactories = loader.getAll();
27 | // remove current
28 | serviceFactories.remove(this);
29 | }
30 |
31 | @Override
32 | public T getDependency(Class type, String name) {
33 | for (ServiceFactory serviceFactory : serviceFactories) {
34 | T dependency = serviceFactory.getDependency(type, name);
35 | if (dependency != null) {
36 | return dependency;
37 | }
38 | }
39 | return null;
40 | }
41 |
42 | @Override
43 | public void setGroupKey(String key) {
44 | this.groupKey = key;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/loader/impl/ConfigServiceFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.loader.impl;
2 |
3 | import com.daydreamer.raft.common.annotation.SPIImplement;
4 | import com.daydreamer.raft.common.loader.ServiceFactory;
5 | import com.daydreamer.raft.common.service.ActiveProperties;
6 |
7 | import java.util.Map;
8 | import java.util.concurrent.ConcurrentHashMap;
9 |
10 | /**
11 | * @author Daydreamer
12 | */
13 | @SPIImplement("configServiceFactory")
14 | public class ConfigServiceFactory implements ServiceFactory {
15 |
16 | private final Map map = new ConcurrentHashMap<>();
17 |
18 | private String groupKey;
19 |
20 | @Override
21 | public T getDependency(Class type, String name) {
22 | if (map.containsKey(name) && map.get(name).getClass().equals(type)) {
23 | return type.cast(map.get(name));
24 | }
25 | return null;
26 | }
27 |
28 | /**
29 | * add property
30 | *
31 | * @param name property name
32 | * @param properties property
33 | */
34 | public void addProperty(String name, ActiveProperties properties) {
35 | map.putIfAbsent(name, properties);
36 | }
37 |
38 | @Override
39 | public void setGroupKey(String key) {
40 | this.groupKey = key;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/loader/impl/SPIServiceFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.loader.impl;
2 |
3 | import com.daydreamer.raft.common.annotation.SPIImplement;
4 | import com.daydreamer.raft.common.loader.GroupAware;
5 | import com.daydreamer.raft.common.loader.RaftServiceLoader;
6 | import com.daydreamer.raft.common.loader.ServiceFactory;
7 |
8 | import java.lang.reflect.Modifier;
9 |
10 | /**
11 | * @author Daydreamer
12 | */
13 | @SPIImplement("spiServiceFactory")
14 | public class SPIServiceFactory implements ServiceFactory {
15 |
16 | private String groupKey;
17 |
18 | @Override
19 | public T getDependency(Class type, String name) {
20 | // if interface or abstract class, then try to find
21 | if (Modifier.isInterface(type.getModifiers())
22 | || Modifier.isAbstract(type.getModifiers())) {
23 | return RaftServiceLoader.getLoader(groupKey, type).getInstance(name);
24 | }
25 | // no found
26 | return null;
27 | }
28 |
29 | @Override
30 | public void setGroupKey(String key) {
31 | this.groupKey = key;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/service/ActiveProperties.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.service;
2 |
3 | /**
4 | * @author Daydreamer
5 | */
6 | public interface ActiveProperties {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/service/PropertiesReader.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.service;
2 |
3 | import com.daydreamer.raft.common.utils.MD5Utils;
4 | import org.apache.log4j.Logger;
5 |
6 | import java.io.BufferedInputStream;
7 | import java.io.File;
8 | import java.io.FileInputStream;
9 | import java.io.IOException;
10 | import java.io.InputStream;
11 | import java.util.Objects;
12 | import java.util.Properties;
13 | import java.util.concurrent.ExecutorService;
14 | import java.util.concurrent.LinkedBlockingQueue;
15 | import java.util.concurrent.ThreadPoolExecutor;
16 | import java.util.concurrent.TimeUnit;
17 |
18 | /**
19 | * @author Daydreamer
20 | */
21 | public abstract class PropertiesReader {
22 |
23 | private static final Logger LOGGER = Logger.getLogger(PropertiesReader.class);
24 |
25 | /**
26 | * target file
27 | */
28 | private String filePath;
29 |
30 | /**
31 | * executor
32 | */
33 | private ExecutorService executorService;
34 |
35 | /**
36 | * properties loader
37 | */
38 | private T properties;
39 |
40 | /**
41 | * file hash
42 | */
43 | private String hash = "";
44 |
45 | /**
46 | * whether open
47 | */
48 | private boolean open;
49 |
50 | public PropertiesReader(String filePath, T properties, boolean open) {
51 | this.filePath = filePath;
52 | this.properties = properties;
53 | this.open = open;
54 | if (this.open) {
55 | executorService = new ThreadPoolExecutor(1, 1, 1000, TimeUnit.MICROSECONDS, new LinkedBlockingQueue<>(), r -> {
56 | Thread thread = new Thread(r);
57 | thread.setDaemon(true);
58 | thread.setName("Watch-Dog-Thread-For-File: " + filePath);
59 | thread.setUncaughtExceptionHandler((t, e) -> {
60 | LOGGER.error("Fail to execute watch job, because: " + e.getLocalizedMessage());
61 | });
62 | return thread;
63 | });
64 | // init
65 | init();
66 | }
67 | }
68 |
69 | public boolean isOpen() {
70 | return open;
71 | }
72 |
73 | /**
74 | * init method
75 | */
76 | private void init() {
77 | // load
78 | load();
79 | // add job
80 | executorService.execute(this::changeDetectJob);
81 | }
82 |
83 | /**
84 | * load properties
85 | *
86 | * @return properties
87 | */
88 | private Properties load() {
89 | Properties p = new Properties();
90 | InputStream in = null;
91 | try {
92 | // load
93 | File file = new File(Objects.requireNonNull(getClass().getClassLoader().getResource(filePath)).getFile());
94 | if (!file.exists()) {
95 | throw new IllegalArgumentException("[PropertiesReader] - Cannot find property file, bad path: " + filePath);
96 | }
97 | in = new BufferedInputStream(new FileInputStream(file));
98 | p.load(in);
99 | // populate
100 | populateProperties(p, properties);
101 | // calculate hash
102 | hash = MD5Utils.getFileMD5String(file);
103 | } catch (Exception e) {
104 | LOGGER.error("Fail to load properties, because: " + e.getLocalizedMessage());
105 | } finally {
106 | if (in != null) {
107 | try {
108 | in.close();
109 | } catch (IOException e) {
110 | // nothing to do
111 | }
112 | }
113 | }
114 | return p;
115 | }
116 |
117 |
118 | /**
119 | * watch job
120 | */
121 | private void changeDetectJob() {
122 | File file = new File(Objects.requireNonNull(getClass().getClassLoader().getResource(filePath)).getFile());
123 | if (!file.exists()) {
124 | throw new IllegalStateException("[PropertiesReader] - Properties loss, file name: " + filePath);
125 | }
126 | try {
127 | String strHash = MD5Utils.getFileMD5String(file);
128 | // if change
129 | if (!strHash.equals(hash)) {
130 | populateProperties(load(), properties);
131 | }
132 | } catch (IOException e) {
133 | throw new IllegalStateException("[PropertiesReader] - Properties loss, file name: " + filePath);
134 | }
135 | }
136 |
137 | /**
138 | * properties
139 | *
140 | * @return properties
141 | */
142 | public T getProperties() {
143 | return properties;
144 | }
145 |
146 | /**
147 | * close
148 | */
149 | public void close() {
150 | if (executorService != null) {
151 | executorService.shutdown();
152 | }
153 | }
154 |
155 | /**
156 | * base on the properties to do some
157 | *
158 | * @param properties properties
159 | * @param activeProperties active properties
160 | */
161 | public abstract void populateProperties(Properties properties, T activeProperties);
162 | }
163 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/threadpool/ThreadPoolFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.threadpool;
2 |
3 | import com.daydreamer.raft.common.annotation.SPI;
4 |
5 | import java.util.concurrent.Executor;
6 |
7 | /**
8 | * @author Daydreamer
9 | */
10 | @SPI("adaptiveThreadPoolFactory")
11 | public interface ThreadPoolFactory {
12 |
13 | /**
14 | * max priority
15 | */
16 | int MAX_PRIORITY = Integer.MAX_VALUE;
17 |
18 | /**
19 | * min priority
20 | */
21 | int MIN_PRIORITY = Integer.MIN_VALUE;
22 |
23 | /**
24 | * get {@link Executor} by key
25 | *
26 | * @param key key
27 | * @return Executor
28 | */
29 | Executor getExecutor(Object key);
30 |
31 | /**
32 | * the larger order, the faster invoke
33 | *
34 | * @return order
35 | */
36 | int getOrder();
37 | }
38 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/threadpool/impl/AdaptiveThreadPoolFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.threadpool.impl;
2 |
3 | import com.daydreamer.raft.common.annotation.SPIImplement;
4 | import com.daydreamer.raft.common.annotation.SPIMethodInit;
5 | import com.daydreamer.raft.common.loader.GroupAware;
6 | import com.daydreamer.raft.common.loader.RaftServiceLoader;
7 | import com.daydreamer.raft.common.threadpool.ThreadPoolFactory;
8 |
9 | import java.util.ArrayList;
10 | import java.util.Comparator;
11 | import java.util.List;
12 | import java.util.concurrent.Executor;
13 |
14 | /**
15 | * @author Daydreamer
16 | */
17 | @SPIImplement("adaptiveThreadPoolFactory")
18 | public class AdaptiveThreadPoolFactory implements ThreadPoolFactory, GroupAware {
19 |
20 | private final List threadPoolFactories = new ArrayList<>();
21 |
22 | private String groupKey;
23 |
24 | @SPIMethodInit
25 | private void init() {
26 | // add all thread pool
27 | List all = RaftServiceLoader
28 | .getLoader(groupKey, ThreadPoolFactory.class)
29 | .getAll();
30 | threadPoolFactories.addAll(all);
31 | threadPoolFactories.remove(this);
32 | threadPoolFactories.sort(Comparator.comparingInt(ThreadPoolFactory::getOrder));
33 | }
34 |
35 | @Override
36 | public Executor getExecutor(Object key) {
37 | for (ThreadPoolFactory threadPoolFactory : threadPoolFactories) {
38 | Executor executor = threadPoolFactory.getExecutor(key);
39 | if (executor != null) {
40 | return executor;
41 | }
42 | }
43 | return null;
44 | }
45 |
46 | @Override
47 | public int getOrder() {
48 | return ThreadPoolFactory.MAX_PRIORITY;
49 | }
50 |
51 | public void setGroupKey(String groupKey) {
52 | this.groupKey = groupKey;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/common/src/main/java/com/daydreamer/raft/common/threadpool/impl/CacheThreadPoolFactory.java:
--------------------------------------------------------------------------------
1 | package com.daydreamer.raft.common.threadpool.impl;
2 |
3 | import com.daydreamer.raft.api.collection.MemorySafeLinkedBlockingQueue;
4 | import com.daydreamer.raft.common.annotation.SPIImplement;
5 | import com.daydreamer.raft.common.entity.RaftConfig;
6 | import com.daydreamer.raft.common.threadpool.ThreadPoolFactory;
7 |
8 | import java.util.Map;
9 | import java.util.concurrent.ConcurrentHashMap;
10 | import java.util.concurrent.Executor;
11 | import java.util.concurrent.ThreadPoolExecutor;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | @SPIImplement("cacheThreadPoolFactory")
15 | public class CacheThreadPoolFactory implements ThreadPoolFactory {
16 |
17 | private Map