├── .gitignore
├── .travis.yml
├── CHANGES.md
├── LICENSE
├── README.md
├── bin
├── ci-deploy-snapshot.sh
├── ci-push-javadoc.sh
├── push-javadoc.sh
└── settings.xml
├── client
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── client
│ │ ├── ConnectionStrategies.java
│ │ ├── ConnectionStrategy.java
│ │ ├── CopycatClient.java
│ │ ├── DefaultCopycatClient.java
│ │ ├── RecoveryStrategies.java
│ │ ├── RecoveryStrategy.java
│ │ ├── ServerSelectionStrategies.java
│ │ ├── ServerSelectionStrategy.java
│ │ ├── package-info.java
│ │ ├── session
│ │ ├── ClientSequencer.java
│ │ ├── ClientSession.java
│ │ ├── ClientSessionListener.java
│ │ ├── ClientSessionManager.java
│ │ ├── ClientSessionState.java
│ │ ├── ClientSessionSubmitter.java
│ │ └── package-info.java
│ │ └── util
│ │ ├── AddressSelector.java
│ │ ├── ClientConnection.java
│ │ └── OrderedCompletableFuture.java
│ └── test
│ ├── java
│ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── client
│ │ ├── ConnectionStrategiesTest.java
│ │ ├── DefaultCopycatClientTest.java
│ │ ├── RecoveryStrategiesTest.java
│ │ ├── ServerSelectionStrategiesTest.java
│ │ ├── session
│ │ ├── ClientSequencerTest.java
│ │ ├── ClientSessionManagerTest.java
│ │ ├── ClientSessionStateTest.java
│ │ └── ClientSessionSubmitterTest.java
│ │ └── util
│ │ ├── AddressSelectorTest.java
│ │ └── OrderedCompletableFutureTest.java
│ └── resources
│ └── logback.xml
├── examples
├── pom.xml
├── value-client
│ ├── pom.xml
│ └── src
│ │ └── main
│ │ ├── java
│ │ └── io
│ │ │ └── atomix
│ │ │ └── copycat
│ │ │ └── examples
│ │ │ └── ValueClientExample.java
│ │ └── resources
│ │ └── logback.xml
└── value-state-machine
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── examples
│ │ ├── DeleteCommand.java
│ │ ├── GetQuery.java
│ │ ├── SetCommand.java
│ │ ├── ValueStateMachine.java
│ │ └── ValueStateMachineExample.java
│ └── resources
│ └── logback.xml
├── pom.xml
├── protocol
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── io
│ │ │ └── atomix
│ │ │ └── copycat
│ │ │ ├── Command.java
│ │ │ ├── NoOpCommand.java
│ │ │ ├── Operation.java
│ │ │ ├── Query.java
│ │ │ ├── error
│ │ │ ├── ApplicationException.java
│ │ │ ├── CommandException.java
│ │ │ ├── ConfigurationException.java
│ │ │ ├── CopycatError.java
│ │ │ ├── CopycatException.java
│ │ │ ├── IllegalMemberStateException.java
│ │ │ ├── InternalException.java
│ │ │ ├── NoLeaderException.java
│ │ │ ├── OperationException.java
│ │ │ ├── QueryException.java
│ │ │ ├── UnknownSessionException.java
│ │ │ └── package-info.java
│ │ │ ├── package-info.java
│ │ │ ├── protocol
│ │ │ ├── AbstractRequest.java
│ │ │ ├── AbstractResponse.java
│ │ │ ├── ClientRequestTypeResolver.java
│ │ │ ├── ClientResponseTypeResolver.java
│ │ │ ├── CommandRequest.java
│ │ │ ├── CommandResponse.java
│ │ │ ├── ConnectRequest.java
│ │ │ ├── ConnectResponse.java
│ │ │ ├── KeepAliveRequest.java
│ │ │ ├── KeepAliveResponse.java
│ │ │ ├── OperationRequest.java
│ │ │ ├── OperationResponse.java
│ │ │ ├── PublishRequest.java
│ │ │ ├── QueryRequest.java
│ │ │ ├── QueryResponse.java
│ │ │ ├── RegisterRequest.java
│ │ │ ├── RegisterResponse.java
│ │ │ ├── Request.java
│ │ │ ├── ResetRequest.java
│ │ │ ├── Response.java
│ │ │ ├── SessionRequest.java
│ │ │ ├── SessionResponse.java
│ │ │ ├── UnregisterRequest.java
│ │ │ ├── UnregisterResponse.java
│ │ │ └── package-info.java
│ │ │ ├── session
│ │ │ ├── ClosedSessionException.java
│ │ │ ├── Event.java
│ │ │ ├── Session.java
│ │ │ └── package-info.java
│ │ │ └── util
│ │ │ └── ProtocolSerialization.java
│ └── resources
│ │ └── META-INF
│ │ └── services
│ │ └── io.atomix.catalyst.serializer.CatalystSerializable
│ └── test
│ └── java
│ └── io
│ └── atomix
│ └── copycat
│ └── error
│ └── CopycatErrorTest.java
├── server
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── server
│ │ ├── Commit.java
│ │ ├── CopycatServer.java
│ │ ├── Snapshottable.java
│ │ ├── StateMachine.java
│ │ ├── StateMachineContext.java
│ │ ├── StateMachineExecutor.java
│ │ ├── cluster
│ │ ├── Cluster.java
│ │ ├── Member.java
│ │ └── package-info.java
│ │ ├── package-info.java
│ │ ├── protocol
│ │ ├── AppendRequest.java
│ │ ├── AppendResponse.java
│ │ ├── ConfigurationRequest.java
│ │ ├── ConfigurationResponse.java
│ │ ├── ConfigureRequest.java
│ │ ├── ConfigureResponse.java
│ │ ├── InstallRequest.java
│ │ ├── InstallResponse.java
│ │ ├── JoinRequest.java
│ │ ├── JoinResponse.java
│ │ ├── LeaveRequest.java
│ │ ├── LeaveResponse.java
│ │ ├── PollRequest.java
│ │ ├── PollResponse.java
│ │ ├── ReconfigureRequest.java
│ │ ├── ReconfigureResponse.java
│ │ ├── VoteRequest.java
│ │ ├── VoteResponse.java
│ │ └── package-info.java
│ │ ├── session
│ │ ├── ServerSession.java
│ │ ├── SessionListener.java
│ │ ├── Sessions.java
│ │ └── package-info.java
│ │ ├── state
│ │ ├── AbstractAppender.java
│ │ ├── AbstractState.java
│ │ ├── ActiveState.java
│ │ ├── CandidateState.java
│ │ ├── ClusterState.java
│ │ ├── ConnectionManager.java
│ │ ├── FollowerAppender.java
│ │ ├── FollowerState.java
│ │ ├── InactiveState.java
│ │ ├── LeaderAppender.java
│ │ ├── LeaderState.java
│ │ ├── MemberState.java
│ │ ├── PassiveState.java
│ │ ├── ReserveState.java
│ │ ├── ServerClock.java
│ │ ├── ServerCommit.java
│ │ ├── ServerCommitPool.java
│ │ ├── ServerContext.java
│ │ ├── ServerMember.java
│ │ ├── ServerSessionContext.java
│ │ ├── ServerSessionManager.java
│ │ ├── ServerState.java
│ │ ├── ServerStateMachine.java
│ │ ├── ServerStateMachineContext.java
│ │ ├── ServerStateMachineExecutor.java
│ │ └── package-info.java
│ │ ├── storage
│ │ ├── DescriptorException.java
│ │ ├── Log.java
│ │ ├── Segment.java
│ │ ├── SegmentDescriptor.java
│ │ ├── SegmentFile.java
│ │ ├── SegmentManager.java
│ │ ├── Storage.java
│ │ ├── StorageCleaner.java
│ │ ├── StorageException.java
│ │ ├── StorageLevel.java
│ │ ├── compaction
│ │ │ ├── Compaction.java
│ │ │ ├── CompactionManager.java
│ │ │ ├── CompactionTask.java
│ │ │ ├── Compactor.java
│ │ │ ├── MajorCompactionManager.java
│ │ │ ├── MajorCompactionTask.java
│ │ │ ├── MinorCompactionManager.java
│ │ │ ├── MinorCompactionTask.java
│ │ │ └── package-info.java
│ │ ├── entry
│ │ │ ├── CommandEntry.java
│ │ │ ├── ConfigurationEntry.java
│ │ │ ├── Entry.java
│ │ │ ├── InitializeEntry.java
│ │ │ ├── KeepAliveEntry.java
│ │ │ ├── OperationEntry.java
│ │ │ ├── QueryEntry.java
│ │ │ ├── RegisterEntry.java
│ │ │ ├── SessionEntry.java
│ │ │ ├── TimestampedEntry.java
│ │ │ ├── TypedEntryPool.java
│ │ │ ├── UnregisterEntry.java
│ │ │ └── package-info.java
│ │ ├── index
│ │ │ ├── DelegatingOffsetIndex.java
│ │ │ ├── OffsetIndex.java
│ │ │ ├── SearchableOffsetIndex.java
│ │ │ └── SequentialOffsetIndex.java
│ │ ├── package-info.java
│ │ ├── snapshot
│ │ │ ├── FileSnapshot.java
│ │ │ ├── MemorySnapshot.java
│ │ │ ├── Snapshot.java
│ │ │ ├── SnapshotDescriptor.java
│ │ │ ├── SnapshotFile.java
│ │ │ ├── SnapshotReader.java
│ │ │ ├── SnapshotStore.java
│ │ │ ├── SnapshotWriter.java
│ │ │ └── package-info.java
│ │ ├── system
│ │ │ ├── Configuration.java
│ │ │ ├── MetaStore.java
│ │ │ └── package-info.java
│ │ └── util
│ │ │ ├── EntryBuffer.java
│ │ │ ├── OffsetPredicate.java
│ │ │ ├── StorageSerialization.java
│ │ │ └── TermIndex.java
│ │ └── util
│ │ ├── Quorum.java
│ │ └── ServerSerialization.java
│ └── test
│ ├── java
│ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── server
│ │ ├── TestStateMachine.java
│ │ ├── Testing.java
│ │ ├── state
│ │ ├── AbstractStateTest.java
│ │ ├── ActiveStateTest.java
│ │ ├── CandidateStateTest.java
│ │ ├── FollowerStateTest.java
│ │ ├── LeaderStateTest.java
│ │ ├── MemberTest.java
│ │ ├── PassiveStateTest.java
│ │ ├── ServerContextTest.java
│ │ ├── ServerSessionTest.java
│ │ └── ServerStateMachineTest.java
│ │ ├── storage
│ │ ├── AbstractLogTest.java
│ │ ├── AbstractSnapshotStoreTest.java
│ │ ├── FileLogTest.java
│ │ ├── FileSnapshotStoreTest.java
│ │ ├── LogTest.java
│ │ ├── MajorCompactionTest.java
│ │ ├── MappedLogTest.java
│ │ ├── MemoryLogTest.java
│ │ ├── MemorySnapshotStoreTest.java
│ │ ├── MetaStoreTest.java
│ │ ├── MinorCompactionTest.java
│ │ ├── OffsetIndexTest.java
│ │ ├── OffsetPredicateTest.java
│ │ ├── SegmentDescriptorTest.java
│ │ ├── SegmentManagerTest.java
│ │ └── TestEntry.java
│ │ └── util
│ │ └── QuorumTest.java
│ └── resources
│ ├── META-INF
│ └── services
│ │ └── io.atomix.catalyst.serializer.CatalystSerializable
│ └── logback.xml
└── test
├── pom.xml
└── src
├── main
├── java
│ └── io
│ │ └── atomix
│ │ └── copycat
│ │ └── test
│ │ ├── FuzzTest.java
│ │ └── PerformanceTest.java
└── resources
│ └── logback.xml
└── test
├── java
└── io
│ └── atomix
│ └── copycat
│ └── test
│ └── ClusterTest.java
└── resources
└── logback.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | test-output/
3 | .settings/
4 | .classpath/
5 | *.project
6 | .idea
7 | *.classpath
8 | *.iml
9 | .DS_Store
10 | pom.xml.tag
11 | pom.xml.releaseBackup
12 | pom.xml.versionsBackup
13 | pom.xml.next
14 | release.properties
15 | dependency-reduced-pom.xml
16 | buildNumber.properties
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | sudo: false
3 | os: linux
4 | dist: trusty
5 |
6 | jdk:
7 | - oraclejdk8
8 | - openjdk8
9 |
10 | notifications:
11 | email: false
12 |
13 | branches:
14 | only:
15 | - master
16 |
17 | script:
18 | - mvn test -Droot.logging.level=INFO
19 |
20 | after_success:
21 | - mvn clean test jacoco:report coveralls:report -Droot.logging.level=INFO
22 | - bin/ci-push-javadoc.sh
23 | - bin/ci-deploy-snapshot.sh
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Copycat
2 |
3 | [](https://travis-ci.org/atomix/copycat)
4 | [](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22io.atomix.copycat%22)
5 | [](https://gitter.im/atomix/atomix)
6 |
7 | ### Copycat has moved!
8 |
9 | Copycat 2.x is now [atomix-raft](https://github.com/atomix/atomix/blob/master/protocols/raft/src/main/java/io/atomix/protocols/raft)
10 | and includes a variety of improvements to Copycat 1.x:
11 | * Multiple state machines per cluster
12 | * Multiple sessions per client
13 | * Index-free memory mapped log
14 | * Per-state-machine snapshots
15 | * Framework agnostic serialization
16 | * Partitioning
17 | * etc
18 |
19 | This repository is no longer officially maintained.
20 |
--------------------------------------------------------------------------------
/bin/ci-deploy-snapshot.sh:
--------------------------------------------------------------------------------
1 | # From https://coderwall.com/p/9b_lfq
2 |
3 | REPO="atomix/copycat"
4 |
5 | if [ "$TRAVIS_REPO_SLUG" == "$REPO" ] && \
6 | [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ] && \
7 | [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
8 | [ "$TRAVIS_BRANCH" == "master" ]; then
9 | echo -e "Publishing maven snapshot...\n"
10 |
11 | mvn clean source:jar deploy --settings="bin/settings.xml" -DskipTests=true -Dmaven.javadoc.skip=true
12 |
13 | echo -e "Published maven snapshot"
14 | fi
--------------------------------------------------------------------------------
/bin/ci-push-javadoc.sh:
--------------------------------------------------------------------------------
1 | # Called by Travis CI to push latest javadoc
2 | # From http://benlimmer.com/2013/12/26/automatically-publish-javadoc-to-gh-pages-with-travis-ci/
3 |
4 | PROJECT=copycat
5 |
6 | if [ "$TRAVIS_REPO_SLUG" == "atomix/$PROJECT" ] && \
7 | [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ] && \
8 | [ "$TRAVIS_PULL_REQUEST" == "false" ] && \
9 | [ "$TRAVIS_BRANCH" == "master" ]; then
10 | echo -e "Publishing Javadoc...\n"
11 |
12 | mvn javadoc:javadoc -Djv=latest
13 | TARGET="$(pwd)/target"
14 |
15 | cd $HOME
16 | git clone --quiet https://${GH_TOKEN}@github.com/atomix/atomix.github.io gh-pages > /dev/null
17 |
18 | cd gh-pages
19 | git config --global user.email "travis@travis-ci.org"
20 | git config --global user.name "travis-ci"
21 | git rm -rf $PROJECT/api/latest
22 | mkdir -p $PROJECT/api/latest
23 | mv -v $TARGET/site/apidocs/* $PROJECT/api/latest
24 | git add -A -f $PROJECT/api/latest
25 | git commit -m "Travis generated Javadoc for $PROJECT build $TRAVIS_BUILD_NUMBER"
26 | git push -fq origin > /dev/null
27 |
28 | echo -e "Published Javadoc to atomix.github.io.\n"
29 | fi
30 |
--------------------------------------------------------------------------------
/bin/push-javadoc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Pushes javadocs for an given release version
3 | # Run from top level dir
4 |
5 | PROJECT=copycat
6 |
7 | echo "Enter the API version to generate docs for: "
8 | read apiVersion
9 |
10 | mvn javadoc:javadoc -Djv=$apiVersion
11 | rm -rf target/docs
12 | git clone git@github.com:atomix/atomix.github.io.git target/docs > /dev/null
13 | cd target/docs
14 | git rm -rf $PROJECT/api/$apiVersion
15 | mkdir -p $PROJECT/api/$apiVersion
16 | mv -v ../site/apidocs/* $PROJECT/api/$apiVersion
17 | git add -A -f $PROJECT/api/$apiVersion
18 | git commit -m "Updated JavaDocs for $apiVersion"
19 | git push -fq origin master > /dev/null
20 |
21 | echo "Published $apiVersion Javadoc to atomix.github.io.\n"
--------------------------------------------------------------------------------
/bin/settings.xml:
--------------------------------------------------------------------------------
1 |
21 | * Client recovery strategies are responsible for recovering a crashed client. When clients fail to contact
22 | * a server for more than their session timeout, the client's session must be closed as linearizability is
23 | * lost. The recovery strategy has the opportunity to recover the crashed client gracefully.
24 | *
25 | * @author
21 | * Client recovery strategies are responsible for recovering a crashed client. When a client is unable
22 | * to communicate with the cluster for some time period, the cluster may expire the client's session.
23 | * In the event that a client reconnects and discovers its session is expired, the client's configured
24 | * recovery strategy will be queried to determine how to handle the failure. Typically, recovery strategies
25 | * can either {@link CopycatClient#recover() recover} or {@link CopycatClient#close() close} the client.
26 | *
27 | * @author
25 | * Selection strategies prioritize communication with certain servers over others. When the client
26 | * loses its connection or cluster membership changes, the client will request a list of servers to
27 | * which the client can connect. The address list should be prioritized.
28 | *
29 | * @author
20 | * The client is a fully featured client that facilitates submitting {@link io.atomix.copycat.Command commands}
21 | * and {@link io.atomix.copycat.Query queries} to a Copycat cluster. Clients communicate with the cluster within
22 | * the context of a session. To create a client and connect to the cluster, use the {@link io.atomix.copycat.client.CopycatClient.Builder}.
23 | *
24 | * {@code
25 | * CopycatClient client = CopycatClient.builder(servers)
26 | * .withTransport(new NettyTransport())
27 | * .build();
28 | * client.open().join();
29 | * }
30 | *
31 | * Clients are designed to communicate with any server in the cluster in a transparent manner. See the
32 | * {@link io.atomix.copycat.client.CopycatClient} documentation for more information.
33 | *
34 | * @author Jordan Halterman
35 | */
36 | package io.atomix.copycat.client;
37 |
--------------------------------------------------------------------------------
/client/src/main/java/io/atomix/copycat/client/session/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 |
17 | /**
18 | * Facilitates communication with the Copycat cluster within the context of a session.
19 | *
20 | * Clients communicate with the Copycat cluster within the context of a session. Sessions are used to
21 | * achieve linearizable semantics and first-in-first-out ordering of client operations by coordinating
22 | * {@link io.atomix.copycat.Command commands} and {@link io.atomix.copycat.Query queries} submitted by
23 | * the client to the cluster. Additionally, sessions facilitate listening for event notifications from
24 | * the cluster. When state changes occur in the server-side replicated state machine, state machines
25 | * can publish messages notifying the client of events. The session aids in guaranteeing sequential
26 | * and linearizable consistency for server-to-client communication.
27 | *
28 | * @author Jordan Halterman
29 | */
30 | package io.atomix.copycat.client.session;
31 |
--------------------------------------------------------------------------------
/client/src/test/java/io/atomix/copycat/client/RecoveryStrategiesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.client;
17 |
18 | import org.testng.annotations.Test;
19 |
20 | import static org.mockito.Mockito.mock;
21 | import static org.mockito.Mockito.verify;
22 |
23 | /**
24 | * Session recovery strategies test.
25 | *
26 | * @author assertEquals(3, order.incrementAndGet()));
31 | future.thenAccept(r -> {
32 | assertEquals(5, order.incrementAndGet());
33 | assertEquals(r, "foo");
34 | });
35 | future.thenApply(r -> {
36 | assertEquals(6, order.incrementAndGet());
37 | assertEquals(r, "foo");
38 | return "bar";
39 | });
40 | future.whenComplete((r, e) -> {
41 | assertEquals(7, order.incrementAndGet());
42 | assertEquals(r, "foo");
43 | });
44 | future.complete("foo");
45 | }
46 |
47 | /**
48 | * Tests ordered failure of future callbacks.
49 | */
50 | public void testOrderedFailure() throws Throwable {
51 | CompletableFuture Example cluster arguments: Example single node arguments:
26 | * No-op commands are submitted by clients to the cluster to complete missing command sequence numbers.
27 | * Copycat clusters require that clients submit commands in sequential order and use a client-provided
28 | * sequence number to ensure FIFO ordering of operations submitted to the cluster. In the event that a
29 | * command fails to be committed to the cluster, a client can resubmit a no-op command to ensure command
30 | * sequence numbers continue to progress.
31 | *
32 | * @author
25 | * This is a base interface for operations on the Raft cluster state. Operations are submitted to Raft clusters
26 | * by clients via a {@link Session}. All operations are sent over the network
27 | * and thus must be serializable by the client and by all servers in the cluster. By default, Java serialization
28 | * is used. However, it is recommended that operations implement {@link io.atomix.catalyst.serializer.CatalystSerializable}
29 | * or register a {@link io.atomix.catalyst.serializer.TypeSerializer} for better performance.
30 | *
31 | * @see Command
32 | * @see Query
33 | *
34 | * @param
21 | * Application exceptions are thrown when an exception occurs within a user-provided state machine.
22 | *
23 | * @author Jordan Halterman
24 | */
25 | public class ApplicationException extends CopycatException {
26 | private static final CopycatError.Type TYPE = CopycatError.Type.APPLICATION_ERROR;
27 |
28 | public ApplicationException(String message, Object... args) {
29 | super(TYPE, message, args);
30 | }
31 |
32 | public ApplicationException(Throwable cause, String message, Object... args) {
33 | super(TYPE, cause, message, args);
34 | }
35 |
36 | public ApplicationException(Throwable cause) {
37 | super(TYPE, cause);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/CommandException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Indicates that an error occurred while committing a write command.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class CommandException extends OperationException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.COMMAND_ERROR;
25 |
26 | public CommandException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public CommandException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public CommandException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/ConfigurationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Indicates that an error occurred while committing a write command.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class ConfigurationException extends OperationException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.CONFIGURATION_ERROR;
25 |
26 | public ConfigurationException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public ConfigurationException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public ConfigurationException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/CopycatException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Base Copycat protocol exception.
20 | *
21 | * This is the base exception type for all Copycat protocol exceptions. Protocol exceptions must be
22 | * associated with a {@link CopycatError.Type} which is used for more efficient serialization.
23 | *
24 | * @author Jordan Halterman
25 | */
26 | public abstract class CopycatException extends RuntimeException {
27 | private final CopycatError.Type type;
28 |
29 | protected CopycatException(CopycatError.Type type, String message, Object... args) {
30 | super(String.format(message, args));
31 | if (type == null)
32 | throw new NullPointerException("type cannot be null");
33 | this.type = type;
34 | }
35 |
36 | protected CopycatException(CopycatError.Type type, Throwable cause, String message, Object... args) {
37 | super(String.format(message, args), cause);
38 | if (type == null)
39 | throw new NullPointerException("type cannot be null");
40 | this.type = type;
41 | }
42 |
43 | protected CopycatException(CopycatError.Type type, Throwable cause) {
44 | super(cause);
45 | if (type == null)
46 | throw new NullPointerException("type cannot be null");
47 | this.type = type;
48 | }
49 |
50 | /**
51 | * Returns the exception type.
52 | *
53 | * @return The exception type.
54 | */
55 | public CopycatError.Type getType() {
56 | return type;
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/IllegalMemberStateException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Indicates that a server received a request for which it was not in the appropriate state to handle.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class IllegalMemberStateException extends CopycatException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.ILLEGAL_MEMBER_STATE_ERROR;
25 |
26 | public IllegalMemberStateException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public IllegalMemberStateException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public IllegalMemberStateException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/InternalException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Catch-all exception for unknown Raft protocol errors.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class InternalException extends CopycatException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.INTERNAL_ERROR;
25 |
26 | public InternalException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public InternalException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public InternalException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/NoLeaderException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Indicates that the server that received a request is not the leader and does not know of a leader.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class NoLeaderException extends CopycatException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.NO_LEADER_ERROR;
25 |
26 | public NoLeaderException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public NoLeaderException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public NoLeaderException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/OperationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Base class for operation exceptions {@link CommandException} and {@link QueryException}.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class QueryException extends OperationException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.QUERY_ERROR;
25 |
26 | public QueryException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public QueryException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public QueryException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/UnknownSessionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.error;
17 |
18 | /**
19 | * Indicates that an operation or other request from an unknown session was received.
20 | *
21 | * @author Jordan Halterman
22 | */
23 | public class UnknownSessionException extends CopycatException {
24 | private static final CopycatError.Type TYPE = CopycatError.Type.UNKNOWN_SESSION_ERROR;
25 |
26 | public UnknownSessionException(String message, Object... args) {
27 | super(TYPE, message, args);
28 | }
29 |
30 | public UnknownSessionException(Throwable cause, String message, Object... args) {
31 | super(TYPE, cause, message, args);
32 | }
33 |
34 | public UnknownSessionException(Throwable cause) {
35 | super(TYPE, cause);
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/error/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * Provides error constants and exceptions associated with the Raft consensus protocol.
19 | *
20 | * Copycat protocol errors are designed to be transported across networks in the most efficient manner possible. Each protocol exception
21 | * is associated with a 1-byte identifier. Rather than serializing complete {@link java.lang.Exception} objects, the protocol exception is
22 | * sent using only its identifier and the exception is recreated by the receiving side of a connection.
23 | *
24 | * @author Jordan Halterman
25 | */
26 | package io.atomix.copycat.error;
27 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * Core interfaces for operating on replicated state machines in the Copycat cluster.
19 | *
20 | * The interfaces in this package are shared by both clients and servers. They are the interfaces through which clients and servers communicate
21 | * state change and query information with one another.
22 | *
23 | * Clients operate on Copycat replicated state machines by submitting state change {@link io.atomix.copycat.Operation operations} to the cluster.
24 | * Copycat supports separate operations - {@link io.atomix.copycat.Command} and {@link io.atomix.copycat.Query} - for submitting state change
25 | * and read-only operations respectively. Each operation maps to a method of a replicated state machine. The handling of operations is dependent
26 | * on a variety of factors, including the operation type and the operation's {@link io.atomix.copycat.Query.ConsistencyLevel consistency level}.
27 | * When an operation is submitted to the cluster, the operation will eventually be translated into a method call on the replicated state machine
28 | * and a response will be sent back to the client.
29 | *
21 | * Command responses are sent by servers to clients upon the completion of a
22 | * {@link CommandRequest}. Command responses are sent with the
23 | * {@link #index()} (or index) of the state machine at the point at which the command was evaluated.
24 | * This can be used by the client to ensure it sees state progress monotonically. Note, however, that
25 | * command responses may not be sent or received in sequential order. If a command response has to await
26 | * the completion of an event, or if the response is proxied through another server, responses may be
27 | * received out of order. Clients should resequence concurrent responses to ensure they're handled in FIFO order.
28 | *
29 | * @author Jordan Halterman
30 | */
31 | public class CommandResponse extends OperationResponse {
32 |
33 | /**
34 | * Returns a new submit response builder.
35 | *
36 | * @return A new submit response builder.
37 | */
38 | public static Builder builder() {
39 | return new Builder(new CommandResponse());
40 | }
41 |
42 | /**
43 | * Returns a submit response builder for an existing request.
44 | *
45 | * @param response The response to build.
46 | * @return The submit response builder.
47 | * @throws NullPointerException if {@code request} is null
48 | */
49 | public static Builder builder(CommandResponse response) {
50 | return new Builder(response);
51 | }
52 |
53 | /**
54 | * Command response builder.
55 | */
56 | public static class Builder extends OperationResponse.Builder
21 | * Query responses are sent by servers to clients upon the completion of a
22 | * {@link QueryRequest}. Query responses are sent with the
23 | * {@link #index()} of the state machine at the point at which the query was evaluated.
24 | * This can be used by the client to ensure it sees state progress monotonically. Note, however, that
25 | * query responses may not be sent or received in sequential order. If a query response is proxied through
26 | * another server, responses may be received out of order. Clients should resequence concurrent responses
27 | * to ensure they're handled in FIFO order.
28 | *
29 | * @author Jordan Halterman
30 | */
31 | public class QueryResponse extends OperationResponse {
32 |
33 | /**
34 | * Returns a new query response builder.
35 | *
36 | * @return A new query response builder.
37 | */
38 | public static Builder builder() {
39 | return new Builder(new QueryResponse());
40 | }
41 |
42 | /**
43 | * Returns a query response builder for an existing request.
44 | *
45 | * @param response The response to build.
46 | * @return The query response builder.
47 | * @throws NullPointerException if {@code request} is null
48 | */
49 | public static Builder builder(QueryResponse response) {
50 | return new Builder(response);
51 | }
52 |
53 | /**
54 | * Query response builder.
55 | */
56 | public static class Builder extends OperationResponse.Builder
26 | * This is the base request for session-related requests. Many client requests are handled within the
27 | * context of a {@link #session()} identifier.
28 | *
29 | * @author Jordan Halterman
30 | */
31 | public abstract class SessionRequest extends AbstractRequest {
32 | protected long session;
33 |
34 | /**
35 | * Returns the session ID.
36 | *
37 | * @return The session ID.
38 | */
39 | public long session() {
40 | return session;
41 | }
42 |
43 | @Override
44 | public void readObject(BufferInput> buffer, Serializer serializer) {
45 | session = buffer.readLong();
46 | }
47 |
48 | @Override
49 | public void writeObject(BufferOutput> buffer, Serializer serializer) {
50 | buffer.writeLong(session);
51 | }
52 |
53 | /**
54 | * Session request builder.
55 | */
56 | public static abstract class Builder
23 | * The unregister request is sent by a client with an open session to the cluster to explicitly
24 | * unregister its session. Note that if a client does not send an unregister request, its session will
25 | * eventually expire. The unregister request simply provides a more orderly method for closing client sessions.
26 | *
27 | * @author Jordan Halterman
28 | */
29 | public class UnregisterRequest extends SessionRequest {
30 |
31 | /**
32 | * Returns a new unregister request builder.
33 | *
34 | * @return A new unregister request builder.
35 | */
36 | public static Builder builder() {
37 | return new Builder(new UnregisterRequest());
38 | }
39 |
40 | /**
41 | * Returns a unregister request builder for an existing request.
42 | *
43 | * @param request The request to build.
44 | * @return The unregister request builder.
45 | * @throws NullPointerException if {@code request} is null
46 | */
47 | public static Builder builder(UnregisterRequest request) {
48 | return new Builder(request);
49 | }
50 |
51 | @Override
52 | public int hashCode() {
53 | return Objects.hash(getClass(), session);
54 | }
55 |
56 | @Override
57 | public boolean equals(Object object) {
58 | if (object instanceof UnregisterRequest) {
59 | UnregisterRequest request = (UnregisterRequest) object;
60 | return request.session == session;
61 | }
62 | return false;
63 | }
64 |
65 | @Override
66 | public String toString() {
67 | return String.format("%s[session=%d]", getClass().getSimpleName(), session);
68 | }
69 |
70 | /**
71 | * Unregister request builder.
72 | */
73 | public static class Builder extends SessionRequest.Builder
20 | * Sessions represent the context in which clients communicate with a Raft cluster. Sessions allow clusters
21 | * to process requests according to client state. For instance, sessions are responsible for ensuring operations
22 | * are executed in the order specified by the client (sequential consistency) and operations are only applied
23 | * to the replicated state machine once (linearizability).
24 | *
25 | * @author Jordan Halterman
26 | */
27 | package io.atomix.copycat.session;
28 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/util/ProtocolSerialization.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.util;
17 |
18 | import io.atomix.catalyst.serializer.SerializableTypeResolver;
19 | import io.atomix.catalyst.serializer.SerializerRegistry;
20 | import io.atomix.catalyst.transport.Address;
21 | import io.atomix.copycat.NoOpCommand;
22 | import io.atomix.copycat.protocol.Request;
23 | import io.atomix.copycat.session.Event;
24 |
25 | import java.util.HashMap;
26 | import java.util.Map;
27 |
28 | /**
29 | * Session serializable type resolver.
30 | *
31 | * @author , Integer> TYPES = new HashMap() {{
36 | put(Address.class, -1);
37 | put(Event.class, -2);
38 | put(NoOpCommand.class, -45);
39 | }};
40 |
41 | @Override
42 | public void resolve(SerializerRegistry registry) {
43 | for (Map.Entry
28 | * The context is reflective of the current position and state of the Raft state machine. In particular,
29 | * it exposes the current approximate {@link StateMachineContext#clock() time} and all open
30 | * {@link Sessions}.
31 | *
32 | * @author Jordan Halterman
21 | */
22 | package io.atomix.copycat.server.cluster;
23 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | /**
18 | * Standalone, feature-complete implementation of the Raft consensus algorithm.
19 | *
20 | * For information on the implementation of the Raft consensus algorithm, see the documentation on
21 | * Copycat internals.
22 | *
23 | * @author Jordan Halterman
24 | */
25 | package io.atomix.copycat.server;
26 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/protocol/JoinRequest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.server.protocol;
17 |
18 | /**
19 | * Server join configuration change request.
20 | *
21 | * The join request is the mechanism by which new servers join a cluster. When a server wants to
22 | * join a cluster, it must submit a join request to the leader. The leader will attempt to commit
23 | * the configuration change and, if successful, respond to the join request with the updated configuration.
24 | *
25 | * @author Jordan Halterman
26 | */
27 | public class JoinRequest extends ConfigurationRequest {
28 |
29 | /**
30 | * Returns a new join request builder.
31 | *
32 | * @return A new join request builder.
33 | */
34 | public static Builder builder() {
35 | return new Builder(new JoinRequest());
36 | }
37 |
38 | /**
39 | * Returns an join request builder for an existing request.
40 | *
41 | * @param request The request to build.
42 | * @return The join request builder.
43 | */
44 | public static Builder builder(JoinRequest request) {
45 | return new Builder(request);
46 | }
47 |
48 | /**
49 | * Join request builder.
50 | */
51 | public static class Builder extends ConfigurationRequest.Builder
23 | * Join responses are sent in response to a request to add a server to the cluster configuration. If a
24 | * configuration change is failed due to a conflict, the response status will be
25 | * {@link Response.Status#ERROR} but the response {@link #error()} will
26 | * be {@code null}.
27 | *
28 | * @author Jordan Halterman
29 | */
30 | public class JoinResponse extends ConfigurationResponse {
31 |
32 | /**
33 | * Returns a new join response builder.
34 | *
35 | * @return A new join response builder.
36 | */
37 | public static Builder builder() {
38 | return new Builder(new JoinResponse());
39 | }
40 |
41 | /**
42 | * Returns an join response builder for an existing response.
43 | *
44 | * @param response The response to build.
45 | * @return The join response builder.
46 | */
47 | public static Builder builder(JoinResponse response) {
48 | return new Builder(response);
49 | }
50 |
51 | /**
52 | * Join response builder.
53 | */
54 | public static class Builder extends ConfigurationResponse.Builder
21 | * The leave request is the mechanism by which servers remove themselves from a cluster. When a server
22 | * wants to leave a cluster, it must submit a leave request to the leader. The leader will attempt to commit
23 | * the configuration change and, if successful, respond to the join request with the updated configuration.
24 | *
25 | * @author Jordan Halterman
26 | */
27 | public class LeaveRequest extends ConfigurationRequest {
28 |
29 | /**
30 | * Returns a new leave request builder.
31 | *
32 | * @return A new leave request builder.
33 | */
34 | public static Builder builder() {
35 | return new Builder(new LeaveRequest());
36 | }
37 |
38 | /**
39 | * Returns an leave request builder for an existing request.
40 | *
41 | * @param request The request to build.
42 | * @return The leave request builder.
43 | */
44 | public static Builder builder(LeaveRequest request) {
45 | return new Builder(request);
46 | }
47 |
48 | /**
49 | * Leave request builder.
50 | */
51 | public static class Builder extends ConfigurationRequest.Builder
23 | * Leave responses are sent in response to a request to add a server to the cluster configuration. If a
24 | * configuration change is failed due to a conflict, the response status will be
25 | * {@link Response.Status#ERROR} but the response {@link #error()} will
26 | * be {@code null}.
27 | *
28 | * @author Jordan Halterman
29 | */
30 | public class LeaveResponse extends ConfigurationResponse {
31 |
32 | /**
33 | * Returns a new leave response builder.
34 | *
35 | * @return A new leave response builder.
36 | */
37 | public static Builder builder() {
38 | return new Builder(new LeaveResponse());
39 | }
40 |
41 | /**
42 | * Returns an leave response builder for an existing response.
43 | *
44 | * @param response The response to build.
45 | * @return The leave response builder.
46 | */
47 | public static Builder builder(LeaveResponse response) {
48 | return new Builder(response);
49 | }
50 |
51 | /**
52 | * Leave response builder.
53 | */
54 | public static class Builder extends ConfigurationResponse.Builder
22 | * Server state machines can use the {@code Sessions} object to access the list of sessions currently open to the
23 | * state machine. Session sets are guaranteed to be deterministic. All state machines will see the same set of
24 | * open sessions at the same point in the log except in cases where a session has already been closed and removed.
25 | * If a session has already been closed on another server, the session is guaranteed to have been expired on all
26 | * servers and thus operations like {@link ServerSession#publish(String, Object)} are effectively no-ops.
27 | *
28 | * @author
20 | * Client session information is exposed to server {@link io.atomix.copycat.server.StateMachine state machines} in the form of a
21 | * {@link io.atomix.copycat.server.session.ServerSession} object. Server sessions provide functionality in addition to normal session state
22 | * information to allow replicated state machines to {@link io.atomix.copycat.server.session.ServerSession#publish(java.lang.String, java.lang.Object) publish}
23 | * event notifications to clients through their session.
24 | *
25 | * @author Jordan Halterman
26 | */
27 | package io.atomix.copycat.server.session;
28 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/state/FollowerAppender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.server.state;
17 |
18 | import io.atomix.copycat.server.cluster.Member;
19 |
20 | /**
21 | * Follower appender.
22 | *
23 | * @author Jordan Halterman
31 | */
32 | final class ServerCommitPool implements AutoCloseable {
33 | private static final Logger LOGGER = LoggerFactory.getLogger(ServerCommitPool.class);
34 | private final Log log;
35 | private final ServerSessionManager sessions;
36 | private final Queue
21 | * Storage levels represent the method used to store the individual {@link Segment segments} that make up a
22 | * {@link Log}. When configuring a {@link Storage} module, the storage can be configured to write
23 | * {@link io.atomix.copycat.server.storage.entry.Entry entries} to disk, memory, or memory-mapped files using the
24 | * values provided by this enum. The {@code StorageLevel} configuration dictates the type of
25 | * {@link io.atomix.catalyst.buffer.Buffer} to which to write entries. See the specific storage levels for more
26 | * information.
27 | *
28 | * @see Storage
29 | *
30 | * @author
26 | * Compaction managers are responsible for providing a set of {@link CompactionTask}s to be executed
27 | * during log compaction. Each {@link Compaction} type is associated with a compaction manager.
28 | *
29 | * @author
23 | * Compaction tasks are responsible for compacting one or more segments in a
24 | * {@link io.atomix.copycat.server.storage.Log}. Tasks are provided by a related {@link CompactionManager}
25 | * and are run in parallel in a pool of {@link Storage#compactionThreads()} background threads.
26 | *
27 | * @author
20 | * The log compaction package implements compaction for Copycat {@link io.atomix.copycat.server.storage.Log logs} using
21 | * a custom log cleaning algorithm. As entries are written to the log and applied to the server's state machine, the
22 | * state machine can arbitrarily mark entries for removal from the log. Periodically, a set of log compaction threads
23 | * will compact {@link io.atomix.copycat.server.storage.Segment segment}s of the log in the background. Log compaction
24 | * is performed in two phases: {@link io.atomix.copycat.server.storage.compaction.MinorCompactionTask minor} and
25 | * {@link io.atomix.copycat.server.storage.compaction.MajorCompactionTask major}. The minor compaction process efficiently
26 | * rewrites individual segments to remove standard entries that have been marked for cleaning. The major compaction process
27 | * periodically rewrites the entire log to combine segments that have previously been compacted.
28 | *
29 | * @author Jordan Halterman
30 | */
31 | package io.atomix.copycat.server.storage.compaction;
32 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/storage/entry/CommandEntry.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.server.storage.entry;
17 |
18 | import io.atomix.catalyst.buffer.BufferInput;
19 | import io.atomix.catalyst.buffer.BufferOutput;
20 | import io.atomix.catalyst.serializer.Serializer;
21 | import io.atomix.catalyst.util.Assert;
22 | import io.atomix.catalyst.util.reference.ReferenceManager;
23 | import io.atomix.copycat.Command;
24 | import io.atomix.copycat.Operation;
25 | import io.atomix.copycat.server.storage.compaction.Compaction;
26 |
27 | /**
28 | * Stores a state machine {@link Command}.
29 | *
30 | * The {@code CommandEntry} is used to store an individual state machine command from an individual
31 | * client along with information relevant to sequencing the command in the server state machine.
32 | *
33 | * @author Jordan Halterman
34 | */
35 | public class CommandEntry extends OperationEntry
31 | * The {@code ConfigurationEntry} stores information relevant to a single cluster configuration change.
32 | * Configuration change entries store a collection of {@link Member members} which each represent a
33 | * server in the cluster. Each time the set of members changes or a property of a single member changes,
34 | * a new {@code ConfigurationEntry} must be logged for the configuration change.
35 | *
36 | * @author Jordan Halterman
37 | */
38 | public class ConfigurationEntry extends TimestampedEntry
24 | * The {@code InitializeEntry} is logged by a leader at the beginning of its term to indicate that
25 | * a leadership change has occurred. Importantly, initialize entries are logged with a {@link #getTimestamp() timestamp}
26 | * which can be used by server state machines to reset session timeouts following leader changes. Initialize entries
27 | * are always the first entry to be committed at the start of a leader's term.
28 | *
29 | * @author Jordan Halterman
30 | */
31 | public class InitializeEntry extends TimestampedEntry
27 | * Each state machine operation is stored with a client-provided {@link #getSequence() sequence number}.
28 | * The sequence number is used by state machines to apply client operations in the order in which they
29 | * were submitted by the client (FIFO order). Additionally, each operation is written with the leader's
30 | * {@link #getTimestamp() timestamp} at the time the entry was logged. This gives state machines an
31 | * approximation of time with which to react to the application of operations to the state machine.
32 | *
33 | * @author Jordan Halterman
34 | */
35 | public abstract class OperationEntry
29 | * The {@code QueryEntry} is a special entry that is typically not ever written to the Raft log.
30 | * Query entries are simply used to represent the context within which a query is applied to the
31 | * state machine. Query entry {@link #getSequence() sequence} numbers and {@link #getIndex() indexes}
32 | * are used to sequence queries as they're applied to the user state machine.
33 | *
34 | * @author Jordan Halterman
35 | */
36 | public class QueryEntry extends OperationEntry
20 | * Logs are the vehicle through which Copycat servers persist and replicate state changes. The Copycat log is designed
21 | * specifically for use with the Raft consensus algorithm. The log is partitioned into multiple files called
22 | * segments. Each segment represents a sequence of indexes in the log. As entries are written to the log and
23 | * segments fill up, the log rolls over to new segments. Once a completed segment has been written and the entries
24 | * within it have been committed, the segment is compacted.
25 | *
26 | * Log compaction is a two-stage process. The {@link io.atomix.copycat.server.storage.compaction.MinorCompactionTask minor compaction}
27 | * process periodically rewrites segments to remove non-tombstone and snapshot-related entries that have been released by the
28 | * state machine. The {@link io.atomix.copycat.server.storage.compaction.MajorCompactionTask major compaction} process periodically
29 | * rewrites segments to remove tombstones and combines multiple segments together to reduce the number of open file descriptors.
30 | *
31 | * Copycat logs also support {@link io.atomix.copycat.server.storage.snapshot.SnapshotStore snapshotting}. Each snapshot
32 | * taken of the state machine's state is associated with a number of snapshotted entries. When segments are compacted,
33 | * entries compacted by the last snapshot are removed from segment files on disk.
34 | *
35 | * For more information on Copycat's log and log compaction algorithms, see the
36 | * log documentation on the Atomix website.
37 | *
38 | * @author Jordan Halterman
39 | */
40 | package io.atomix.copycat.server.storage;
41 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/storage/snapshot/MemorySnapshot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.server.storage.snapshot;
17 |
18 | import io.atomix.catalyst.buffer.HeapBuffer;
19 | import io.atomix.catalyst.util.Assert;
20 |
21 | /**
22 | * In-memory snapshot backed by a {@link HeapBuffer}.
23 | *
24 | * @author
20 | * Snapshots are byte-level representations of the state machine's state taken periodically to allow entries
21 | * to be removed from Copycat's {@link io.atomix.copycat.server.storage.Log} during log compaction.
22 | * Copycat interacts with snapshots primarily through the {@link io.atomix.copycat.server.storage.snapshot.SnapshotStore}
23 | * which is responsible for storing and loading snapshots. Each snapshot is stored as a separate file
24 | * on disk, and old snapshots may or may not be retained depending on the {@link io.atomix.copycat.server.storage.Storage}
25 | * configuration.
26 | *
27 | * @author Jordan Halterman
28 | */
29 | package io.atomix.copycat.server.storage.snapshot;
30 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/storage/system/Configuration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.server.storage.system;
17 |
18 | import io.atomix.catalyst.util.Assert;
19 | import io.atomix.copycat.server.cluster.Member;
20 |
21 | import java.util.Collection;
22 |
23 | /**
24 | * Represents a persisted server configuration.
25 | *
26 | * This class represents a cluster configuration stored on disk. Configurations are managed by
27 | * a {@link MetaStore}, stored on disk when {@link io.atomix.copycat.server.cluster.Cluster Cluster}
28 | * configurations change, and loaded from disk on server startup.
29 | *
30 | * @author
48 | * The index is the index of the {@link io.atomix.copycat.server.storage.entry.ConfigurationEntry ConfigurationEntry}
49 | * which resulted in this configuration.
50 | *
51 | * @return The configuration index.
52 | */
53 | public long index() {
54 | return index;
55 | }
56 |
57 | /**
58 | * Returns the configuration term.
59 | *
60 | * The term is the term of the leader at the time the configuration change was committed.
61 | *
62 | * @return The configuration term.
63 | */
64 | public long term() {
65 | return term;
66 | }
67 |
68 | /**
69 | * Returns the configuration time.
70 | *
71 | * @return The time at which the configuration was committed.
72 | */
73 | public long time() {
74 | return time;
75 | }
76 |
77 | /**
78 | * Returns the cluster membership for this configuration.
79 | *
80 | * @return The cluster membership.
81 | */
82 | public Collection
20 | * The {@link io.atomix.copycat.server.storage.system.MetaStore} is the primary interface through which servers
21 | * store and load server {@link io.atomix.copycat.server.storage.system.Configuration configurations} on disk.
22 | * Configurations include the current cluster configuration as well as the server's last
23 | * {@link io.atomix.copycat.server.storage.system.MetaStore#loadTerm() term} and
24 | * {@link io.atomix.copycat.server.storage.system.MetaStore#loadVote() vote} which must be persisted according
25 | * to the Raft consensus algorithm.
26 | *
27 | * @author Jordan Halterman
28 | */
29 | package io.atomix.copycat.server.storage.system;
30 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/storage/util/EntryBuffer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.server.storage.util;
17 |
18 | import io.atomix.copycat.server.storage.entry.Entry;
19 |
20 | /**
21 | * Log entry buffer.
22 | *
23 | * @author T get(long index) {
57 | Entry entry = buffer[offset(index)];
58 | return entry != null && entry.getIndex() == index ? (T) entry.acquire() : null;
59 | }
60 |
61 | /**
62 | * Clears the buffer and resets the index to the given index.
63 | *
64 | * @return The entry buffer.
65 | */
66 | public EntryBuffer clear() {
67 | for (int i = 0; i < buffer.length; i++) {
68 | buffer[i] = null;
69 | }
70 | return this;
71 | }
72 |
73 | /**
74 | * Returns the buffer index for the given offset.
75 | */
76 | private int offset(long index) {
77 | int offset = (int) (index % buffer.length);
78 | if (offset < 0) {
79 | offset += buffer.length;
80 | }
81 | return offset;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/server/src/main/java/io/atomix/copycat/server/storage/util/OffsetPredicate.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 | package io.atomix.copycat.server.storage.util;
17 |
18 | import io.atomix.catalyst.buffer.util.BitArray;
19 | import io.atomix.catalyst.util.Assert;
20 |
21 | import java.util.function.Predicate;
22 |
23 | /**
24 | * Segment offset liveness predicate.
25 | *
26 | * The offset predicate tracks the liveness of relative offsets within a segment. Liveness is tracked
27 | * in a {@link BitArray} that is resized to accommodate offsets as necessary. Each bit in the array
28 | * represents the liveness of a relative offset in the segment. When an offset is
29 | * {@link #release(long) released} from a segment, the bit at that offset is flipped in the bit array.
30 | * {@link #test(Long) Testing} the predicate indicates whether an offset is still live in the segment.
31 | *
32 | * @author , Integer> TYPES = new HashMap() {{
34 | put(CommandEntry.class, -36);
35 | put(ConfigurationEntry.class, -37);
36 | put(KeepAliveEntry.class, -38);
37 | put(InitializeEntry.class, -39);
38 | put(QueryEntry.class, -40);
39 | put(RegisterEntry.class, -41);
40 | put(UnregisterEntry.class, -43);
41 | }};
42 |
43 | @Override
44 | public void resolve(SerializerRegistry registry) {
45 | for (Map.Entry
24 | * The term index facilitates storing terms for a group of entries by relating the term only
25 | * to the first offset for all entries in the term. Because terms are monotonically increasing,
26 | * we can assume that if entry {@code n}'s term is {@code t} then entry {@code n + 1}'s term
27 | * will be {@code t} or greater.
28 | *
29 | * The implementation of the term index uses a {@link TreeMap} to store a map of offsets to
30 | * terms. To look up the term for any given offset, we use {@code map.floorEntry(offset)}
31 | * to loop up the term for the offset.
32 | *
33 | * This class is thread safe.
34 | *
35 | * @author Jordan Halterman
25 | */
26 | public class Quorum {
27 | private final int quorum;
28 | private int succeeded = 1;
29 | private int failed;
30 | private Consumerlogs 10.0.1.10:5000 10.0.1.11:5001 10.0.1.12:5002
35 | * logs localhost:5000
36 | *
37 | * @author members = new ArrayList<>();
54 | for (int i = 1; i < args.length; i++) {
55 | String[] parts = args[i].split(":");
56 | members.add(new Address(parts[0], Integer.valueOf(parts[1])));
57 | }
58 |
59 | CopycatServer server = CopycatServer.builder(address)
60 | .withStateMachine(ValueStateMachine::new)
61 | .withTransport(new NettyTransport())
62 | .withStorage(Storage.builder()
63 | .withDirectory(args[0])
64 | .withMaxSegmentSize(1024 * 1024 * 32)
65 | .withMinorCompactionInterval(Duration.ofMinutes(1))
66 | .withMajorCompactionInterval(Duration.ofMinutes(15))
67 | .build())
68 | .build();
69 |
70 | server.serializer().register(SetCommand.class, 1);
71 | server.serializer().register(GetQuery.class, 2);
72 | server.serializer().register(DeleteCommand.class, 3);
73 |
74 | server.bootstrap(members).join();
75 |
76 | while (server.isRunning()) {
77 | Thread.sleep(1000);
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/examples/value-state-machine/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
16 | Commands
30 | * {@link io.atomix.copycat.Command Commands} are operations that modify the state of the replicated state machine. A command is a serializable
31 | * object that will be sent to the leader of the cluster and replicated to a persisted on a majority of the servers in the Copycat cluster before
32 | * being applied to the state machine. Once a command is committed (stored on a majority of servers), it's translated into a method call on the
33 | * state machine on each server. The return value of the state machine method on the leader is sent back to the client.
34 | * Queries
35 | * {@link io.atomix.copycat.Query Queries} are operations that read but do not modify the state of the replicated state machine. Because queries
36 | * do not effect the state of the system, servers do not have to replicate them to a majority of the cluster, and no disk I/O is necessary to
37 | * complete a query of the state machine's state. Like commands, queries translate to a method call on the replicated state machine, but only
38 | * the server to which the query is submitted applies the query to its state machine. Once a query is completed, the return value of the state
39 | * machine method called is sent back to the client.
40 | *
41 | * @author Jordan Halterman
42 | */
43 | package io.atomix.copycat;
44 |
--------------------------------------------------------------------------------
/protocol/src/main/java/io/atomix/copycat/protocol/AbstractRequest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package io.atomix.copycat.protocol;
17 |
18 | import io.atomix.catalyst.buffer.BufferInput;
19 | import io.atomix.catalyst.buffer.BufferOutput;
20 | import io.atomix.catalyst.serializer.Serializer;
21 |
22 | import java.util.Objects;
23 |
24 | /**
25 | * Base request for all client requests.
26 | *
27 | * @author Jordan Halterman
28 | */
29 | public abstract class AbstractRequest implements Request {
30 |
31 | @Override
32 | public void writeObject(BufferOutput> buffer, Serializer serializer) {
33 | }
34 |
35 | @Override
36 | public void readObject(BufferInput> buffer, Serializer serializer) {
37 | }
38 |
39 | /**
40 | * Abstract request builder.
41 | *
42 | * @param