From 2df7a3d1a5f358d7a11d2a51f9f62ca8693d33b9 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 11:58:51 -0500 Subject: [PATCH 01/26] Refactor must-be-leader logic into base state This is in preparation for other must-be-leader logic --- .../main/java/org/robotninjas/barge/state/BaseState.java | 9 +++++++++ .../main/java/org/robotninjas/barge/state/Candidate.java | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java b/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java index 816b758..8f3220b 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java @@ -2,6 +2,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; +import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; @@ -31,4 +33,11 @@ boolean shouldVoteFor(@Nonnull RaftLog log, @Nonnull RequestVote request) { } + @Nonnull + public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException { + throw throwMustBeLeader(); + } + + protected abstract RuntimeException throwMustBeLeader() throws RaftException; + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index 756f056..1612da6 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -174,7 +174,6 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ throw new NoLeaderException(); } - @VisibleForTesting List> sendRequests(RaftStateContext ctx) { From a6b12877f2947bd0a5ff4970b913e2618190e3e7 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 15:42:29 -0500 Subject: [PATCH 02/26] Initial work on re-configuration --- .../java/org/robotninjas/barge/Replica.java | 16 +- .../org/robotninjas/barge/log/RaftLog.java | 76 +- .../org/robotninjas/barge/proto/LogProto.java | 1039 ++--------------- .../robotninjas/barge/proto/RaftEntry.java | 927 ++++++++++++++- .../robotninjas/barge/proto/RaftProto.java | 824 ++++++++++++- .../robotninjas/barge/state/BaseState.java | 9 - .../robotninjas/barge/state/Candidate.java | 13 +- .../barge/state/ConfigurationState.java | 110 ++ .../org/robotninjas/barge/state/Follower.java | 12 + .../org/robotninjas/barge/state/Leader.java | 108 +- .../org/robotninjas/barge/state/PollFor.java | 77 ++ .../barge/state/RaftStateContext.java | 9 +- .../org/robotninjas/barge/state/Start.java | 9 +- .../org/robotninjas/barge/state/State.java | 4 + barge-core/src/main/proto/entry.proto | 8 +- barge-core/src/main/proto/log.proto | 7 - .../barge/state/BaseStateTest.java | 7 + .../barge/state/CandidateTest.java | 18 +- .../barge/state/DefaultContextTest.java | 4 +- .../org/robotninjas/barge/tools/LogTool.java | 16 +- 20 files changed, 2222 insertions(+), 1071 deletions(-) create mode 100644 barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java create mode 100644 barge-core/src/main/java/org/robotninjas/barge/state/PollFor.java diff --git a/barge-core/src/main/java/org/robotninjas/barge/Replica.java b/barge-core/src/main/java/org/robotninjas/barge/Replica.java index 4e54823..f346a0e 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/Replica.java +++ b/barge-core/src/main/java/org/robotninjas/barge/Replica.java @@ -35,19 +35,21 @@ public class Replica { private final InetSocketAddress address; + private final String key; - Replica(@Nonnull InetSocketAddress address) { + private Replica(@Nonnull String key, @Nonnull InetSocketAddress address) { + this.key = checkNotNull(key); this.address = checkNotNull(address); } @Nonnull - public static Replica fromString(@Nonnull String info) { + public static Replica fromString(@Nonnull String key) { try { - checkNotNull(info); - HostAndPort hostAndPort = HostAndPort.fromString(info); + checkNotNull(key); + HostAndPort hostAndPort = HostAndPort.fromString(key); InetAddress addr = InetAddress.getByName(hostAndPort.getHostText()); InetSocketAddress saddr = new InetSocketAddress(addr, hostAndPort.getPort()); - return new Replica(saddr); + return new Replica(key, saddr); } catch (UnknownHostException e) { throw Throwables.propagate(e); } @@ -83,4 +85,8 @@ public boolean equals(Object o) { public String toString() { return address.getAddress().getHostName() + ":" + address.getPort(); } + + public String getKey() { + return key; + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 7d82cf0..3dfec3e 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -24,9 +24,12 @@ import com.google.inject.Inject; import com.google.protobuf.ByteString; import journal.io.api.Journal; -import org.robotninjas.barge.ClusterConfig; + import org.robotninjas.barge.Replica; +import org.robotninjas.barge.proto.RaftEntry.Entry; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.rpc.RaftExecutor; +import org.robotninjas.barge.state.ConfigurationState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -43,9 +46,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; -import static com.google.common.collect.Lists.newArrayList; -import static java.util.Collections.unmodifiableList; -import static org.robotninjas.barge.proto.RaftEntry.Entry; import static org.robotninjas.barge.proto.RaftProto.AppendEntries; @NotThreadSafe @@ -55,7 +55,7 @@ public class RaftLog { private static final Entry SENTINEL = Entry.newBuilder().setCommand(ByteString.EMPTY).setTerm(0).build(); private final TreeMap log = Maps.newTreeMap(); - private final ClusterConfig config; + private final ConfigurationState config; private final StateMachineProxy stateMachine; private final RaftJournal journal; private final ListeningExecutorService executor; @@ -70,7 +70,7 @@ public class RaftLog { private volatile long lastApplied = 0; @Inject - RaftLog(@Nonnull Journal journal, @Nonnull ClusterConfig config, + RaftLog(@Nonnull Journal journal, @Nonnull ConfigurationState config, @Nonnull StateMachineProxy stateMachine, @RaftExecutor ListeningExecutorService raftThread) { this.journal = new RaftJournal(checkNotNull(journal)); this.config = checkNotNull(config); @@ -105,6 +105,10 @@ public void append(Entry entry, long index) { lastLogIndex = Math.max(index, lastLogIndex); lastLogTerm = Math.max(entry.getTerm(), lastLogTerm); log.put(index, entry); + + if (entry.hasMembership()) { + config.add(index, entry); + } } }); @@ -118,23 +122,35 @@ private SettableFuture storeEntry(final long index, @Nonnull Entry entry LOGGER.debug("{}", entry); journal.appendEntry(entry, index); log.put(index, entry); + + if (entry.hasMembership()) { + config.add(index, entry); + } + SettableFuture result = SettableFuture.create(); operationResults.put(index, result); return result; } - public ListenableFuture append(@Nonnull byte[] operation) { - + public ListenableFuture append(@Nonnull byte[] operation, @Nonnull Membership membership) { long index = ++lastLogIndex; lastLogTerm = currentTerm; - Entry entry = + Entry.Builder entry = Entry.newBuilder() - .setCommand(ByteString.copyFrom(operation)) - .setTerm(currentTerm) - .build(); + .setTerm(currentTerm); + + if (operation != null) { + checkArgument(membership == null); + entry.setCommand(ByteString.copyFrom(operation)); + } else if (membership != null) { + checkArgument(operation == null); + entry.setMembership(membership); + } else { + checkArgument(false); + } - return storeEntry(index, entry); + return storeEntry(index, entry.build()); } @@ -178,11 +194,21 @@ public GetEntriesResult getEntriesFrom(@Nonnegative long beginningIndex, @Nonneg void fireComitted() { try { for (long i = lastApplied + 1; i <= Math.min(commitIndex, lastLogIndex); ++i, ++lastApplied) { - byte[] rawCommand = log.get(i).getCommand().toByteArray(); - final ByteBuffer operation = ByteBuffer.wrap(rawCommand).asReadOnlyBuffer(); - ListenableFuture result = stateMachine.dispatchOperation(operation); - final SettableFuture returnedResult = operationResults.remove(i); - Futures.addCallback(result, new PromiseBridge(returnedResult)); + Entry entry = log.get(i); + if (entry.hasCommand()) { + ByteString command = entry.getCommand(); +// byte[] rawCommand = command.toByteArray(); +// final ByteBuffer operation = ByteBuffer.wrap(rawCommand).asReadOnlyBuffer(); + final ByteBuffer operation = command.asReadOnlyByteBuffer(); + + ListenableFuture result = stateMachine.dispatchOperation(operation); + final SettableFuture returnedResult = operationResults.remove(i); + Futures.addCallback(result, new PromiseBridge(returnedResult)); + } + + if (!entry.hasMembership() && !entry.hasCommand()){ + LOGGER.warn("Ignoring unusual log entry: {}", entry); + } } } catch (Exception e) { throw propagate(e); @@ -230,16 +256,6 @@ public void lastVotedFor(@Nonnull Optional vote) { journal.appendVote(vote); } - @Nonnull - public Replica self() { - return config.local(); - } - - @Nonnull - public List members() { - return unmodifiableList(newArrayList(config.remote())); - } - @Override public String toString() { return Objects.toStringHelper(getClass()) @@ -269,4 +285,8 @@ public void onFailure(Throwable t) { } } + public Replica self() { + return config.self(); + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/proto/LogProto.java b/barge-core/src/main/java/org/robotninjas/barge/proto/LogProto.java index d6a3e76..4409dac 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/proto/LogProto.java +++ b/barge-core/src/main/java/org/robotninjas/barge/proto/LogProto.java @@ -620,684 +620,6 @@ public org.robotninjas.barge.proto.RaftEntry.EntryOrBuilder getEntryOrBuilder() // @@protoc_insertion_point(class_scope:Append) } - public interface MembershipOrBuilder - extends com.google.protobuf.MessageOrBuilder { - - // required int64 index = 1; - /** - * required int64 index = 1; - */ - boolean hasIndex(); - /** - * required int64 index = 1; - */ - long getIndex(); - - // required int64 term = 2; - /** - * required int64 term = 2; - */ - boolean hasTerm(); - /** - * required int64 term = 2; - */ - long getTerm(); - - // repeated string members = 3; - /** - * repeated string members = 3; - */ - java.util.List - getMembersList(); - /** - * repeated string members = 3; - */ - int getMembersCount(); - /** - * repeated string members = 3; - */ - java.lang.String getMembers(int index); - /** - * repeated string members = 3; - */ - com.google.protobuf.ByteString - getMembersBytes(int index); - } - /** - * Protobuf type {@code Membership} - */ - public static final class Membership extends - com.google.protobuf.GeneratedMessage - implements MembershipOrBuilder { - // Use Membership.newBuilder() to construct. - private Membership(com.google.protobuf.GeneratedMessage.Builder builder) { - super(builder); - this.unknownFields = builder.getUnknownFields(); - } - private Membership(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } - - private static final Membership defaultInstance; - public static Membership getDefaultInstance() { - return defaultInstance; - } - - public Membership getDefaultInstanceForType() { - return defaultInstance; - } - - private final com.google.protobuf.UnknownFieldSet unknownFields; - @java.lang.Override - public final com.google.protobuf.UnknownFieldSet - getUnknownFields() { - return this.unknownFields; - } - private Membership( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - initFields(); - int mutable_bitField0_ = 0; - com.google.protobuf.UnknownFieldSet.Builder unknownFields = - com.google.protobuf.UnknownFieldSet.newBuilder(); - try { - boolean done = false; - while (!done) { - int tag = input.readTag(); - switch (tag) { - case 0: - done = true; - break; - default: { - if (!parseUnknownField(input, unknownFields, - extensionRegistry, tag)) { - done = true; - } - break; - } - case 8: { - bitField0_ |= 0x00000001; - index_ = input.readInt64(); - break; - } - case 16: { - bitField0_ |= 0x00000002; - term_ = input.readInt64(); - break; - } - case 26: { - if (!((mutable_bitField0_ & 0x00000004) == 0x00000004)) { - members_ = new com.google.protobuf.LazyStringArrayList(); - mutable_bitField0_ |= 0x00000004; - } - members_.add(input.readBytes()); - break; - } - } - } - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(this); - } catch (java.io.IOException e) { - throw new com.google.protobuf.InvalidProtocolBufferException( - e.getMessage()).setUnfinishedMessage(this); - } finally { - if (((mutable_bitField0_ & 0x00000004) == 0x00000004)) { - members_ = new com.google.protobuf.UnmodifiableLazyStringList(members_); - } - this.unknownFields = unknownFields.build(); - makeExtensionsImmutable(); - } - } - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.robotninjas.barge.proto.LogProto.internal_static_Membership_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.robotninjas.barge.proto.LogProto.internal_static_Membership_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.robotninjas.barge.proto.LogProto.Membership.class, org.robotninjas.barge.proto.LogProto.Membership.Builder.class); - } - - public static com.google.protobuf.Parser PARSER = - new com.google.protobuf.AbstractParser() { - public Membership parsePartialFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return new Membership(input, extensionRegistry); - } - }; - - @java.lang.Override - public com.google.protobuf.Parser getParserForType() { - return PARSER; - } - - private int bitField0_; - // required int64 index = 1; - public static final int INDEX_FIELD_NUMBER = 1; - private long index_; - /** - * required int64 index = 1; - */ - public boolean hasIndex() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * required int64 index = 1; - */ - public long getIndex() { - return index_; - } - - // required int64 term = 2; - public static final int TERM_FIELD_NUMBER = 2; - private long term_; - /** - * required int64 term = 2; - */ - public boolean hasTerm() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * required int64 term = 2; - */ - public long getTerm() { - return term_; - } - - // repeated string members = 3; - public static final int MEMBERS_FIELD_NUMBER = 3; - private com.google.protobuf.LazyStringList members_; - /** - * repeated string members = 3; - */ - public java.util.List - getMembersList() { - return members_; - } - /** - * repeated string members = 3; - */ - public int getMembersCount() { - return members_.size(); - } - /** - * repeated string members = 3; - */ - public java.lang.String getMembers(int index) { - return members_.get(index); - } - /** - * repeated string members = 3; - */ - public com.google.protobuf.ByteString - getMembersBytes(int index) { - return members_.getByteString(index); - } - - private void initFields() { - index_ = 0L; - term_ = 0L; - members_ = com.google.protobuf.LazyStringArrayList.EMPTY; - } - private byte memoizedIsInitialized = -1; - public final boolean isInitialized() { - byte isInitialized = memoizedIsInitialized; - if (isInitialized != -1) return isInitialized == 1; - - if (!hasIndex()) { - memoizedIsInitialized = 0; - return false; - } - if (!hasTerm()) { - memoizedIsInitialized = 0; - return false; - } - memoizedIsInitialized = 1; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (((bitField0_ & 0x00000001) == 0x00000001)) { - output.writeInt64(1, index_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeInt64(2, term_); - } - for (int i = 0; i < members_.size(); i++) { - output.writeBytes(3, members_.getByteString(i)); - } - getUnknownFields().writeTo(output); - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (((bitField0_ & 0x00000001) == 0x00000001)) { - size += com.google.protobuf.CodedOutputStream - .computeInt64Size(1, index_); - } - if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeInt64Size(2, term_); - } - { - int dataSize = 0; - for (int i = 0; i < members_.size(); i++) { - dataSize += com.google.protobuf.CodedOutputStream - .computeBytesSizeNoTag(members_.getByteString(i)); - } - size += dataSize; - size += 1 * getMembersList().size(); - } - size += getUnknownFields().getSerializedSize(); - memoizedSerializedSize = size; - return size; - } - - private static final long serialVersionUID = 0L; - @java.lang.Override - protected java.lang.Object writeReplace() - throws java.io.ObjectStreamException { - return super.writeReplace(); - } - - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return PARSER.parseFrom(data, extensionRegistry); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseDelimitedFrom(input, extensionRegistry); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return PARSER.parseFrom(input); - } - public static org.robotninjas.barge.proto.LogProto.Membership parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return PARSER.parseFrom(input, extensionRegistry); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.robotninjas.barge.proto.LogProto.Membership prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - @java.lang.Override - protected Builder newBuilderForType( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - Builder builder = new Builder(parent); - return builder; - } - /** - * Protobuf type {@code Membership} - */ - public static final class Builder extends - com.google.protobuf.GeneratedMessage.Builder - implements org.robotninjas.barge.proto.LogProto.MembershipOrBuilder { - public static final com.google.protobuf.Descriptors.Descriptor - getDescriptor() { - return org.robotninjas.barge.proto.LogProto.internal_static_Membership_descriptor; - } - - protected com.google.protobuf.GeneratedMessage.FieldAccessorTable - internalGetFieldAccessorTable() { - return org.robotninjas.barge.proto.LogProto.internal_static_Membership_fieldAccessorTable - .ensureFieldAccessorsInitialized( - org.robotninjas.barge.proto.LogProto.Membership.class, org.robotninjas.barge.proto.LogProto.Membership.Builder.class); - } - - // Construct using org.robotninjas.barge.proto.LogProto.Membership.newBuilder() - private Builder() { - maybeForceBuilderInitialization(); - } - - private Builder( - com.google.protobuf.GeneratedMessage.BuilderParent parent) { - super(parent); - maybeForceBuilderInitialization(); - } - private void maybeForceBuilderInitialization() { - if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { - } - } - private static Builder create() { - return new Builder(); - } - - public Builder clear() { - super.clear(); - index_ = 0L; - bitField0_ = (bitField0_ & ~0x00000001); - term_ = 0L; - bitField0_ = (bitField0_ & ~0x00000002); - members_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00000004); - return this; - } - - public Builder clone() { - return create().mergeFrom(buildPartial()); - } - - public com.google.protobuf.Descriptors.Descriptor - getDescriptorForType() { - return org.robotninjas.barge.proto.LogProto.internal_static_Membership_descriptor; - } - - public org.robotninjas.barge.proto.LogProto.Membership getDefaultInstanceForType() { - return org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance(); - } - - public org.robotninjas.barge.proto.LogProto.Membership build() { - org.robotninjas.barge.proto.LogProto.Membership result = buildPartial(); - if (!result.isInitialized()) { - throw newUninitializedMessageException(result); - } - return result; - } - - public org.robotninjas.barge.proto.LogProto.Membership buildPartial() { - org.robotninjas.barge.proto.LogProto.Membership result = new org.robotninjas.barge.proto.LogProto.Membership(this); - int from_bitField0_ = bitField0_; - int to_bitField0_ = 0; - if (((from_bitField0_ & 0x00000001) == 0x00000001)) { - to_bitField0_ |= 0x00000001; - } - result.index_ = index_; - if (((from_bitField0_ & 0x00000002) == 0x00000002)) { - to_bitField0_ |= 0x00000002; - } - result.term_ = term_; - if (((bitField0_ & 0x00000004) == 0x00000004)) { - members_ = new com.google.protobuf.UnmodifiableLazyStringList( - members_); - bitField0_ = (bitField0_ & ~0x00000004); - } - result.members_ = members_; - result.bitField0_ = to_bitField0_; - onBuilt(); - return result; - } - - public Builder mergeFrom(com.google.protobuf.Message other) { - if (other instanceof org.robotninjas.barge.proto.LogProto.Membership) { - return mergeFrom((org.robotninjas.barge.proto.LogProto.Membership)other); - } else { - super.mergeFrom(other); - return this; - } - } - - public Builder mergeFrom(org.robotninjas.barge.proto.LogProto.Membership other) { - if (other == org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance()) return this; - if (other.hasIndex()) { - setIndex(other.getIndex()); - } - if (other.hasTerm()) { - setTerm(other.getTerm()); - } - if (!other.members_.isEmpty()) { - if (members_.isEmpty()) { - members_ = other.members_; - bitField0_ = (bitField0_ & ~0x00000004); - } else { - ensureMembersIsMutable(); - members_.addAll(other.members_); - } - onChanged(); - } - this.mergeUnknownFields(other.getUnknownFields()); - return this; - } - - public final boolean isInitialized() { - if (!hasIndex()) { - - return false; - } - if (!hasTerm()) { - - return false; - } - return true; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - org.robotninjas.barge.proto.LogProto.Membership parsedMessage = null; - try { - parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { - parsedMessage = (org.robotninjas.barge.proto.LogProto.Membership) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); - } - } - return this; - } - private int bitField0_; - - // required int64 index = 1; - private long index_ ; - /** - * required int64 index = 1; - */ - public boolean hasIndex() { - return ((bitField0_ & 0x00000001) == 0x00000001); - } - /** - * required int64 index = 1; - */ - public long getIndex() { - return index_; - } - /** - * required int64 index = 1; - */ - public Builder setIndex(long value) { - bitField0_ |= 0x00000001; - index_ = value; - onChanged(); - return this; - } - /** - * required int64 index = 1; - */ - public Builder clearIndex() { - bitField0_ = (bitField0_ & ~0x00000001); - index_ = 0L; - onChanged(); - return this; - } - - // required int64 term = 2; - private long term_ ; - /** - * required int64 term = 2; - */ - public boolean hasTerm() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * required int64 term = 2; - */ - public long getTerm() { - return term_; - } - /** - * required int64 term = 2; - */ - public Builder setTerm(long value) { - bitField0_ |= 0x00000002; - term_ = value; - onChanged(); - return this; - } - /** - * required int64 term = 2; - */ - public Builder clearTerm() { - bitField0_ = (bitField0_ & ~0x00000002); - term_ = 0L; - onChanged(); - return this; - } - - // repeated string members = 3; - private com.google.protobuf.LazyStringList members_ = com.google.protobuf.LazyStringArrayList.EMPTY; - private void ensureMembersIsMutable() { - if (!((bitField0_ & 0x00000004) == 0x00000004)) { - members_ = new com.google.protobuf.LazyStringArrayList(members_); - bitField0_ |= 0x00000004; - } - } - /** - * repeated string members = 3; - */ - public java.util.List - getMembersList() { - return java.util.Collections.unmodifiableList(members_); - } - /** - * repeated string members = 3; - */ - public int getMembersCount() { - return members_.size(); - } - /** - * repeated string members = 3; - */ - public java.lang.String getMembers(int index) { - return members_.get(index); - } - /** - * repeated string members = 3; - */ - public com.google.protobuf.ByteString - getMembersBytes(int index) { - return members_.getByteString(index); - } - /** - * repeated string members = 3; - */ - public Builder setMembers( - int index, java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureMembersIsMutable(); - members_.set(index, value); - onChanged(); - return this; - } - /** - * repeated string members = 3; - */ - public Builder addMembers( - java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - ensureMembersIsMutable(); - members_.add(value); - onChanged(); - return this; - } - /** - * repeated string members = 3; - */ - public Builder addAllMembers( - java.lang.Iterable values) { - ensureMembersIsMutable(); - super.addAll(values, members_); - onChanged(); - return this; - } - /** - * repeated string members = 3; - */ - public Builder clearMembers() { - members_ = com.google.protobuf.LazyStringArrayList.EMPTY; - bitField0_ = (bitField0_ & ~0x00000004); - onChanged(); - return this; - } - /** - * repeated string members = 3; - */ - public Builder addMembersBytes( - com.google.protobuf.ByteString value) { - if (value == null) { - throw new NullPointerException(); - } - ensureMembersIsMutable(); - members_.add(value); - onChanged(); - return this; - } - - // @@protoc_insertion_point(builder_scope:Membership) - } - - static { - defaultInstance = new Membership(true); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:Membership) - } - public interface VoteOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -3251,20 +2573,6 @@ public interface JournalEntryOrBuilder */ org.robotninjas.barge.proto.LogProto.AppendOrBuilder getAppendOrBuilder(); - // optional .Membership membership = 3; - /** - * optional .Membership membership = 3; - */ - boolean hasMembership(); - /** - * optional .Membership membership = 3; - */ - org.robotninjas.barge.proto.LogProto.Membership getMembership(); - /** - * optional .Membership membership = 3; - */ - org.robotninjas.barge.proto.LogProto.MembershipOrBuilder getMembershipOrBuilder(); - // optional .Vote vote = 4; /** * optional .Vote vote = 4; @@ -3385,22 +2693,9 @@ private JournalEntry( bitField0_ |= 0x00000001; break; } - case 26: { - org.robotninjas.barge.proto.LogProto.Membership.Builder subBuilder = null; - if (((bitField0_ & 0x00000002) == 0x00000002)) { - subBuilder = membership_.toBuilder(); - } - membership_ = input.readMessage(org.robotninjas.barge.proto.LogProto.Membership.PARSER, extensionRegistry); - if (subBuilder != null) { - subBuilder.mergeFrom(membership_); - membership_ = subBuilder.buildPartial(); - } - bitField0_ |= 0x00000002; - break; - } case 34: { org.robotninjas.barge.proto.LogProto.Vote.Builder subBuilder = null; - if (((bitField0_ & 0x00000004) == 0x00000004)) { + if (((bitField0_ & 0x00000002) == 0x00000002)) { subBuilder = vote_.toBuilder(); } vote_ = input.readMessage(org.robotninjas.barge.proto.LogProto.Vote.PARSER, extensionRegistry); @@ -3408,12 +2703,12 @@ private JournalEntry( subBuilder.mergeFrom(vote_); vote_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000004; + bitField0_ |= 0x00000002; break; } case 42: { org.robotninjas.barge.proto.LogProto.Term.Builder subBuilder = null; - if (((bitField0_ & 0x00000008) == 0x00000008)) { + if (((bitField0_ & 0x00000004) == 0x00000004)) { subBuilder = term_.toBuilder(); } term_ = input.readMessage(org.robotninjas.barge.proto.LogProto.Term.PARSER, extensionRegistry); @@ -3421,12 +2716,12 @@ private JournalEntry( subBuilder.mergeFrom(term_); term_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000008; + bitField0_ |= 0x00000004; break; } case 50: { org.robotninjas.barge.proto.LogProto.Commit.Builder subBuilder = null; - if (((bitField0_ & 0x00000010) == 0x00000010)) { + if (((bitField0_ & 0x00000008) == 0x00000008)) { subBuilder = commit_.toBuilder(); } commit_ = input.readMessage(org.robotninjas.barge.proto.LogProto.Commit.PARSER, extensionRegistry); @@ -3434,12 +2729,12 @@ private JournalEntry( subBuilder.mergeFrom(commit_); commit_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000010; + bitField0_ |= 0x00000008; break; } case 58: { org.robotninjas.barge.proto.LogProto.Snapshot.Builder subBuilder = null; - if (((bitField0_ & 0x00000020) == 0x00000020)) { + if (((bitField0_ & 0x00000010) == 0x00000010)) { subBuilder = snapshot_.toBuilder(); } snapshot_ = input.readMessage(org.robotninjas.barge.proto.LogProto.Snapshot.PARSER, extensionRegistry); @@ -3447,7 +2742,7 @@ private JournalEntry( subBuilder.mergeFrom(snapshot_); snapshot_ = subBuilder.buildPartial(); } - bitField0_ |= 0x00000020; + bitField0_ |= 0x00000010; break; } } @@ -3512,28 +2807,6 @@ public org.robotninjas.barge.proto.LogProto.AppendOrBuilder getAppendOrBuilder() return append_; } - // optional .Membership membership = 3; - public static final int MEMBERSHIP_FIELD_NUMBER = 3; - private org.robotninjas.barge.proto.LogProto.Membership membership_; - /** - * optional .Membership membership = 3; - */ - public boolean hasMembership() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional .Membership membership = 3; - */ - public org.robotninjas.barge.proto.LogProto.Membership getMembership() { - return membership_; - } - /** - * optional .Membership membership = 3; - */ - public org.robotninjas.barge.proto.LogProto.MembershipOrBuilder getMembershipOrBuilder() { - return membership_; - } - // optional .Vote vote = 4; public static final int VOTE_FIELD_NUMBER = 4; private org.robotninjas.barge.proto.LogProto.Vote vote_; @@ -3541,7 +2814,7 @@ public org.robotninjas.barge.proto.LogProto.MembershipOrBuilder getMembershipOrB * optional .Vote vote = 4; */ public boolean hasVote() { - return ((bitField0_ & 0x00000004) == 0x00000004); + return ((bitField0_ & 0x00000002) == 0x00000002); } /** * optional .Vote vote = 4; @@ -3563,7 +2836,7 @@ public org.robotninjas.barge.proto.LogProto.VoteOrBuilder getVoteOrBuilder() { * optional .Term term = 5; */ public boolean hasTerm() { - return ((bitField0_ & 0x00000008) == 0x00000008); + return ((bitField0_ & 0x00000004) == 0x00000004); } /** * optional .Term term = 5; @@ -3585,7 +2858,7 @@ public org.robotninjas.barge.proto.LogProto.TermOrBuilder getTermOrBuilder() { * optional .Commit commit = 6; */ public boolean hasCommit() { - return ((bitField0_ & 0x00000010) == 0x00000010); + return ((bitField0_ & 0x00000008) == 0x00000008); } /** * optional .Commit commit = 6; @@ -3607,7 +2880,7 @@ public org.robotninjas.barge.proto.LogProto.CommitOrBuilder getCommitOrBuilder() * optional .Snapshot snapshot = 7; */ public boolean hasSnapshot() { - return ((bitField0_ & 0x00000020) == 0x00000020); + return ((bitField0_ & 0x00000010) == 0x00000010); } /** * optional .Snapshot snapshot = 7; @@ -3624,7 +2897,6 @@ public org.robotninjas.barge.proto.LogProto.SnapshotOrBuilder getSnapshotOrBuild private void initFields() { append_ = org.robotninjas.barge.proto.LogProto.Append.getDefaultInstance(); - membership_ = org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance(); vote_ = org.robotninjas.barge.proto.LogProto.Vote.getDefaultInstance(); term_ = org.robotninjas.barge.proto.LogProto.Term.getDefaultInstance(); commit_ = org.robotninjas.barge.proto.LogProto.Commit.getDefaultInstance(); @@ -3641,12 +2913,6 @@ public final boolean isInitialized() { return false; } } - if (hasMembership()) { - if (!getMembership().isInitialized()) { - memoizedIsInitialized = 0; - return false; - } - } if (hasTerm()) { if (!getTerm().isInitialized()) { memoizedIsInitialized = 0; @@ -3676,18 +2942,15 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) output.writeMessage(2, append_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { - output.writeMessage(3, membership_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeMessage(4, vote_); } - if (((bitField0_ & 0x00000008) == 0x00000008)) { + if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeMessage(5, term_); } - if (((bitField0_ & 0x00000010) == 0x00000010)) { + if (((bitField0_ & 0x00000008) == 0x00000008)) { output.writeMessage(6, commit_); } - if (((bitField0_ & 0x00000020) == 0x00000020)) { + if (((bitField0_ & 0x00000010) == 0x00000010)) { output.writeMessage(7, snapshot_); } getUnknownFields().writeTo(output); @@ -3704,22 +2967,18 @@ public int getSerializedSize() { .computeMessageSize(2, append_); } if (((bitField0_ & 0x00000002) == 0x00000002)) { - size += com.google.protobuf.CodedOutputStream - .computeMessageSize(3, membership_); - } - if (((bitField0_ & 0x00000004) == 0x00000004)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(4, vote_); } - if (((bitField0_ & 0x00000008) == 0x00000008)) { + if (((bitField0_ & 0x00000004) == 0x00000004)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(5, term_); } - if (((bitField0_ & 0x00000010) == 0x00000010)) { + if (((bitField0_ & 0x00000008) == 0x00000008)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(6, commit_); } - if (((bitField0_ & 0x00000020) == 0x00000020)) { + if (((bitField0_ & 0x00000010) == 0x00000010)) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(7, snapshot_); } @@ -3832,7 +3091,6 @@ private Builder( private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { getAppendFieldBuilder(); - getMembershipFieldBuilder(); getVoteFieldBuilder(); getTermFieldBuilder(); getCommitFieldBuilder(); @@ -3851,36 +3109,30 @@ public Builder clear() { appendBuilder_.clear(); } bitField0_ = (bitField0_ & ~0x00000001); - if (membershipBuilder_ == null) { - membership_ = org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance(); - } else { - membershipBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000002); if (voteBuilder_ == null) { vote_ = org.robotninjas.barge.proto.LogProto.Vote.getDefaultInstance(); } else { voteBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000004); + bitField0_ = (bitField0_ & ~0x00000002); if (termBuilder_ == null) { term_ = org.robotninjas.barge.proto.LogProto.Term.getDefaultInstance(); } else { termBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000008); + bitField0_ = (bitField0_ & ~0x00000004); if (commitBuilder_ == null) { commit_ = org.robotninjas.barge.proto.LogProto.Commit.getDefaultInstance(); } else { commitBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000010); + bitField0_ = (bitField0_ & ~0x00000008); if (snapshotBuilder_ == null) { snapshot_ = org.robotninjas.barge.proto.LogProto.Snapshot.getDefaultInstance(); } else { snapshotBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000020); + bitField0_ = (bitField0_ & ~0x00000010); return this; } @@ -3920,37 +3172,29 @@ public org.robotninjas.barge.proto.LogProto.JournalEntry buildPartial() { if (((from_bitField0_ & 0x00000002) == 0x00000002)) { to_bitField0_ |= 0x00000002; } - if (membershipBuilder_ == null) { - result.membership_ = membership_; - } else { - result.membership_ = membershipBuilder_.build(); - } - if (((from_bitField0_ & 0x00000004) == 0x00000004)) { - to_bitField0_ |= 0x00000004; - } if (voteBuilder_ == null) { result.vote_ = vote_; } else { result.vote_ = voteBuilder_.build(); } - if (((from_bitField0_ & 0x00000008) == 0x00000008)) { - to_bitField0_ |= 0x00000008; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; } if (termBuilder_ == null) { result.term_ = term_; } else { result.term_ = termBuilder_.build(); } - if (((from_bitField0_ & 0x00000010) == 0x00000010)) { - to_bitField0_ |= 0x00000010; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; } if (commitBuilder_ == null) { result.commit_ = commit_; } else { result.commit_ = commitBuilder_.build(); } - if (((from_bitField0_ & 0x00000020) == 0x00000020)) { - to_bitField0_ |= 0x00000020; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; } if (snapshotBuilder_ == null) { result.snapshot_ = snapshot_; @@ -3976,9 +3220,6 @@ public Builder mergeFrom(org.robotninjas.barge.proto.LogProto.JournalEntry other if (other.hasAppend()) { mergeAppend(other.getAppend()); } - if (other.hasMembership()) { - mergeMembership(other.getMembership()); - } if (other.hasVote()) { mergeVote(other.getVote()); } @@ -4002,12 +3243,6 @@ public final boolean isInitialized() { return false; } } - if (hasMembership()) { - if (!getMembership().isInitialized()) { - - return false; - } - } if (hasTerm()) { if (!getTerm().isInitialized()) { @@ -4165,123 +3400,6 @@ public org.robotninjas.barge.proto.LogProto.AppendOrBuilder getAppendOrBuilder() return appendBuilder_; } - // optional .Membership membership = 3; - private org.robotninjas.barge.proto.LogProto.Membership membership_ = org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance(); - private com.google.protobuf.SingleFieldBuilder< - org.robotninjas.barge.proto.LogProto.Membership, org.robotninjas.barge.proto.LogProto.Membership.Builder, org.robotninjas.barge.proto.LogProto.MembershipOrBuilder> membershipBuilder_; - /** - * optional .Membership membership = 3; - */ - public boolean hasMembership() { - return ((bitField0_ & 0x00000002) == 0x00000002); - } - /** - * optional .Membership membership = 3; - */ - public org.robotninjas.barge.proto.LogProto.Membership getMembership() { - if (membershipBuilder_ == null) { - return membership_; - } else { - return membershipBuilder_.getMessage(); - } - } - /** - * optional .Membership membership = 3; - */ - public Builder setMembership(org.robotninjas.barge.proto.LogProto.Membership value) { - if (membershipBuilder_ == null) { - if (value == null) { - throw new NullPointerException(); - } - membership_ = value; - onChanged(); - } else { - membershipBuilder_.setMessage(value); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .Membership membership = 3; - */ - public Builder setMembership( - org.robotninjas.barge.proto.LogProto.Membership.Builder builderForValue) { - if (membershipBuilder_ == null) { - membership_ = builderForValue.build(); - onChanged(); - } else { - membershipBuilder_.setMessage(builderForValue.build()); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .Membership membership = 3; - */ - public Builder mergeMembership(org.robotninjas.barge.proto.LogProto.Membership value) { - if (membershipBuilder_ == null) { - if (((bitField0_ & 0x00000002) == 0x00000002) && - membership_ != org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance()) { - membership_ = - org.robotninjas.barge.proto.LogProto.Membership.newBuilder(membership_).mergeFrom(value).buildPartial(); - } else { - membership_ = value; - } - onChanged(); - } else { - membershipBuilder_.mergeFrom(value); - } - bitField0_ |= 0x00000002; - return this; - } - /** - * optional .Membership membership = 3; - */ - public Builder clearMembership() { - if (membershipBuilder_ == null) { - membership_ = org.robotninjas.barge.proto.LogProto.Membership.getDefaultInstance(); - onChanged(); - } else { - membershipBuilder_.clear(); - } - bitField0_ = (bitField0_ & ~0x00000002); - return this; - } - /** - * optional .Membership membership = 3; - */ - public org.robotninjas.barge.proto.LogProto.Membership.Builder getMembershipBuilder() { - bitField0_ |= 0x00000002; - onChanged(); - return getMembershipFieldBuilder().getBuilder(); - } - /** - * optional .Membership membership = 3; - */ - public org.robotninjas.barge.proto.LogProto.MembershipOrBuilder getMembershipOrBuilder() { - if (membershipBuilder_ != null) { - return membershipBuilder_.getMessageOrBuilder(); - } else { - return membership_; - } - } - /** - * optional .Membership membership = 3; - */ - private com.google.protobuf.SingleFieldBuilder< - org.robotninjas.barge.proto.LogProto.Membership, org.robotninjas.barge.proto.LogProto.Membership.Builder, org.robotninjas.barge.proto.LogProto.MembershipOrBuilder> - getMembershipFieldBuilder() { - if (membershipBuilder_ == null) { - membershipBuilder_ = new com.google.protobuf.SingleFieldBuilder< - org.robotninjas.barge.proto.LogProto.Membership, org.robotninjas.barge.proto.LogProto.Membership.Builder, org.robotninjas.barge.proto.LogProto.MembershipOrBuilder>( - membership_, - getParentForChildren(), - isClean()); - membership_ = null; - } - return membershipBuilder_; - } - // optional .Vote vote = 4; private org.robotninjas.barge.proto.LogProto.Vote vote_ = org.robotninjas.barge.proto.LogProto.Vote.getDefaultInstance(); private com.google.protobuf.SingleFieldBuilder< @@ -4290,7 +3408,7 @@ public org.robotninjas.barge.proto.LogProto.MembershipOrBuilder getMembershipOrB * optional .Vote vote = 4; */ public boolean hasVote() { - return ((bitField0_ & 0x00000004) == 0x00000004); + return ((bitField0_ & 0x00000002) == 0x00000002); } /** * optional .Vote vote = 4; @@ -4315,7 +3433,7 @@ public Builder setVote(org.robotninjas.barge.proto.LogProto.Vote value) { } else { voteBuilder_.setMessage(value); } - bitField0_ |= 0x00000004; + bitField0_ |= 0x00000002; return this; } /** @@ -4329,7 +3447,7 @@ public Builder setVote( } else { voteBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000004; + bitField0_ |= 0x00000002; return this; } /** @@ -4337,7 +3455,7 @@ public Builder setVote( */ public Builder mergeVote(org.robotninjas.barge.proto.LogProto.Vote value) { if (voteBuilder_ == null) { - if (((bitField0_ & 0x00000004) == 0x00000004) && + if (((bitField0_ & 0x00000002) == 0x00000002) && vote_ != org.robotninjas.barge.proto.LogProto.Vote.getDefaultInstance()) { vote_ = org.robotninjas.barge.proto.LogProto.Vote.newBuilder(vote_).mergeFrom(value).buildPartial(); @@ -4348,7 +3466,7 @@ public Builder mergeVote(org.robotninjas.barge.proto.LogProto.Vote value) { } else { voteBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000004; + bitField0_ |= 0x00000002; return this; } /** @@ -4361,14 +3479,14 @@ public Builder clearVote() { } else { voteBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000004); + bitField0_ = (bitField0_ & ~0x00000002); return this; } /** * optional .Vote vote = 4; */ public org.robotninjas.barge.proto.LogProto.Vote.Builder getVoteBuilder() { - bitField0_ |= 0x00000004; + bitField0_ |= 0x00000002; onChanged(); return getVoteFieldBuilder().getBuilder(); } @@ -4407,7 +3525,7 @@ public org.robotninjas.barge.proto.LogProto.VoteOrBuilder getVoteOrBuilder() { * optional .Term term = 5; */ public boolean hasTerm() { - return ((bitField0_ & 0x00000008) == 0x00000008); + return ((bitField0_ & 0x00000004) == 0x00000004); } /** * optional .Term term = 5; @@ -4432,7 +3550,7 @@ public Builder setTerm(org.robotninjas.barge.proto.LogProto.Term value) { } else { termBuilder_.setMessage(value); } - bitField0_ |= 0x00000008; + bitField0_ |= 0x00000004; return this; } /** @@ -4446,7 +3564,7 @@ public Builder setTerm( } else { termBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000008; + bitField0_ |= 0x00000004; return this; } /** @@ -4454,7 +3572,7 @@ public Builder setTerm( */ public Builder mergeTerm(org.robotninjas.barge.proto.LogProto.Term value) { if (termBuilder_ == null) { - if (((bitField0_ & 0x00000008) == 0x00000008) && + if (((bitField0_ & 0x00000004) == 0x00000004) && term_ != org.robotninjas.barge.proto.LogProto.Term.getDefaultInstance()) { term_ = org.robotninjas.barge.proto.LogProto.Term.newBuilder(term_).mergeFrom(value).buildPartial(); @@ -4465,7 +3583,7 @@ public Builder mergeTerm(org.robotninjas.barge.proto.LogProto.Term value) { } else { termBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000008; + bitField0_ |= 0x00000004; return this; } /** @@ -4478,14 +3596,14 @@ public Builder clearTerm() { } else { termBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000008); + bitField0_ = (bitField0_ & ~0x00000004); return this; } /** * optional .Term term = 5; */ public org.robotninjas.barge.proto.LogProto.Term.Builder getTermBuilder() { - bitField0_ |= 0x00000008; + bitField0_ |= 0x00000004; onChanged(); return getTermFieldBuilder().getBuilder(); } @@ -4524,7 +3642,7 @@ public org.robotninjas.barge.proto.LogProto.TermOrBuilder getTermOrBuilder() { * optional .Commit commit = 6; */ public boolean hasCommit() { - return ((bitField0_ & 0x00000010) == 0x00000010); + return ((bitField0_ & 0x00000008) == 0x00000008); } /** * optional .Commit commit = 6; @@ -4549,7 +3667,7 @@ public Builder setCommit(org.robotninjas.barge.proto.LogProto.Commit value) { } else { commitBuilder_.setMessage(value); } - bitField0_ |= 0x00000010; + bitField0_ |= 0x00000008; return this; } /** @@ -4563,7 +3681,7 @@ public Builder setCommit( } else { commitBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000010; + bitField0_ |= 0x00000008; return this; } /** @@ -4571,7 +3689,7 @@ public Builder setCommit( */ public Builder mergeCommit(org.robotninjas.barge.proto.LogProto.Commit value) { if (commitBuilder_ == null) { - if (((bitField0_ & 0x00000010) == 0x00000010) && + if (((bitField0_ & 0x00000008) == 0x00000008) && commit_ != org.robotninjas.barge.proto.LogProto.Commit.getDefaultInstance()) { commit_ = org.robotninjas.barge.proto.LogProto.Commit.newBuilder(commit_).mergeFrom(value).buildPartial(); @@ -4582,7 +3700,7 @@ public Builder mergeCommit(org.robotninjas.barge.proto.LogProto.Commit value) { } else { commitBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000010; + bitField0_ |= 0x00000008; return this; } /** @@ -4595,14 +3713,14 @@ public Builder clearCommit() { } else { commitBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000010); + bitField0_ = (bitField0_ & ~0x00000008); return this; } /** * optional .Commit commit = 6; */ public org.robotninjas.barge.proto.LogProto.Commit.Builder getCommitBuilder() { - bitField0_ |= 0x00000010; + bitField0_ |= 0x00000008; onChanged(); return getCommitFieldBuilder().getBuilder(); } @@ -4641,7 +3759,7 @@ public org.robotninjas.barge.proto.LogProto.CommitOrBuilder getCommitOrBuilder() * optional .Snapshot snapshot = 7; */ public boolean hasSnapshot() { - return ((bitField0_ & 0x00000020) == 0x00000020); + return ((bitField0_ & 0x00000010) == 0x00000010); } /** * optional .Snapshot snapshot = 7; @@ -4666,7 +3784,7 @@ public Builder setSnapshot(org.robotninjas.barge.proto.LogProto.Snapshot value) } else { snapshotBuilder_.setMessage(value); } - bitField0_ |= 0x00000020; + bitField0_ |= 0x00000010; return this; } /** @@ -4680,7 +3798,7 @@ public Builder setSnapshot( } else { snapshotBuilder_.setMessage(builderForValue.build()); } - bitField0_ |= 0x00000020; + bitField0_ |= 0x00000010; return this; } /** @@ -4688,7 +3806,7 @@ public Builder setSnapshot( */ public Builder mergeSnapshot(org.robotninjas.barge.proto.LogProto.Snapshot value) { if (snapshotBuilder_ == null) { - if (((bitField0_ & 0x00000020) == 0x00000020) && + if (((bitField0_ & 0x00000010) == 0x00000010) && snapshot_ != org.robotninjas.barge.proto.LogProto.Snapshot.getDefaultInstance()) { snapshot_ = org.robotninjas.barge.proto.LogProto.Snapshot.newBuilder(snapshot_).mergeFrom(value).buildPartial(); @@ -4699,7 +3817,7 @@ public Builder mergeSnapshot(org.robotninjas.barge.proto.LogProto.Snapshot value } else { snapshotBuilder_.mergeFrom(value); } - bitField0_ |= 0x00000020; + bitField0_ |= 0x00000010; return this; } /** @@ -4712,14 +3830,14 @@ public Builder clearSnapshot() { } else { snapshotBuilder_.clear(); } - bitField0_ = (bitField0_ & ~0x00000020); + bitField0_ = (bitField0_ & ~0x00000010); return this; } /** * optional .Snapshot snapshot = 7; */ public org.robotninjas.barge.proto.LogProto.Snapshot.Builder getSnapshotBuilder() { - bitField0_ |= 0x00000020; + bitField0_ |= 0x00000010; onChanged(); return getSnapshotFieldBuilder().getBuilder(); } @@ -4766,11 +3884,6 @@ public org.robotninjas.barge.proto.LogProto.SnapshotOrBuilder getSnapshotOrBuild private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_Append_fieldAccessorTable; - private static com.google.protobuf.Descriptors.Descriptor - internal_static_Membership_descriptor; - private static - com.google.protobuf.GeneratedMessage.FieldAccessorTable - internal_static_Membership_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_Vote_descriptor; private static @@ -4806,18 +3919,16 @@ public org.robotninjas.barge.proto.LogProto.SnapshotOrBuilder getSnapshotOrBuild static { java.lang.String[] descriptorData = { "\n\tlog.proto\032\013entry.proto\".\n\006Append\022\r\n\005in" + - "dex\030\001 \002(\003\022\025\n\005entry\030\002 \002(\0132\006.Entry\":\n\nMemb" + - "ership\022\r\n\005index\030\001 \002(\003\022\014\n\004term\030\002 \002(\003\022\017\n\007m" + - "embers\030\003 \003(\t\"\031\n\004Vote\022\021\n\tvoted_for\030\002 \001(\t\"" + - "\024\n\004Term\022\014\n\004term\030\001 \002(\003\"\027\n\006Commit\022\r\n\005index" + - "\030\001 \002(\003\"Z\n\010Snapshot\022\033\n\023last_included_inde" + - "x\030\001 \002(\003\022\032\n\022last_included_term\030\002 \002(\003\022\025\n\rs" + - "napshot_file\030\003 \002(\t\"\250\001\n\014JournalEntry\022\027\n\006a" + - "ppend\030\002 \001(\0132\007.Append\022\037\n\nmembership\030\003 \001(\013" + - "2\013.Membership\022\023\n\004vote\030\004 \001(\0132\005.Vote\022\023\n\004te", - "rm\030\005 \001(\0132\005.Term\022\027\n\006commit\030\006 \001(\0132\007.Commit" + - "\022\033\n\010snapshot\030\007 \001(\0132\t.SnapshotB\'\n\033org.rob" + - "otninjas.barge.protoB\010LogProto" + "dex\030\001 \002(\003\022\025\n\005entry\030\002 \002(\0132\006.Entry\"\031\n\004Vote" + + "\022\021\n\tvoted_for\030\002 \001(\t\"\024\n\004Term\022\014\n\004term\030\001 \002(" + + "\003\"\027\n\006Commit\022\r\n\005index\030\001 \002(\003\"Z\n\010Snapshot\022\033" + + "\n\023last_included_index\030\001 \002(\003\022\032\n\022last_incl" + + "uded_term\030\002 \002(\003\022\025\n\rsnapshot_file\030\003 \002(\t\"\207" + + "\001\n\014JournalEntry\022\027\n\006append\030\002 \001(\0132\007.Append" + + "\022\023\n\004vote\030\004 \001(\0132\005.Vote\022\023\n\004term\030\005 \001(\0132\005.Te" + + "rm\022\027\n\006commit\030\006 \001(\0132\007.Commit\022\033\n\010snapshot\030" + + "\007 \001(\0132\t.SnapshotB\'\n\033org.robotninjas.barg", + "e.protoB\010LogProto" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -4830,42 +3941,36 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Append_descriptor, new java.lang.String[] { "Index", "Entry", }); - internal_static_Membership_descriptor = - getDescriptor().getMessageTypes().get(1); - internal_static_Membership_fieldAccessorTable = new - com.google.protobuf.GeneratedMessage.FieldAccessorTable( - internal_static_Membership_descriptor, - new java.lang.String[] { "Index", "Term", "Members", }); internal_static_Vote_descriptor = - getDescriptor().getMessageTypes().get(2); + getDescriptor().getMessageTypes().get(1); internal_static_Vote_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Vote_descriptor, new java.lang.String[] { "VotedFor", }); internal_static_Term_descriptor = - getDescriptor().getMessageTypes().get(3); + getDescriptor().getMessageTypes().get(2); internal_static_Term_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Term_descriptor, new java.lang.String[] { "Term", }); internal_static_Commit_descriptor = - getDescriptor().getMessageTypes().get(4); + getDescriptor().getMessageTypes().get(3); internal_static_Commit_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Commit_descriptor, new java.lang.String[] { "Index", }); internal_static_Snapshot_descriptor = - getDescriptor().getMessageTypes().get(5); + getDescriptor().getMessageTypes().get(4); internal_static_Snapshot_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Snapshot_descriptor, new java.lang.String[] { "LastIncludedIndex", "LastIncludedTerm", "SnapshotFile", }); internal_static_JournalEntry_descriptor = - getDescriptor().getMessageTypes().get(6); + getDescriptor().getMessageTypes().get(5); internal_static_JournalEntry_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_JournalEntry_descriptor, - new java.lang.String[] { "Append", "Membership", "Vote", "Term", "Commit", "Snapshot", }); + new java.lang.String[] { "Append", "Vote", "Term", "Commit", "Snapshot", }); return null; } }; diff --git a/barge-core/src/main/java/org/robotninjas/barge/proto/RaftEntry.java b/barge-core/src/main/java/org/robotninjas/barge/proto/RaftEntry.java index 32ae405..a9e994b 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/proto/RaftEntry.java +++ b/barge-core/src/main/java/org/robotninjas/barge/proto/RaftEntry.java @@ -8,6 +8,688 @@ private RaftEntry() {} public static void registerAllExtensions( com.google.protobuf.ExtensionRegistry registry) { } + public interface MembershipOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // repeated string members = 1; + /** + * repeated string members = 1; + */ + java.util.List + getMembersList(); + /** + * repeated string members = 1; + */ + int getMembersCount(); + /** + * repeated string members = 1; + */ + java.lang.String getMembers(int index); + /** + * repeated string members = 1; + */ + com.google.protobuf.ByteString + getMembersBytes(int index); + + // repeated string proposed_members = 2; + /** + * repeated string proposed_members = 2; + */ + java.util.List + getProposedMembersList(); + /** + * repeated string proposed_members = 2; + */ + int getProposedMembersCount(); + /** + * repeated string proposed_members = 2; + */ + java.lang.String getProposedMembers(int index); + /** + * repeated string proposed_members = 2; + */ + com.google.protobuf.ByteString + getProposedMembersBytes(int index); + } + /** + * Protobuf type {@code Membership} + */ + public static final class Membership extends + com.google.protobuf.GeneratedMessage + implements MembershipOrBuilder { + // Use Membership.newBuilder() to construct. + private Membership(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private Membership(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final Membership defaultInstance; + public static Membership getDefaultInstance() { + return defaultInstance; + } + + public Membership getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private Membership( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 10: { + if (!((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + members_ = new com.google.protobuf.LazyStringArrayList(); + mutable_bitField0_ |= 0x00000001; + } + members_.add(input.readBytes()); + break; + } + case 18: { + if (!((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + proposedMembers_ = new com.google.protobuf.LazyStringArrayList(); + mutable_bitField0_ |= 0x00000002; + } + proposedMembers_.add(input.readBytes()); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + if (((mutable_bitField0_ & 0x00000001) == 0x00000001)) { + members_ = new com.google.protobuf.UnmodifiableLazyStringList(members_); + } + if (((mutable_bitField0_ & 0x00000002) == 0x00000002)) { + proposedMembers_ = new com.google.protobuf.UnmodifiableLazyStringList(proposedMembers_); + } + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.robotninjas.barge.proto.RaftEntry.internal_static_Membership_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.robotninjas.barge.proto.RaftEntry.internal_static_Membership_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.robotninjas.barge.proto.RaftEntry.Membership.class, org.robotninjas.barge.proto.RaftEntry.Membership.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public Membership parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new Membership(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + // repeated string members = 1; + public static final int MEMBERS_FIELD_NUMBER = 1; + private com.google.protobuf.LazyStringList members_; + /** + * repeated string members = 1; + */ + public java.util.List + getMembersList() { + return members_; + } + /** + * repeated string members = 1; + */ + public int getMembersCount() { + return members_.size(); + } + /** + * repeated string members = 1; + */ + public java.lang.String getMembers(int index) { + return members_.get(index); + } + /** + * repeated string members = 1; + */ + public com.google.protobuf.ByteString + getMembersBytes(int index) { + return members_.getByteString(index); + } + + // repeated string proposed_members = 2; + public static final int PROPOSED_MEMBERS_FIELD_NUMBER = 2; + private com.google.protobuf.LazyStringList proposedMembers_; + /** + * repeated string proposed_members = 2; + */ + public java.util.List + getProposedMembersList() { + return proposedMembers_; + } + /** + * repeated string proposed_members = 2; + */ + public int getProposedMembersCount() { + return proposedMembers_.size(); + } + /** + * repeated string proposed_members = 2; + */ + public java.lang.String getProposedMembers(int index) { + return proposedMembers_.get(index); + } + /** + * repeated string proposed_members = 2; + */ + public com.google.protobuf.ByteString + getProposedMembersBytes(int index) { + return proposedMembers_.getByteString(index); + } + + private void initFields() { + members_ = com.google.protobuf.LazyStringArrayList.EMPTY; + proposedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + for (int i = 0; i < members_.size(); i++) { + output.writeBytes(1, members_.getByteString(i)); + } + for (int i = 0; i < proposedMembers_.size(); i++) { + output.writeBytes(2, proposedMembers_.getByteString(i)); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + { + int dataSize = 0; + for (int i = 0; i < members_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(members_.getByteString(i)); + } + size += dataSize; + size += 1 * getMembersList().size(); + } + { + int dataSize = 0; + for (int i = 0; i < proposedMembers_.size(); i++) { + dataSize += com.google.protobuf.CodedOutputStream + .computeBytesSizeNoTag(proposedMembers_.getByteString(i)); + } + size += dataSize; + size += 1 * getProposedMembersList().size(); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.robotninjas.barge.proto.RaftEntry.Membership parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.robotninjas.barge.proto.RaftEntry.Membership prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code Membership} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.robotninjas.barge.proto.RaftEntry.internal_static_Membership_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.robotninjas.barge.proto.RaftEntry.internal_static_Membership_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.robotninjas.barge.proto.RaftEntry.Membership.class, org.robotninjas.barge.proto.RaftEntry.Membership.Builder.class); + } + + // Construct using org.robotninjas.barge.proto.RaftEntry.Membership.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + members_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000001); + proposedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.robotninjas.barge.proto.RaftEntry.internal_static_Membership_descriptor; + } + + public org.robotninjas.barge.proto.RaftEntry.Membership getDefaultInstanceForType() { + return org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance(); + } + + public org.robotninjas.barge.proto.RaftEntry.Membership build() { + org.robotninjas.barge.proto.RaftEntry.Membership result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.robotninjas.barge.proto.RaftEntry.Membership buildPartial() { + org.robotninjas.barge.proto.RaftEntry.Membership result = new org.robotninjas.barge.proto.RaftEntry.Membership(this); + int from_bitField0_ = bitField0_; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + members_ = new com.google.protobuf.UnmodifiableLazyStringList( + members_); + bitField0_ = (bitField0_ & ~0x00000001); + } + result.members_ = members_; + if (((bitField0_ & 0x00000002) == 0x00000002)) { + proposedMembers_ = new com.google.protobuf.UnmodifiableLazyStringList( + proposedMembers_); + bitField0_ = (bitField0_ & ~0x00000002); + } + result.proposedMembers_ = proposedMembers_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.robotninjas.barge.proto.RaftEntry.Membership) { + return mergeFrom((org.robotninjas.barge.proto.RaftEntry.Membership)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.robotninjas.barge.proto.RaftEntry.Membership other) { + if (other == org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance()) return this; + if (!other.members_.isEmpty()) { + if (members_.isEmpty()) { + members_ = other.members_; + bitField0_ = (bitField0_ & ~0x00000001); + } else { + ensureMembersIsMutable(); + members_.addAll(other.members_); + } + onChanged(); + } + if (!other.proposedMembers_.isEmpty()) { + if (proposedMembers_.isEmpty()) { + proposedMembers_ = other.proposedMembers_; + bitField0_ = (bitField0_ & ~0x00000002); + } else { + ensureProposedMembersIsMutable(); + proposedMembers_.addAll(other.proposedMembers_); + } + onChanged(); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.robotninjas.barge.proto.RaftEntry.Membership parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.robotninjas.barge.proto.RaftEntry.Membership) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // repeated string members = 1; + private com.google.protobuf.LazyStringList members_ = com.google.protobuf.LazyStringArrayList.EMPTY; + private void ensureMembersIsMutable() { + if (!((bitField0_ & 0x00000001) == 0x00000001)) { + members_ = new com.google.protobuf.LazyStringArrayList(members_); + bitField0_ |= 0x00000001; + } + } + /** + * repeated string members = 1; + */ + public java.util.List + getMembersList() { + return java.util.Collections.unmodifiableList(members_); + } + /** + * repeated string members = 1; + */ + public int getMembersCount() { + return members_.size(); + } + /** + * repeated string members = 1; + */ + public java.lang.String getMembers(int index) { + return members_.get(index); + } + /** + * repeated string members = 1; + */ + public com.google.protobuf.ByteString + getMembersBytes(int index) { + return members_.getByteString(index); + } + /** + * repeated string members = 1; + */ + public Builder setMembers( + int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.set(index, value); + onChanged(); + return this; + } + /** + * repeated string members = 1; + */ + public Builder addMembers( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.add(value); + onChanged(); + return this; + } + /** + * repeated string members = 1; + */ + public Builder addAllMembers( + java.lang.Iterable values) { + ensureMembersIsMutable(); + super.addAll(values, members_); + onChanged(); + return this; + } + /** + * repeated string members = 1; + */ + public Builder clearMembers() { + members_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000001); + onChanged(); + return this; + } + /** + * repeated string members = 1; + */ + public Builder addMembersBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureMembersIsMutable(); + members_.add(value); + onChanged(); + return this; + } + + // repeated string proposed_members = 2; + private com.google.protobuf.LazyStringList proposedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + private void ensureProposedMembersIsMutable() { + if (!((bitField0_ & 0x00000002) == 0x00000002)) { + proposedMembers_ = new com.google.protobuf.LazyStringArrayList(proposedMembers_); + bitField0_ |= 0x00000002; + } + } + /** + * repeated string proposed_members = 2; + */ + public java.util.List + getProposedMembersList() { + return java.util.Collections.unmodifiableList(proposedMembers_); + } + /** + * repeated string proposed_members = 2; + */ + public int getProposedMembersCount() { + return proposedMembers_.size(); + } + /** + * repeated string proposed_members = 2; + */ + public java.lang.String getProposedMembers(int index) { + return proposedMembers_.get(index); + } + /** + * repeated string proposed_members = 2; + */ + public com.google.protobuf.ByteString + getProposedMembersBytes(int index) { + return proposedMembers_.getByteString(index); + } + /** + * repeated string proposed_members = 2; + */ + public Builder setProposedMembers( + int index, java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureProposedMembersIsMutable(); + proposedMembers_.set(index, value); + onChanged(); + return this; + } + /** + * repeated string proposed_members = 2; + */ + public Builder addProposedMembers( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + ensureProposedMembersIsMutable(); + proposedMembers_.add(value); + onChanged(); + return this; + } + /** + * repeated string proposed_members = 2; + */ + public Builder addAllProposedMembers( + java.lang.Iterable values) { + ensureProposedMembersIsMutable(); + super.addAll(values, proposedMembers_); + onChanged(); + return this; + } + /** + * repeated string proposed_members = 2; + */ + public Builder clearProposedMembers() { + proposedMembers_ = com.google.protobuf.LazyStringArrayList.EMPTY; + bitField0_ = (bitField0_ & ~0x00000002); + onChanged(); + return this; + } + /** + * repeated string proposed_members = 2; + */ + public Builder addProposedMembersBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + ensureProposedMembersIsMutable(); + proposedMembers_.add(value); + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:Membership) + } + + static { + defaultInstance = new Membership(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:Membership) + } + public interface EntryOrBuilder extends com.google.protobuf.MessageOrBuilder { @@ -21,15 +703,29 @@ public interface EntryOrBuilder */ long getTerm(); - // required bytes command = 2; + // optional bytes command = 2; /** - * required bytes command = 2; + * optional bytes command = 2; */ boolean hasCommand(); /** - * required bytes command = 2; + * optional bytes command = 2; */ com.google.protobuf.ByteString getCommand(); + + // optional .Membership membership = 3; + /** + * optional .Membership membership = 3; + */ + boolean hasMembership(); + /** + * optional .Membership membership = 3; + */ + org.robotninjas.barge.proto.RaftEntry.Membership getMembership(); + /** + * optional .Membership membership = 3; + */ + org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder getMembershipOrBuilder(); } /** * Protobuf type {@code Entry} @@ -92,6 +788,19 @@ private Entry( command_ = input.readBytes(); break; } + case 26: { + org.robotninjas.barge.proto.RaftEntry.Membership.Builder subBuilder = null; + if (((bitField0_ & 0x00000004) == 0x00000004)) { + subBuilder = membership_.toBuilder(); + } + membership_ = input.readMessage(org.robotninjas.barge.proto.RaftEntry.Membership.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(membership_); + membership_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000004; + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -148,25 +857,48 @@ public long getTerm() { return term_; } - // required bytes command = 2; + // optional bytes command = 2; public static final int COMMAND_FIELD_NUMBER = 2; private com.google.protobuf.ByteString command_; /** - * required bytes command = 2; + * optional bytes command = 2; */ public boolean hasCommand() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** - * required bytes command = 2; + * optional bytes command = 2; */ public com.google.protobuf.ByteString getCommand() { return command_; } + // optional .Membership membership = 3; + public static final int MEMBERSHIP_FIELD_NUMBER = 3; + private org.robotninjas.barge.proto.RaftEntry.Membership membership_; + /** + * optional .Membership membership = 3; + */ + public boolean hasMembership() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .Membership membership = 3; + */ + public org.robotninjas.barge.proto.RaftEntry.Membership getMembership() { + return membership_; + } + /** + * optional .Membership membership = 3; + */ + public org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder getMembershipOrBuilder() { + return membership_; + } + private void initFields() { term_ = 0L; command_ = com.google.protobuf.ByteString.EMPTY; + membership_ = org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -177,10 +909,6 @@ public final boolean isInitialized() { memoizedIsInitialized = 0; return false; } - if (!hasCommand()) { - memoizedIsInitialized = 0; - return false; - } memoizedIsInitialized = 1; return true; } @@ -194,6 +922,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000002) == 0x00000002)) { output.writeBytes(2, command_); } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeMessage(3, membership_); + } getUnknownFields().writeTo(output); } @@ -211,6 +942,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeBytesSize(2, command_); } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, membership_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -319,6 +1054,7 @@ private Builder( } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getMembershipFieldBuilder(); } } private static Builder create() { @@ -331,6 +1067,12 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x00000001); command_ = com.google.protobuf.ByteString.EMPTY; bitField0_ = (bitField0_ & ~0x00000002); + if (membershipBuilder_ == null) { + membership_ = org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance(); + } else { + membershipBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); return this; } @@ -367,6 +1109,14 @@ public org.robotninjas.barge.proto.RaftEntry.Entry buildPartial() { to_bitField0_ |= 0x00000002; } result.command_ = command_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + if (membershipBuilder_ == null) { + result.membership_ = membership_; + } else { + result.membership_ = membershipBuilder_.build(); + } result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -389,6 +1139,9 @@ public Builder mergeFrom(org.robotninjas.barge.proto.RaftEntry.Entry other) { if (other.hasCommand()) { setCommand(other.getCommand()); } + if (other.hasMembership()) { + mergeMembership(other.getMembership()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -398,10 +1151,6 @@ public final boolean isInitialized() { return false; } - if (!hasCommand()) { - - return false; - } return true; } @@ -457,22 +1206,22 @@ public Builder clearTerm() { return this; } - // required bytes command = 2; + // optional bytes command = 2; private com.google.protobuf.ByteString command_ = com.google.protobuf.ByteString.EMPTY; /** - * required bytes command = 2; + * optional bytes command = 2; */ public boolean hasCommand() { return ((bitField0_ & 0x00000002) == 0x00000002); } /** - * required bytes command = 2; + * optional bytes command = 2; */ public com.google.protobuf.ByteString getCommand() { return command_; } /** - * required bytes command = 2; + * optional bytes command = 2; */ public Builder setCommand(com.google.protobuf.ByteString value) { if (value == null) { @@ -484,7 +1233,7 @@ public Builder setCommand(com.google.protobuf.ByteString value) { return this; } /** - * required bytes command = 2; + * optional bytes command = 2; */ public Builder clearCommand() { bitField0_ = (bitField0_ & ~0x00000002); @@ -493,6 +1242,123 @@ public Builder clearCommand() { return this; } + // optional .Membership membership = 3; + private org.robotninjas.barge.proto.RaftEntry.Membership membership_ = org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftEntry.Membership, org.robotninjas.barge.proto.RaftEntry.Membership.Builder, org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder> membershipBuilder_; + /** + * optional .Membership membership = 3; + */ + public boolean hasMembership() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * optional .Membership membership = 3; + */ + public org.robotninjas.barge.proto.RaftEntry.Membership getMembership() { + if (membershipBuilder_ == null) { + return membership_; + } else { + return membershipBuilder_.getMessage(); + } + } + /** + * optional .Membership membership = 3; + */ + public Builder setMembership(org.robotninjas.barge.proto.RaftEntry.Membership value) { + if (membershipBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + membership_ = value; + onChanged(); + } else { + membershipBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .Membership membership = 3; + */ + public Builder setMembership( + org.robotninjas.barge.proto.RaftEntry.Membership.Builder builderForValue) { + if (membershipBuilder_ == null) { + membership_ = builderForValue.build(); + onChanged(); + } else { + membershipBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .Membership membership = 3; + */ + public Builder mergeMembership(org.robotninjas.barge.proto.RaftEntry.Membership value) { + if (membershipBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004) && + membership_ != org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance()) { + membership_ = + org.robotninjas.barge.proto.RaftEntry.Membership.newBuilder(membership_).mergeFrom(value).buildPartial(); + } else { + membership_ = value; + } + onChanged(); + } else { + membershipBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000004; + return this; + } + /** + * optional .Membership membership = 3; + */ + public Builder clearMembership() { + if (membershipBuilder_ == null) { + membership_ = org.robotninjas.barge.proto.RaftEntry.Membership.getDefaultInstance(); + onChanged(); + } else { + membershipBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + /** + * optional .Membership membership = 3; + */ + public org.robotninjas.barge.proto.RaftEntry.Membership.Builder getMembershipBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return getMembershipFieldBuilder().getBuilder(); + } + /** + * optional .Membership membership = 3; + */ + public org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder getMembershipOrBuilder() { + if (membershipBuilder_ != null) { + return membershipBuilder_.getMessageOrBuilder(); + } else { + return membership_; + } + } + /** + * optional .Membership membership = 3; + */ + private com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftEntry.Membership, org.robotninjas.barge.proto.RaftEntry.Membership.Builder, org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder> + getMembershipFieldBuilder() { + if (membershipBuilder_ == null) { + membershipBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftEntry.Membership, org.robotninjas.barge.proto.RaftEntry.Membership.Builder, org.robotninjas.barge.proto.RaftEntry.MembershipOrBuilder>( + membership_, + getParentForChildren(), + isClean()); + membership_ = null; + } + return membershipBuilder_; + } + // @@protoc_insertion_point(builder_scope:Entry) } @@ -504,6 +1370,11 @@ public Builder clearCommand() { // @@protoc_insertion_point(class_scope:Entry) } + private static com.google.protobuf.Descriptors.Descriptor + internal_static_Membership_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_Membership_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_Entry_descriptor; private static @@ -518,21 +1389,29 @@ public Builder clearCommand() { descriptor; static { java.lang.String[] descriptorData = { - "\n\013entry.proto\"&\n\005Entry\022\014\n\004term\030\001 \002(\003\022\017\n\007" + - "command\030\002 \002(\014B(\n\033org.robotninjas.barge.p" + - "rotoB\tRaftEntry" + "\n\013entry.proto\"7\n\nMembership\022\017\n\007members\030\001" + + " \003(\t\022\030\n\020proposed_members\030\002 \003(\t\"G\n\005Entry\022" + + "\014\n\004term\030\001 \002(\003\022\017\n\007command\030\002 \001(\014\022\037\n\nmember" + + "ship\030\003 \001(\0132\013.MembershipB(\n\033org.robotninj" + + "as.barge.protoB\tRaftEntry" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { public com.google.protobuf.ExtensionRegistry assignDescriptors( com.google.protobuf.Descriptors.FileDescriptor root) { descriptor = root; - internal_static_Entry_descriptor = + internal_static_Membership_descriptor = getDescriptor().getMessageTypes().get(0); + internal_static_Membership_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_Membership_descriptor, + new java.lang.String[] { "Members", "ProposedMembers", }); + internal_static_Entry_descriptor = + getDescriptor().getMessageTypes().get(1); internal_static_Entry_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_Entry_descriptor, - new java.lang.String[] { "Term", "Command", }); + new java.lang.String[] { "Term", "Command", "Membership", }); return null; } }; diff --git a/barge-core/src/main/java/org/robotninjas/barge/proto/RaftProto.java b/barge-core/src/main/java/org/robotninjas/barge/proto/RaftProto.java index d65d0a2..efa9c2c 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/proto/RaftProto.java +++ b/barge-core/src/main/java/org/robotninjas/barge/proto/RaftProto.java @@ -2488,6 +2488,20 @@ public interface AppendEntriesResponseOrBuilder * optional int64 last_log_index = 3; */ long getLastLogIndex(); + + // optional .AppendEntriesResponse.TermInfo term_info = 4; + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + boolean hasTermInfo(); + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo getTermInfo(); + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder getTermInfoOrBuilder(); } /** * Protobuf type {@code AppendEntriesResponse} @@ -2555,6 +2569,19 @@ private AppendEntriesResponse( lastLogIndex_ = input.readInt64(); break; } + case 34: { + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder subBuilder = null; + if (((bitField0_ & 0x00000008) == 0x00000008)) { + subBuilder = termInfo_.toBuilder(); + } + termInfo_ = input.readMessage(org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(termInfo_); + termInfo_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000008; + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -2594,6 +2621,588 @@ public com.google.protobuf.Parser getParserForType() { return PARSER; } + public interface TermInfoOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required int64 term = 1; + /** + * required int64 term = 1; + */ + boolean hasTerm(); + /** + * required int64 term = 1; + */ + long getTerm(); + + // required int64 begin_index = 2; + /** + * required int64 begin_index = 2; + */ + boolean hasBeginIndex(); + /** + * required int64 begin_index = 2; + */ + long getBeginIndex(); + + // required int64 end_index = 3; + /** + * required int64 end_index = 3; + */ + boolean hasEndIndex(); + /** + * required int64 end_index = 3; + */ + long getEndIndex(); + } + /** + * Protobuf type {@code AppendEntriesResponse.TermInfo} + */ + public static final class TermInfo extends + com.google.protobuf.GeneratedMessage + implements TermInfoOrBuilder { + // Use TermInfo.newBuilder() to construct. + private TermInfo(com.google.protobuf.GeneratedMessage.Builder builder) { + super(builder); + this.unknownFields = builder.getUnknownFields(); + } + private TermInfo(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); } + + private static final TermInfo defaultInstance; + public static TermInfo getDefaultInstance() { + return defaultInstance; + } + + public TermInfo getDefaultInstanceForType() { + return defaultInstance; + } + + private final com.google.protobuf.UnknownFieldSet unknownFields; + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private TermInfo( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + initFields(); + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + done = true; + } + break; + } + case 8: { + bitField0_ |= 0x00000001; + term_ = input.readInt64(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + beginIndex_ = input.readInt64(); + break; + } + case 24: { + bitField0_ |= 0x00000004; + endIndex_ = input.readInt64(); + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e.getMessage()).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.robotninjas.barge.proto.RaftProto.internal_static_AppendEntriesResponse_TermInfo_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.robotninjas.barge.proto.RaftProto.internal_static_AppendEntriesResponse_TermInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.class, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder.class); + } + + public static com.google.protobuf.Parser PARSER = + new com.google.protobuf.AbstractParser() { + public TermInfo parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new TermInfo(input, extensionRegistry); + } + }; + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + private int bitField0_; + // required int64 term = 1; + public static final int TERM_FIELD_NUMBER = 1; + private long term_; + /** + * required int64 term = 1; + */ + public boolean hasTerm() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required int64 term = 1; + */ + public long getTerm() { + return term_; + } + + // required int64 begin_index = 2; + public static final int BEGIN_INDEX_FIELD_NUMBER = 2; + private long beginIndex_; + /** + * required int64 begin_index = 2; + */ + public boolean hasBeginIndex() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required int64 begin_index = 2; + */ + public long getBeginIndex() { + return beginIndex_; + } + + // required int64 end_index = 3; + public static final int END_INDEX_FIELD_NUMBER = 3; + private long endIndex_; + /** + * required int64 end_index = 3; + */ + public boolean hasEndIndex() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required int64 end_index = 3; + */ + public long getEndIndex() { + return endIndex_; + } + + private void initFields() { + term_ = 0L; + beginIndex_ = 0L; + endIndex_ = 0L; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasTerm()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasBeginIndex()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasEndIndex()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeInt64(1, term_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeInt64(2, beginIndex_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeInt64(3, endIndex_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(1, term_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(2, beginIndex_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeInt64Size(3, endIndex_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseDelimitedFrom(input, extensionRegistry); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return PARSER.parseFrom(input); + } + public static org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return PARSER.parseFrom(input, extensionRegistry); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code AppendEntriesResponse.TermInfo} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.robotninjas.barge.proto.RaftProto.internal_static_AppendEntriesResponse_TermInfo_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.robotninjas.barge.proto.RaftProto.internal_static_AppendEntriesResponse_TermInfo_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.class, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder.class); + } + + // Construct using org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + term_ = 0L; + bitField0_ = (bitField0_ & ~0x00000001); + beginIndex_ = 0L; + bitField0_ = (bitField0_ & ~0x00000002); + endIndex_ = 0L; + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.robotninjas.barge.proto.RaftProto.internal_static_AppendEntriesResponse_TermInfo_descriptor; + } + + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo getDefaultInstanceForType() { + return org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance(); + } + + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo build() { + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo buildPartial() { + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo result = new org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.term_ = term_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.beginIndex_ = beginIndex_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.endIndex_ = endIndex_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo) { + return mergeFrom((org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo other) { + if (other == org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance()) return this; + if (other.hasTerm()) { + setTerm(other.getTerm()); + } + if (other.hasBeginIndex()) { + setBeginIndex(other.getBeginIndex()); + } + if (other.hasEndIndex()) { + setEndIndex(other.getEndIndex()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasTerm()) { + + return false; + } + if (!hasBeginIndex()) { + + return false; + } + if (!hasEndIndex()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo) e.getUnfinishedMessage(); + throw e; + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + private int bitField0_; + + // required int64 term = 1; + private long term_ ; + /** + * required int64 term = 1; + */ + public boolean hasTerm() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + /** + * required int64 term = 1; + */ + public long getTerm() { + return term_; + } + /** + * required int64 term = 1; + */ + public Builder setTerm(long value) { + bitField0_ |= 0x00000001; + term_ = value; + onChanged(); + return this; + } + /** + * required int64 term = 1; + */ + public Builder clearTerm() { + bitField0_ = (bitField0_ & ~0x00000001); + term_ = 0L; + onChanged(); + return this; + } + + // required int64 begin_index = 2; + private long beginIndex_ ; + /** + * required int64 begin_index = 2; + */ + public boolean hasBeginIndex() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + /** + * required int64 begin_index = 2; + */ + public long getBeginIndex() { + return beginIndex_; + } + /** + * required int64 begin_index = 2; + */ + public Builder setBeginIndex(long value) { + bitField0_ |= 0x00000002; + beginIndex_ = value; + onChanged(); + return this; + } + /** + * required int64 begin_index = 2; + */ + public Builder clearBeginIndex() { + bitField0_ = (bitField0_ & ~0x00000002); + beginIndex_ = 0L; + onChanged(); + return this; + } + + // required int64 end_index = 3; + private long endIndex_ ; + /** + * required int64 end_index = 3; + */ + public boolean hasEndIndex() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + /** + * required int64 end_index = 3; + */ + public long getEndIndex() { + return endIndex_; + } + /** + * required int64 end_index = 3; + */ + public Builder setEndIndex(long value) { + bitField0_ |= 0x00000004; + endIndex_ = value; + onChanged(); + return this; + } + /** + * required int64 end_index = 3; + */ + public Builder clearEndIndex() { + bitField0_ = (bitField0_ & ~0x00000004); + endIndex_ = 0L; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:AppendEntriesResponse.TermInfo) + } + + static { + defaultInstance = new TermInfo(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:AppendEntriesResponse.TermInfo) + } + private int bitField0_; // required int64 term = 1; public static final int TERM_FIELD_NUMBER = 1; @@ -2643,10 +3252,33 @@ public long getLastLogIndex() { return lastLogIndex_; } + // optional .AppendEntriesResponse.TermInfo term_info = 4; + public static final int TERM_INFO_FIELD_NUMBER = 4; + private org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo termInfo_; + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public boolean hasTermInfo() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo getTermInfo() { + return termInfo_; + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder getTermInfoOrBuilder() { + return termInfo_; + } + private void initFields() { term_ = 0L; success_ = false; lastLogIndex_ = 0L; + termInfo_ = org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -2661,6 +3293,12 @@ public final boolean isInitialized() { memoizedIsInitialized = 0; return false; } + if (hasTermInfo()) { + if (!getTermInfo().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } memoizedIsInitialized = 1; return true; } @@ -2677,6 +3315,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000004) == 0x00000004)) { output.writeInt64(3, lastLogIndex_); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeMessage(4, termInfo_); + } getUnknownFields().writeTo(output); } @@ -2698,6 +3339,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeInt64Size(3, lastLogIndex_); } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(4, termInfo_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -2806,6 +3451,7 @@ private Builder( } private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getTermInfoFieldBuilder(); } } private static Builder create() { @@ -2820,6 +3466,12 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x00000002); lastLogIndex_ = 0L; bitField0_ = (bitField0_ & ~0x00000004); + if (termInfoBuilder_ == null) { + termInfo_ = org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance(); + } else { + termInfoBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); return this; } @@ -2860,6 +3512,14 @@ public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse buildPartial( to_bitField0_ |= 0x00000004; } result.lastLogIndex_ = lastLogIndex_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + if (termInfoBuilder_ == null) { + result.termInfo_ = termInfo_; + } else { + result.termInfo_ = termInfoBuilder_.build(); + } result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -2885,6 +3545,9 @@ public Builder mergeFrom(org.robotninjas.barge.proto.RaftProto.AppendEntriesResp if (other.hasLastLogIndex()) { setLastLogIndex(other.getLastLogIndex()); } + if (other.hasTermInfo()) { + mergeTermInfo(other.getTermInfo()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -2898,6 +3561,12 @@ public final boolean isInitialized() { return false; } + if (hasTermInfo()) { + if (!getTermInfo().isInitialized()) { + + return false; + } + } return true; } @@ -3019,6 +3688,123 @@ public Builder clearLastLogIndex() { return this; } + // optional .AppendEntriesResponse.TermInfo term_info = 4; + private org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo termInfo_ = org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder> termInfoBuilder_; + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public boolean hasTermInfo() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo getTermInfo() { + if (termInfoBuilder_ == null) { + return termInfo_; + } else { + return termInfoBuilder_.getMessage(); + } + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public Builder setTermInfo(org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo value) { + if (termInfoBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + termInfo_ = value; + onChanged(); + } else { + termInfoBuilder_.setMessage(value); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public Builder setTermInfo( + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder builderForValue) { + if (termInfoBuilder_ == null) { + termInfo_ = builderForValue.build(); + onChanged(); + } else { + termInfoBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public Builder mergeTermInfo(org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo value) { + if (termInfoBuilder_ == null) { + if (((bitField0_ & 0x00000008) == 0x00000008) && + termInfo_ != org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance()) { + termInfo_ = + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.newBuilder(termInfo_).mergeFrom(value).buildPartial(); + } else { + termInfo_ = value; + } + onChanged(); + } else { + termInfoBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000008; + return this; + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public Builder clearTermInfo() { + if (termInfoBuilder_ == null) { + termInfo_ = org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.getDefaultInstance(); + onChanged(); + } else { + termInfoBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder getTermInfoBuilder() { + bitField0_ |= 0x00000008; + onChanged(); + return getTermInfoFieldBuilder().getBuilder(); + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder getTermInfoOrBuilder() { + if (termInfoBuilder_ != null) { + return termInfoBuilder_.getMessageOrBuilder(); + } else { + return termInfo_; + } + } + /** + * optional .AppendEntriesResponse.TermInfo term_info = 4; + */ + private com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder> + getTermInfoFieldBuilder() { + if (termInfoBuilder_ == null) { + termInfoBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfo.Builder, org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse.TermInfoOrBuilder>( + termInfo_, + getParentForChildren(), + isClean()); + termInfo_ = null; + } + return termInfoBuilder_; + } + // @@protoc_insertion_point(builder_scope:AppendEntriesResponse) } @@ -4520,6 +5306,11 @@ public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse appendEntries private static com.google.protobuf.GeneratedMessage.FieldAccessorTable internal_static_AppendEntriesResponse_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_AppendEntriesResponse_TermInfo_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_AppendEntriesResponse_TermInfo_fieldAccessorTable; private static com.google.protobuf.Descriptors.Descriptor internal_static_InstallSnapshot_descriptor; private static @@ -4547,17 +5338,20 @@ public org.robotninjas.barge.proto.RaftProto.AppendEntriesResponse appendEntries "\022\014\n\004term\030\001 \002(\003\022\021\n\tleader_id\030\002 \002(\t\022\026\n\016pre" + "v_log_index\030\003 \002(\003\022\025\n\rprev_log_term\030\004 \002(\003" + "\022\024\n\014commit_index\030\005 \002(\003\022\027\n\007entries\030\006 \003(\0132" + - "\006.Entry\"N\n\025AppendEntriesResponse\022\014\n\004term" + - "\030\001 \002(\003\022\017\n\007success\030\002 \002(\010\022\026\n\016last_log_inde", - "x\030\003 \001(\003\"o\n\017InstallSnapshot\022\014\n\004term\030\001 \002(\003" + - "\022\033\n\023last_included_index\030\002 \002(\003\022\032\n\022last_in" + - "cluded_term\030\003 \002(\003\022\025\n\rsnapshot_data\030\004 \002(\014" + - "\"8\n\027InstallSnapshotResponse\022\014\n\004term\030\001 \002(" + - "\003\022\017\n\007success\030\002 \002(\0102y\n\013RaftService\0221\n\013req" + - "uestVote\022\014.RequestVote\032\024.RequestVoteResp" + - "onse\0227\n\rappendEntries\022\016.AppendEntries\032\026." + - "AppendEntriesResponseB+\n\033org.robotninjas" + - ".barge.protoB\tRaftProto\210\001\001" + "\006.Entry\"\304\001\n\025AppendEntriesResponse\022\014\n\004ter" + + "m\030\001 \002(\003\022\017\n\007success\030\002 \002(\010\022\026\n\016last_log_ind", + "ex\030\003 \001(\003\0222\n\tterm_info\030\004 \001(\0132\037.AppendEntr" + + "iesResponse.TermInfo\032@\n\010TermInfo\022\014\n\004term" + + "\030\001 \002(\003\022\023\n\013begin_index\030\002 \002(\003\022\021\n\tend_index" + + "\030\003 \002(\003\"o\n\017InstallSnapshot\022\014\n\004term\030\001 \002(\003\022" + + "\033\n\023last_included_index\030\002 \002(\003\022\032\n\022last_inc" + + "luded_term\030\003 \002(\003\022\025\n\rsnapshot_data\030\004 \002(\014\"" + + "8\n\027InstallSnapshotResponse\022\014\n\004term\030\001 \002(\003" + + "\022\017\n\007success\030\002 \002(\0102y\n\013RaftService\0221\n\013requ" + + "estVote\022\014.RequestVote\032\024.RequestVoteRespo" + + "nse\0227\n\rappendEntries\022\016.AppendEntries\032\026.A", + "ppendEntriesResponseB+\n\033org.robotninjas." + + "barge.protoB\tRaftProto\210\001\001" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { @@ -4587,7 +5381,13 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_AppendEntriesResponse_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_AppendEntriesResponse_descriptor, - new java.lang.String[] { "Term", "Success", "LastLogIndex", }); + new java.lang.String[] { "Term", "Success", "LastLogIndex", "TermInfo", }); + internal_static_AppendEntriesResponse_TermInfo_descriptor = + internal_static_AppendEntriesResponse_descriptor.getNestedTypes().get(0); + internal_static_AppendEntriesResponse_TermInfo_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_AppendEntriesResponse_TermInfo_descriptor, + new java.lang.String[] { "Term", "BeginIndex", "EndIndex", }); internal_static_InstallSnapshot_descriptor = getDescriptor().getMessageTypes().get(4); internal_static_InstallSnapshot_fieldAccessorTable = new diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java b/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java index 8f3220b..816b758 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/BaseState.java @@ -2,8 +2,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; -import com.google.common.util.concurrent.ListenableFuture; -import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; @@ -33,11 +31,4 @@ boolean shouldVoteFor(@Nonnull RaftLog log, @Nonnull RequestVote request) { } - @Nonnull - public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException { - throw throwMustBeLeader(); - } - - protected abstract RuntimeException throwMustBeLeader() throws RaftException; - } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index 1612da6..d1af018 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -26,6 +26,7 @@ import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.rpc.Client; import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; @@ -177,16 +178,18 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ @VisibleForTesting List> sendRequests(RaftStateContext ctx) { + ConfigurationState configurationState = ctx.getConfigurationState(); + RequestVote request = RequestVote.newBuilder() .setTerm(log.currentTerm()) - .setCandidateId(log.self().toString()) + .setCandidateId(configurationState.self().toString()) .setLastLogIndex(log.lastLogIndex()) .setLastLogTerm(log.lastLogTerm()) .build(); List> responses = Lists.newArrayList(); - for (Replica replica : log.members()) { + for (Replica replica : configurationState.remote()) { ListenableFuture response = client.requestVote(replica, request); Futures.addCallback(response, checkTerm(ctx)); responses.add(response); @@ -210,4 +213,10 @@ public void onFailure(Throwable t) {} }; } + @Override + public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) + throws RaftException { + throw new NoLeaderException(); + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java new file mode 100644 index 0000000..68d00c6 --- /dev/null +++ b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java @@ -0,0 +1,110 @@ +package org.robotninjas.barge.state; + +import static com.google.common.base.Preconditions.*; + +import java.util.List; +import java.util.Set; + +import javax.annotation.Nonnull; + +import org.robotninjas.barge.Replica; +import org.robotninjas.barge.proto.RaftEntry.Entry; +import org.robotninjas.barge.proto.RaftEntry.Membership; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class ConfigurationState { + + State state; + + long membershipIndex; + Membership membership; + + final Replica local; + ImmutableList remote; + + final String localKey; + + public ConfigurationState(Replica self) { + this.local = self; + this.localKey = self.getKey(); + setMembership(0, Membership.getDefaultInstance()); + } + + public long getId() { + return membershipIndex; + } + + enum State { + STABLE, TRANSITIONAL + } + + @Nonnull + public Replica self() { + return local; + } + + @Nonnull + public List remote() { + return remote; + } + + public boolean hasVote(Replica r) { + String key = r.getKey(); + + if (membership.getMembersList().contains(key)) { + return true; + } + + if (state == State.TRANSITIONAL) { + if (membership.getProposedMembersList().contains(key)) { + return true; + } + } + + return false; + } + + public void add(long index, Entry entry) { + checkArgument(entry.hasMembership()); + + if (membership == null || index > membershipIndex) { + setMembership(index, entry.getMembership()); + } + } + + private void setMembership(long index, Membership membership) { + boolean transitional = membership.getProposedMembersCount() != 0; + + Set replicaKeys = Sets.newHashSet(); + replicaKeys.addAll(membership.getMembersList()); + if (transitional) { + replicaKeys.addAll(membership.getProposedMembersList()); + } + + List remotes = Lists.newArrayList(); + for (String replicaKey : replicaKeys) { + Replica replica = Replica.fromString(replicaKey); + if (replicaKey.equals(localKey)) { + continue; + } + + remotes.add(replica); + } + + this.remote = ImmutableList.copyOf(remotes); + this.membership = membership; + this.membershipIndex = index; + this.state = transitional ? State.TRANSITIONAL : State.STABLE; + } + + public Membership getMembership() { + return membership; + } + + public boolean isTransitional() { + return state == State.TRANSITIONAL; + } +} diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 7537102..e0fdf7f 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -24,6 +24,7 @@ import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -136,11 +137,22 @@ public AppendEntriesResponse appendEntries(@Nonnull RaftStateContext ctx, @Nonnu @Nonnull @Override public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException { + throw throwMustBeLeader(); + } + + protected RuntimeException throwMustBeLeader() throws RaftException { if (leader.isPresent()) { throw new NotLeaderException(leader.get()); } else { throw new NoLeaderException(); } } + + @Override + public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) + throws RaftException { + throw throwMustBeLeader(); + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 153ee31..5a3c519 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -20,12 +20,14 @@ import com.google.common.base.Optional; import com.google.common.collect.Maps; import com.google.common.primitives.Longs; +import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,6 +43,7 @@ import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -75,7 +78,7 @@ class Leader extends BaseState { @Override public void init(@Nonnull RaftStateContext ctx) { - for (Replica replica : log.members()) { + for (Replica replica : ctx.getConfigurationState().remote()) { managers.put(replica, replicaManagerFactory.create(replica)); } @@ -161,7 +164,18 @@ public void run() { public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException { resetTimeout(ctx); - ListenableFuture result = log.append(operation); + + ListenableFuture result = log.append(operation, null); + sendRequests(ctx); + return result; + + } + + ListenableFuture commitMembership(@Nonnull RaftStateContext ctx, @Nonnull Membership membership) { + + resetTimeout(ctx); + + ListenableFuture result = log.append(null, membership); sendRequests(ctx); return result; @@ -172,7 +186,7 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ * matchIndex values are greater and half are less than this value. So, at least half of the replicas have stored the * median value, this is the definition of committed. */ - private void updateCommitted() { + private void updateCommitted(RaftStateContext ctx) { List sorted = newArrayList(managers.values()); Collections.sort(sorted, new Comparator() { @@ -186,6 +200,49 @@ public int compare(ReplicaManager o, ReplicaManager o2) { final long committed = sorted.get(middle).getMatchIndex(); log.commitIndex(committed); + ConfigurationState configurationState = ctx.getConfigurationState(); + if (committed >= configurationState.getId()) { + handleConfigurationUpdate(ctx); + } + + } + + private void handleConfigurationUpdate(RaftStateContext ctx) { + ConfigurationState configurationState = ctx.getConfigurationState(); + + // Upon committing a configuration that excludes itself, the leader + // steps down. + if (!configurationState.hasVote(configurationState.self())) { + stepDown(ctx /*logcabin: currentTerm + 1*/); + return; + } + + // Upon committing a reconfiguration (Cold,new) entry, the leader + // creates the next configuration (Cnew) entry. + if (configurationState.isTransitional()) { + final Membership membership = configurationState.getMembership(); + + Membership.Builder members = Membership.newBuilder(); + members.addAllMembers(membership.getProposedMembersList()); + + Futures.addCallback(commitMembership(ctx, members.build()), + new FutureCallback() { + + @Override + public void onSuccess(Object result) { + if (Boolean.TRUE.equals(result)) { + LOGGER.info("Committed new cluster configuration: {}", membership); + } else { + LOGGER.warn("Failed to commit new cluster configuration: {}", membership); + } + } + + @Override + public void onFailure(Throwable t) { + LOGGER.warn("Error committing new cluster configuration: {}", membership); + } + }); + } } private void checkTermOnResponse(RaftStateContext ctx, AppendEntriesResponse response) { @@ -212,7 +269,7 @@ List> sendRequests(final RaftStateContex Futures.addCallback(response, new FutureCallback() { @Override public void onSuccess(@Nullable AppendEntriesResponse result) { - updateCommitted(); + updateCommitted(ctx); checkTermOnResponse(ctx, result); } @@ -224,5 +281,48 @@ public void onFailure(Throwable t) {} } return responses; } + + @Override + public ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, long oldId, final Membership nextConfiguration) throws RaftException { + if (nextConfiguration.getProposedMembersCount() != 0) { + // We expect members to be passed in, not proposed_members + throw new IllegalArgumentException(); + } + + final ConfigurationState configuration = ctx.getConfigurationState(); + if (configuration.getId() != oldId || configuration.isTransitional()) { + // configurations has changed in the meantime + return Futures.immediateFuture(Boolean.FALSE); + } + + // TODO: Introduce Staging state; wait for staging servers to catch up + + // Commit a transitional configuration with old and new + Membership.Builder transitionalMembership = Membership.newBuilder(); + transitionalMembership.addAllMembers(configuration.getMembership().getMembersList()); + transitionalMembership.addAllProposedMembers(nextConfiguration.getMembersList()); + ListenableFuture transitionFuture = commitMembership(ctx, transitionalMembership.build()); + + return Futures.transform(transitionFuture, new AsyncFunction() { + // In response to the transitional configuration, the leader commits the final configuration + // We poll for this configuration + @Override + public ListenableFuture apply(Object input) throws Exception { + if (!Boolean.TRUE.equals(input)) { + return Futures.immediateFuture(Boolean.FALSE); + } + + return new PollFor(scheduler, 200, 200, TimeUnit.MILLISECONDS) { + @Override + protected Optional poll() { + if (!configuration.isTransitional()) { + return Optional.of(configuration.getMembership().equals(nextConfiguration)); + } + return Optional.absent(); + } + }.start(); + } + }); + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/PollFor.java b/barge-core/src/main/java/org/robotninjas/barge/state/PollFor.java new file mode 100644 index 0000000..95af8e8 --- /dev/null +++ b/barge-core/src/main/java/org/robotninjas/barge/state/PollFor.java @@ -0,0 +1,77 @@ +package org.robotninjas.barge.state; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; + +public abstract class PollFor { + private static final Logger log = LoggerFactory.getLogger(PollFor.class); + + protected final SettableFuture future; + final ScheduledExecutorService executor; + final int initial; + final int interval; + final TimeUnit timeUnit; + + protected abstract Optional poll(); + + public PollFor(ScheduledExecutorService executor, int initial, int interval, TimeUnit timeUnit) { + this.executor = executor; + this.initial = initial; + this.interval = interval; + this.timeUnit = timeUnit; + this.future = SettableFuture.create(); + } + + public ListenableFuture start() { + executor.schedule(new Runnable() { + + @Override + public void run() { + doPoll(); + } + }, initial, timeUnit); + return future; + } + + protected final void doPoll() { + try { + doPoll0(); + } catch (Throwable t) { + log.error("Error while polling", t); + } + } + + protected void doPoll0() { + if (future.isCancelled()) { + return; + } + + try { + Optional result = poll(); + if (result.isPresent()) { + future.set(result.get()); + } + } catch (Throwable t) { + future.setException(t); + } + + if (!future.isDone()) { + executor.schedule(new Runnable() { + + @Override + public void run() { + doPoll(); + } + + }, interval, timeUnit); + } + + } +} diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java index 9940efb..1594a84 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java @@ -39,10 +39,12 @@ public enum StateType {START, FOLLOWER, CANDIDATE, LEADER} private final StateFactory stateFactory; private volatile StateType state; private volatile State delegate; + private final ConfigurationState configurationState; @Inject - RaftStateContext(StateFactory stateFactory) { + RaftStateContext(StateFactory stateFactory, ConfigurationState configurationState) { this.stateFactory = stateFactory; + this.configurationState = configurationState; } @Nonnull @@ -95,4 +97,9 @@ public synchronized void setState(@Nonnull State oldState, @Nonnull StateType st public StateType getState() { return state; } + + @Nonnull + public ConfigurationState getConfigurationState() { + return configurationState; + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java index 923f32c..48e3568 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java @@ -4,9 +4,8 @@ import com.google.inject.Inject; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.log.RaftLog; - +import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; - import static com.google.inject.internal.util.$Preconditions.checkNotNull; import static org.robotninjas.barge.proto.RaftProto.*; import static org.robotninjas.barge.state.RaftStateContext.StateType.FOLLOWER; @@ -44,4 +43,10 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ throw new RaftException("Service has not started yet"); } + @Override + public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) + throws RaftException { + throw new RaftException("Service has not started yet"); + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/State.java b/barge-core/src/main/java/org/robotninjas/barge/state/State.java index befd113..a8bafe6 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/State.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/State.java @@ -18,6 +18,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; @@ -36,4 +37,7 @@ interface State { @Nonnull ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException; + @Nonnull + ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, long oldId, @Nonnull Membership nextConfiguration) throws RaftException; + } diff --git a/barge-core/src/main/proto/entry.proto b/barge-core/src/main/proto/entry.proto index ed48285..3a01f81 100644 --- a/barge-core/src/main/proto/entry.proto +++ b/barge-core/src/main/proto/entry.proto @@ -17,7 +17,13 @@ option java_package = "org.robotninjas.barge.proto"; option java_outer_classname = "RaftEntry"; +message Membership { + repeated string members = 1; + repeated string proposed_members = 2; +} + message Entry { required int64 term = 1; - required bytes command = 2; + optional bytes command = 2; + optional Membership membership = 3; } \ No newline at end of file diff --git a/barge-core/src/main/proto/log.proto b/barge-core/src/main/proto/log.proto index b3f55b9..44ec900 100644 --- a/barge-core/src/main/proto/log.proto +++ b/barge-core/src/main/proto/log.proto @@ -25,12 +25,6 @@ message Append { required Entry entry = 2; } -message Membership { - required int64 index = 1; - required int64 term = 2; - repeated string members = 3; -} - message Vote { optional string voted_for = 2; } @@ -51,7 +45,6 @@ message Snapshot { message JournalEntry { optional Append append = 2; - optional Membership membership = 3; optional Vote vote = 4; optional Term term = 5; optional Commit commit = 6; diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java index 61c6fd7..2531174 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java @@ -10,6 +10,7 @@ import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.proto.RaftProto; import javax.annotation.Nonnull; @@ -176,6 +177,12 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ return null; } + @Override + public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) + throws RaftException { + return null; + } + } } diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java index 7045d3f..8631dfc 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java @@ -36,12 +36,17 @@ public class CandidateTest { private @Mock RaftLog mockRaftLog; private @Mock RaftStateContext mockRaftStateContext; + private @Mock + ConfigurationState configurationState; @Before public void initMocks() { MockitoAnnotations.initMocks(this); + when(configurationState.self()).thenReturn(self); + when(mockRaftStateContext.getConfigurationState()).thenReturn(configurationState); + when(mockRaftLog.self()).thenReturn(self); when(mockRaftLog.lastVotedFor()).thenReturn(Optional.absent()); when(mockRaftLog.lastLogTerm()).thenReturn(0L); @@ -84,6 +89,8 @@ public void testRequestVoteWithNewerTerm() throws Exception { verify(mockRaftStateContext, times(1)).setState(any(Candidate.class), eq(FOLLOWER)); verify(mockRaftStateContext, times(1)).setState(any(Candidate.class), eq(LEADER)); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); @@ -116,6 +123,8 @@ public void testRequestVoteWithOlderTerm() throws Exception { verify(mockRaftLog, never()).commitIndex(anyLong()); verify(mockRaftStateContext).setState(any(Candidate.class), eq(LEADER)); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); } @@ -148,7 +157,8 @@ public void testRequestVoteWithSameTerm() throws Exception { verify(mockRaftStateContext).setState(any(State.class), any(RaftStateContext.StateType.class)); - verifyZeroInteractions(mockRaftStateContext); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); } @@ -183,6 +193,8 @@ public void testAppendEntriesWithNewerTerm() throws Exception { verify(mockRaftStateContext).setState(any(Candidate.class), eq(FOLLOWER)); verify(mockRaftStateContext).setState(any(Candidate.class), eq(LEADER)); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); @@ -216,6 +228,8 @@ public void testAppendEntriesWithOlderTerm() throws Exception { verify(mockRaftLog, never()).commitIndex(anyLong()); verify(mockRaftStateContext).setState(any(Candidate.class), eq(LEADER)); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); @@ -248,6 +262,8 @@ public void testAppendEntriesWithSameTerm() throws Exception { verify(mockRaftStateContext).setState(any(Candidate.class), eq(FOLLOWER)); verify(mockRaftStateContext).setState(any(Candidate.class), eq(LEADER)); + verify(mockRaftStateContext, times(1)).getConfigurationState(); + verifyNoMoreInteractions(mockRaftStateContext); verifyZeroInteractions(mockRaftClient); diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/DefaultContextTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/DefaultContextTest.java index c3694c8..d67213a 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/DefaultContextTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/DefaultContextTest.java @@ -5,6 +5,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.Replica; import static junit.framework.Assert.assertEquals; import static org.mockito.Mockito.*; @@ -15,6 +16,7 @@ public class DefaultContextTest { private @Mock StateFactory mockStateFactory; + private @Mock ConfigurationState configurationState; private @Mock Leader mockLeader; private @Mock Follower mockFollower; private @Mock Candidate mockCandidate; @@ -35,7 +37,7 @@ public void initMocks() { @Test public void testDefaultContext() throws RaftException { - RaftStateContext ctx = new RaftStateContext(mockStateFactory); + RaftStateContext ctx = new RaftStateContext(mockStateFactory, configurationState); ctx.setState(null, StateType.FOLLOWER); diff --git a/barge-tools/src/main/java/org/robotninjas/barge/tools/LogTool.java b/barge-tools/src/main/java/org/robotninjas/barge/tools/LogTool.java index 9c965af..59644ad 100644 --- a/barge-tools/src/main/java/org/robotninjas/barge/tools/LogTool.java +++ b/barge-tools/src/main/java/org/robotninjas/barge/tools/LogTool.java @@ -5,6 +5,7 @@ import journal.io.api.JournalBuilder; import journal.io.api.Location; import org.robotninjas.barge.proto.LogProto; +import org.robotninjas.barge.proto.RaftEntry.Entry; import java.io.File; import java.io.IOException; @@ -40,8 +41,15 @@ public static void main(String... args) throws IOException { LogProto.Append a = entry.getAppend(); index = a.getIndex(); + + Entry appendEntry = a.getEntry(); + if (appendEntry.hasMembership()) { + lastEntryType = Type.MEMBERSHIP; + } + if (appendEntry.hasCommand()) { + lastEntryType = Type.APPEND; + } term = a.getEntry().getTerm(); - lastEntryType = Type.APPEND; } else if (entry.hasCommit()) { @@ -49,12 +57,6 @@ public static void main(String... args) throws IOException { committed = c.getIndex(); lastEntryType = Type.COMMIT; - } else if (entry.hasMembership()) { - - LogProto.Membership m = entry.getMembership(); - membership = m.getMembersList(); - lastEntryType = Type.MEMBERSHIP; - } else if (entry.hasSnapshot()) { LogProto.Snapshot s = entry.getSnapshot(); From 20322c20410b3b05598335020d1c3ce5e08f839a Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 16:55:40 -0500 Subject: [PATCH 03/26] Inject ConfigurationState with suitable starting state --- .../src/main/java/org/robotninjas/barge/RaftModule.java | 2 +- .../org/robotninjas/barge/state/ConfigurationState.java | 4 +++- .../java/org/robotninjas/barge/state/StateModule.java | 9 ++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java index a4d25c8..b80b5c5 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java @@ -67,8 +67,8 @@ public void setTimeout(long timeout) { @Override protected void configure() { - install(new StateModule(timeout)); Replica local = config.local(); + install(new StateModule(local, timeout)); final NioEventLoopGroup eventLoop; if (eventLoopGroup.isPresent()) { diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java index 68d00c6..43b0002 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java @@ -30,7 +30,9 @@ public class ConfigurationState { public ConfigurationState(Replica self) { this.local = self; this.localKey = self.getKey(); - setMembership(0, Membership.getDefaultInstance()); + Membership.Builder membership = Membership.newBuilder(); + membership.addMembers(self.getKey()); + setMembership(0, membership.build()); } public long getId() { diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/StateModule.java b/barge-core/src/main/java/org/robotninjas/barge/state/StateModule.java index 6ba7446..00cee98 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/StateModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/StateModule.java @@ -16,14 +16,18 @@ package org.robotninjas.barge.state; +import org.robotninjas.barge.Replica; + import com.google.inject.PrivateModule; import com.google.inject.assistedinject.FactoryModuleBuilder; public class StateModule extends PrivateModule { private final long electionTimeout; + private final Replica self; - public StateModule(long electionTimeout) { + public StateModule(Replica self, long electionTimeout) { + this.self = self; this.electionTimeout = electionTimeout; } @@ -44,6 +48,9 @@ protected void configure() { .asEagerSingleton(); expose(RaftStateContext.class); + bind(ConfigurationState.class) + .toInstance(new ConfigurationState(self)); + expose(ConfigurationState.class); } } From a131801cd15c1a48b959a547dea084eeb54ecff4 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 16:56:06 -0500 Subject: [PATCH 04/26] Cope with transitional configurations --- .../org/robotninjas/barge/state/Leader.java | 53 ++++++++++++++----- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 5a3c519..f5c2908 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -38,7 +38,6 @@ import javax.annotation.concurrent.NotThreadSafe; import javax.inject.Inject; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; @@ -186,21 +185,51 @@ ListenableFuture commitMembership(@Nonnull RaftStateContext ctx, @Nonnul * matchIndex values are greater and half are less than this value. So, at least half of the replicas have stored the * median value, this is the definition of committed. */ - private void updateCommitted(RaftStateContext ctx) { - - List sorted = newArrayList(managers.values()); - Collections.sort(sorted, new Comparator() { - @Override - public int compare(ReplicaManager o, ReplicaManager o2) { - return Longs.compare(o.getMatchIndex(), o2.getMatchIndex()); + long getQuorumMatchIndex(List serverKeys) { + List sorted = newArrayList(); + for (String serverKey : serverKeys) { + ReplicaManager replicaManager = managers.get(serverKey); + if (replicaManager != null) { + sorted.add(replicaManager.getMatchIndex()); + } else if (serverKey.equals(log.self().getKey())) { + sorted.add(log.lastLogIndex()); + } else { + throw new IllegalStateException("No replica manager for server: " + serverKey); } - }); + } + Collections.sort(sorted); + + int n = sorted.size(); + int quorumSize; + if ((n & 1) == 1) { + // Odd + quorumSize = (n + 1) / 2; + } else { + // Even + quorumSize = (n / 2) + 1; + } + final int middle = quorumSize - 1; + final long committed = sorted.get(middle); + + return committed; + } - final int middle = (int) Math.ceil(sorted.size() / 2.0); - final long committed = sorted.get(middle).getMatchIndex(); - log.commitIndex(committed); + long getQuorumMatchIndex(ConfigurationState configurationState) { + if (configurationState.isTransitional()) { + return Math.min( + getQuorumMatchIndex(configurationState.getMembership().getMembersList()), + getQuorumMatchIndex(configurationState.getMembership().getProposedMembersList())); + } else { + return getQuorumMatchIndex(configurationState.getMembership().getMembersList()); + } + } + private void updateCommitted(RaftStateContext ctx) { ConfigurationState configurationState = ctx.getConfigurationState(); + + long committed = getQuorumMatchIndex(configurationState); + log.commitIndex(committed); + if (committed >= configurationState.getId()) { handleConfigurationUpdate(ctx); } From 3ef9a951aaed5602df86ad7b9a3659dead311d23 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 16:56:21 -0500 Subject: [PATCH 05/26] Cope with empty configurations --- .../src/main/java/org/robotninjas/barge/state/Leader.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index f5c2908..4a99faa 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -308,6 +308,10 @@ public void onFailure(Throwable t) {} }); } + + if (responses.isEmpty()) { + updateCommitted(ctx); + } return responses; } From 3e8d6741d1db24e267bc5ef2be1da6dc9b074d08 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 22:58:18 -0500 Subject: [PATCH 06/26] First passing test with configuration change Admittedly with no data! --- .../org/robotninjas/barge/RaftMembership.java | 40 ++++ .../org/robotninjas/barge/RaftService.java | 40 +++- .../org/robotninjas/barge/log/RaftLog.java | 16 +- .../org/robotninjas/barge/rpc/RaftClient.java | 18 +- .../barge/rpc/RaftClientProvider.java | 2 +- .../robotninjas/barge/state/Candidate.java | 32 ++- .../barge/state/ConfigurationState.java | 154 +++++++++---- .../org/robotninjas/barge/state/Follower.java | 5 +- .../org/robotninjas/barge/state/Leader.java | 211 ++++++++++++------ .../barge/state/RaftStateContext.java | 8 + .../org/robotninjas/barge/state/Start.java | 5 +- .../org/robotninjas/barge/state/State.java | 3 +- .../barge/state/BaseStateTest.java | 5 +- 13 files changed, 417 insertions(+), 122 deletions(-) create mode 100644 barge-core/src/main/java/org/robotninjas/barge/RaftMembership.java diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftMembership.java b/barge-core/src/main/java/org/robotninjas/barge/RaftMembership.java new file mode 100644 index 0000000..c7206a7 --- /dev/null +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftMembership.java @@ -0,0 +1,40 @@ +package org.robotninjas.barge; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; + +public class RaftMembership { + + final long id; + final ImmutableList members; + + public RaftMembership(long id, Collection members) { + this.id = id; + List sorted = Lists.newArrayList(members); + Collections.sort(sorted); + this.members = ImmutableList.copyOf(sorted); + } + + public long getId() { + return id; + } + + public ImmutableList getMembers() { + return members; + } + + public RaftMembership merge(RaftMembership other) { + Set merged = Sets.newHashSet(); + merged.addAll(members); + merged.addAll(other.members); + + return new RaftMembership(-1L, merged); + } + +} diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 8adb891..16498f2 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -23,6 +23,9 @@ import com.google.inject.Injector; import com.google.protobuf.Service; import io.netty.channel.nio.NioEventLoopGroup; + +import org.robotninjas.barge.log.RaftLog; +import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.proto.RaftProto; import org.robotninjas.barge.rpc.RaftExecutor; import org.robotninjas.barge.state.RaftStateContext; @@ -53,16 +56,28 @@ public class RaftService extends AbstractService { private final ListeningExecutorService executor; private final RpcServer rpcServer; private final RaftStateContext ctx; + private final RaftLog raftLog; @Inject - RaftService(@Nonnull RpcServer rpcServer, @RaftExecutor ListeningExecutorService executor, @Nonnull RaftStateContext ctx) { + RaftService(@Nonnull RpcServer rpcServer, @RaftExecutor ListeningExecutorService executor, @Nonnull RaftStateContext ctx, @Nonnull RaftLog raftLog) { this.executor = checkNotNull(executor); this.rpcServer = checkNotNull(rpcServer); this.ctx = checkNotNull(ctx); + this.raftLog = raftLog; } + public void bootstrap(Membership membership) { + + LOGGER.info("Bootstrapping log with {}", membership); + if (raftLog.lastLogTerm() != 0 || raftLog.lastLogIndex() != 0) { + LOGGER.warn("Cannot bootstrap, as raft log already contains data"); + throw new IllegalStateException(); + } + raftLog.append(null, membership); + } + @Override protected void doStart() { @@ -176,5 +191,28 @@ public RaftService build(StateMachine stateMachine) { } + public ListenableFuture setConfiguration(final RaftMembership oldMembership, final RaftMembership newMembership) { + + // Make sure this happens on the Barge thread + ListenableFuture> response = + executor.submit(new Callable>() { + @Override + public ListenableFuture call() throws Exception { + return ctx.setConfiguration(oldMembership, newMembership); + } + }); + + return Futures.dereference(response); + + } + + public RaftMembership getClusterMembership() { + return ctx.getConfigurationState().getClusterMembership(); + } + + public String getServerKey() { + return ctx.getConfigurationState().self().getKey(); + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 3dfec3e..ceea7e5 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -68,6 +68,7 @@ public class RaftLog { private volatile Optional votedFor = Optional.absent(); private volatile long commitIndex = 0; private volatile long lastApplied = 0; + private final String name; @Inject RaftLog(@Nonnull Journal journal, @Nonnull ConfigurationState config, @@ -76,6 +77,8 @@ public class RaftLog { this.config = checkNotNull(config); this.stateMachine = checkNotNull(stateMachine); this.executor = checkNotNull(raftThread); + + this.name = journal.getDirectory().getName(); } public void load() { @@ -107,7 +110,7 @@ public void append(Entry entry, long index) { log.put(index, entry); if (entry.hasMembership()) { - config.add(index, entry); + config.addMembershipEntry(index, entry); } } }); @@ -124,7 +127,7 @@ private SettableFuture storeEntry(final long index, @Nonnull Entry entry log.put(index, entry); if (entry.hasMembership()) { - config.add(index, entry); + config.addMembershipEntry(index, entry); } SettableFuture result = SettableFuture.create(); @@ -195,6 +198,10 @@ void fireComitted() { try { for (long i = lastApplied + 1; i <= Math.min(commitIndex, lastLogIndex); ++i, ++lastApplied) { Entry entry = log.get(i); + + final SettableFuture returnedResult = operationResults.remove(i); + assert returnedResult != null; + if (entry.hasCommand()) { ByteString command = entry.getCommand(); // byte[] rawCommand = command.toByteArray(); @@ -202,7 +209,6 @@ void fireComitted() { final ByteBuffer operation = command.asReadOnlyByteBuffer(); ListenableFuture result = stateMachine.dispatchOperation(operation); - final SettableFuture returnedResult = operationResults.remove(i); Futures.addCallback(result, new PromiseBridge(returnedResult)); } @@ -289,4 +295,8 @@ public Replica self() { return config.self(); } + public String getName() { + return name; + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java index 7e3c98b..f958e52 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java +++ b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java @@ -21,8 +21,10 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.RpcCallback; import com.google.protobuf.RpcController; + import org.apache.commons.pool.ObjectPool; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.Replica; import org.robotninjas.barge.proto.RaftProto; import org.robotninjas.protobuf.netty.client.ClientController; import org.robotninjas.protobuf.netty.client.NettyRpcChannel; @@ -47,9 +49,11 @@ class RaftClient { private static final Logger LOGGER = LoggerFactory.getLogger(RaftClient.class); private static final long DEFAULT_TIMEOUT = 2000; + private final Replica replica; private final ObjectPool> channelPool; - RaftClient(@Nonnull ObjectPool> channelPool) { + RaftClient(@Nonnull Replica replica, @Nonnull ObjectPool> channelPool) { + this.replica = replica; this.channelPool = checkNotNull(channelPool); } @@ -67,6 +71,8 @@ public ListenableFuture appendEntries(@Nonnull AppendEntr private ListenableFuture call(final RpcCall call) { + LOGGER.debug("Sending message to {}: {}", replica, call); + ListenableFuture channel = null; try { @@ -131,6 +137,11 @@ static RpcCall appendEntries(final AppendEntries request) public void call(RaftService.Stub stub, RpcController controller, RpcCallback callback) { stub.appendEntries(controller, request, callback); } + + @Override + public String toString() { + return request.toString(); + } }; } @@ -140,6 +151,11 @@ static RpcCall requestVote(final RequestVote request) { public void call(RaftService.Stub stub, RpcController controller, RpcCallback callback) { stub.requestVote(controller, request, callback); } + + @Override + public String toString() { + return request.toString(); + } }; } diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClientProvider.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClientProvider.java index 4bdde57..6511a48 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClientProvider.java +++ b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClientProvider.java @@ -59,7 +59,7 @@ public RaftClientProvider(@Nonnull RpcClient client) { @Nonnull public RaftClient get(@Nonnull Replica replica) { checkNotNull(replica); - return new RaftClient(adapt(connectionPools, replica)); + return new RaftClient(replica, adapt(connectionPools, replica)); } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index d1af018..09c3b7d 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -24,9 +24,9 @@ import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.NoLeaderException; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; -import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.rpc.Client; import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; @@ -75,9 +75,16 @@ public void init(@Nonnull final RaftStateContext ctx) { log.currentTerm(log.currentTerm() + 1); log.lastVotedFor(Optional.of(log.self())); + if (configurationState.getAllVotingMembers().isEmpty()) { + // If there is nobody to vote in an election, we can't run it... + LOGGER.debug("No voting members; won't run election"); + return; + } + LOGGER.debug("Election starting for term {}", log.currentTerm()); List> responses = sendRequests(ctx); + electionResult = majorityResponse(responses, voteGranted()); long timeout = electionTimeout + (RAND.nextLong() % electionTimeout); @@ -189,10 +196,17 @@ List> sendRequests(RaftStateContext ctx) { .build(); List> responses = Lists.newArrayList(); - for (Replica replica : configurationState.remote()) { - ListenableFuture response = client.requestVote(replica, request); - Futures.addCallback(response, checkTerm(ctx)); - responses.add(response); + Replica self = configurationState.self(); + LOGGER.info("Starting election with members: {}", configurationState.getAllVotingMembers()); + for (Replica replica : configurationState.getAllVotingMembers()) { + if (replica == self) { + // We always vote for ourselves + responses.add(Futures.immediateFuture(RequestVoteResponse.newBuilder().setVoteGranted(true).buildPartial())); + } else { + ListenableFuture response = client.requestVote(replica, request); + Futures.addCallback(response, checkTerm(ctx)); + responses.add(response); + } } return responses; @@ -214,9 +228,13 @@ public void onFailure(Throwable t) {} } @Override - public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) - throws RaftException { + public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMembership oldMembership, + RaftMembership newMembership) throws RaftException { throw new NoLeaderException(); } + @Override + public String toString() { + return "Candidate [" + log.getName() + " @ " + log.self() + "]"; + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java index 43b0002..a81e520 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/ConfigurationState.java @@ -3,16 +3,19 @@ import static com.google.common.base.Preconditions.*; import java.util.List; +import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.proto.RaftEntry.Entry; import org.robotninjas.barge.proto.RaftEntry.Membership; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import com.google.common.collect.Sets; public class ConfigurationState { @@ -22,54 +25,69 @@ public class ConfigurationState { long membershipIndex; Membership membership; - final Replica local; - ImmutableList remote; + final Replica self; + // ImmutableList remote; - final String localKey; + private ImmutableList currentMembers; + private ImmutableList proposedMembers; + + private ImmutableList allVotingMembers; + + long version; + + private RaftMembership clusterMembership; public ConfigurationState(Replica self) { - this.local = self; - this.localKey = self.getKey(); + this.self = self; + + // The starting configuration is _no_ configuration. + // We must (externally) create an initial configuration log entry which will be replayed Membership.Builder membership = Membership.newBuilder(); - membership.addMembers(self.getKey()); +// membership.addMembers(self.getKey()); setMembership(0, membership.build()); } - + public long getId() { return membershipIndex; } + public long getVersion() { + return version; + } + enum State { STABLE, TRANSITIONAL } @Nonnull public Replica self() { - return local; + return self; } - @Nonnull - public List remote() { - return remote; - } + // @Nonnull + // public List remote() { + // return remote; + // } public boolean hasVote(Replica r) { - String key = r.getKey(); - - if (membership.getMembersList().contains(key)) { - return true; - } - - if (state == State.TRANSITIONAL) { - if (membership.getProposedMembersList().contains(key)) { - return true; - } - } - - return false; + return allVotingMembers.contains(r); + // + // String key = r.getKey(); + // + // if (membership.getMembersList().contains(key)) { + // return true; + // } + // + // if (state == State.TRANSITIONAL) { + // if (membership.getProposedMembersList().contains(key)) { + // return true; + // } + // } + // + // return false; } - public void add(long index, Entry entry) { + public void addMembershipEntry(long index, Entry entry) { checkArgument(entry.hasMembership()); if (membership == null || index > membershipIndex) { @@ -77,29 +95,65 @@ public void add(long index, Entry entry) { } } - private void setMembership(long index, Membership membership) { + private synchronized void setMembership(long index, Membership membership) { boolean transitional = membership.getProposedMembersCount() != 0; - Set replicaKeys = Sets.newHashSet(); - replicaKeys.addAll(membership.getMembersList()); + List proposedMembers = Lists.newArrayList(); + List currentMembers = Lists.newArrayList(); + List allVotingMembers = Lists.newArrayList(); + + Set allVotingMemberKeys = Sets.newHashSet(); + allVotingMemberKeys.addAll(membership.getMembersList()); if (transitional) { - replicaKeys.addAll(membership.getProposedMembersList()); + allVotingMemberKeys.addAll(membership.getProposedMembersList()); } - List remotes = Lists.newArrayList(); - for (String replicaKey : replicaKeys) { - Replica replica = Replica.fromString(replicaKey); - if (replicaKey.equals(localKey)) { - continue; + // TODO: Reuse objects? + Map replicas = Maps.newHashMap(); + replicas.put(self.getKey(), self); + + for (String replicaKey : allVotingMemberKeys) { + Replica replica = replicas.get(replicaKey); + if (replica == null) { + replica = Replica.fromString(replicaKey); + replicas.put(replicaKey, replica); } + allVotingMembers.add(replica); + } - remotes.add(replica); + for (String replicaKey : membership.getMembersList()) { + Replica replica = replicas.get(replicaKey); + if (replica == null) { + throw new IllegalStateException(); + } + currentMembers.add(replica); } - - this.remote = ImmutableList.copyOf(remotes); + + for (String replicaKey : membership.getProposedMembersList()) { + Replica replica = replicas.get(replicaKey); + if (replica == null) { + throw new IllegalStateException(); + } + proposedMembers.add(replica); + } + + // this.remote = ImmutableList.copyOf(remotes); this.membership = membership; this.membershipIndex = index; this.state = transitional ? State.TRANSITIONAL : State.STABLE; + + if (transitional) { + this.clusterMembership = null; + this.proposedMembers = ImmutableList.copyOf(proposedMembers); + } else { + this.clusterMembership = new RaftMembership(index, membership.getMembersList()); + this.proposedMembers = null; + } + + this.currentMembers = ImmutableList.copyOf(currentMembers); + this.allVotingMembers = ImmutableList.copyOf(allVotingMembers); + + this.version++; } public Membership getMembership() { @@ -109,4 +163,28 @@ public Membership getMembership() { public boolean isTransitional() { return state == State.TRANSITIONAL; } + + public RaftMembership getClusterMembership() { + return clusterMembership; + } + + public List getAllVotingMembers() { + return allVotingMembers; + } + + public List getCurrentMembers() { + return currentMembers; + } + + public List getProposedMembers() { + return proposedMembers; + } + + @Override + public String toString() { + return "ConfigurationState [state=" + state + ", currentMembers=" + currentMembers + ", proposedMembers=" + + proposedMembers + ", allVotingMembers=" + allVotingMembers + ", version=" + version + "]"; + } + + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index e0fdf7f..9d6f8c9 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -22,6 +22,7 @@ import org.robotninjas.barge.NoLeaderException; import org.robotninjas.barge.NotLeaderException; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; @@ -149,8 +150,8 @@ protected RuntimeException throwMustBeLeader() throws RaftException { } @Override - public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) - throws RaftException { + public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMembership oldMembership, + RaftMembership newMembership) throws RaftException { throw throwMustBeLeader(); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 4a99faa..9adb806 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -18,13 +18,15 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import com.google.common.primitives.Longs; +import com.google.common.collect.Sets; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; @@ -38,8 +40,11 @@ import javax.annotation.concurrent.NotThreadSafe; import javax.inject.Inject; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -59,13 +64,14 @@ class Leader extends BaseState { private final RaftLog log; private final ScheduledExecutorService scheduler; private final long timeout; - private final Map managers = Maps.newHashMap(); + private final Map replicaManagers = Maps.newHashMap(); + private long replicaManagersLastUpdated; private final ReplicaManagerFactory replicaManagerFactory; private ScheduledFuture heartbeatTask; @Inject - Leader(RaftLog log, @RaftScheduler ScheduledExecutorService scheduler, - @ElectionTimeout @Nonnegative long timeout, ReplicaManagerFactory replicaManagerFactory) { + Leader(RaftLog log, @RaftScheduler ScheduledExecutorService scheduler, @ElectionTimeout @Nonnegative long timeout, + ReplicaManagerFactory replicaManagerFactory) { this.log = checkNotNull(log); this.scheduler = checkNotNull(scheduler); @@ -77,18 +83,42 @@ class Leader extends BaseState { @Override public void init(@Nonnull RaftStateContext ctx) { - for (Replica replica : ctx.getConfigurationState().remote()) { - managers.put(replica, replicaManagerFactory.create(replica)); - } - sendRequests(ctx); resetTimeout(ctx); } + private ReplicaManager getReplicaManager(RaftStateContext ctx, Replica replica) { + assert replica != ctx.getConfigurationState().self(); + ReplicaManager replicaManager = replicaManagers.get(replica); + if (replicaManager == null) { + replicaManager = replicaManagerFactory.create(replica); + replicaManagers.put(replica, replicaManager); + } + + // Remove old entries + { + long configurationVersion = ctx.getConfigurationState().getVersion(); + if (configurationVersion != replicaManagersLastUpdated) { + Set allMembers = Sets.newHashSet(ctx.getConfigurationState().getAllVotingMembers()); + Iterator> it = replicaManagers.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + assert entry.getKey() != ctx.getConfigurationState().self(); + if (!allMembers.contains(entry.getKey())) { + it.remove(); + } + } + replicaManagersLastUpdated = configurationVersion; + } + } + + return replicaManager; + } + private void stepDown(RaftStateContext ctx) { heartbeatTask.cancel(false); - for (ReplicaManager mgr : managers.values()) { + for (ReplicaManager mgr : replicaManagers.values()) { mgr.shutdown(); } ctx.setState(this, FOLLOWER); @@ -127,9 +157,16 @@ public RequestVoteResponse requestVote(@Nonnull RaftStateContext ctx, @Nonnull R @Override public AppendEntriesResponse appendEntries(@Nonnull RaftStateContext ctx, @Nonnull AppendEntries request) { + LOGGER.debug("Got request: {}", request); + boolean success = false; - if (request.getTerm() > log.currentTerm()) { + long currentTerm = log.currentTerm(); + if (request.getTerm() < currentTerm) { + LOGGER.info("Caller has out-of-date term; ignoring request: {}", request); + } + + if (request.getTerm() > currentTerm) { log.currentTerm(request.getTerm()); stepDown(ctx); success = log.append(request); @@ -160,7 +197,8 @@ public void run() { @Nonnull @Override - public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException { + public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) + throws RaftException { resetTimeout(ctx); @@ -185,16 +223,19 @@ ListenableFuture commitMembership(@Nonnull RaftStateContext ctx, @Nonnul * matchIndex values are greater and half are less than this value. So, at least half of the replicas have stored the * median value, this is the definition of committed. */ - long getQuorumMatchIndex(List serverKeys) { + long getQuorumMatchIndex(RaftStateContext ctx, List replicas) { + Replica self = log.self(); + List sorted = newArrayList(); - for (String serverKey : serverKeys) { - ReplicaManager replicaManager = managers.get(serverKey); - if (replicaManager != null) { - sorted.add(replicaManager.getMatchIndex()); - } else if (serverKey.equals(log.self().getKey())) { + for (Replica replica : replicas) { + if (replica == self) { sorted.add(log.lastLogIndex()); } else { - throw new IllegalStateException("No replica manager for server: " + serverKey); + ReplicaManager replicaManager = getReplicaManager(ctx, replica); + if (replicaManager == null) { + throw new IllegalStateException("No replica manager for server: " + replica); + } + sorted.add(replicaManager.getMatchIndex()); } } Collections.sort(sorted); @@ -209,41 +250,43 @@ long getQuorumMatchIndex(List serverKeys) { quorumSize = (n / 2) + 1; } final int middle = quorumSize - 1; + assert middle < sorted.size(); + assert middle >= 0; final long committed = sorted.get(middle); - + + LOGGER.info("State={} Quorum={}", sorted, committed); return committed; } - long getQuorumMatchIndex(ConfigurationState configurationState) { + long getQuorumMatchIndex(RaftStateContext ctx, ConfigurationState configurationState) { if (configurationState.isTransitional()) { - return Math.min( - getQuorumMatchIndex(configurationState.getMembership().getMembersList()), - getQuorumMatchIndex(configurationState.getMembership().getProposedMembersList())); + return Math.min(getQuorumMatchIndex(ctx, configurationState.getCurrentMembers()), + getQuorumMatchIndex(ctx, configurationState.getProposedMembers())); } else { - return getQuorumMatchIndex(configurationState.getMembership().getMembersList()); + return getQuorumMatchIndex(ctx, configurationState.getCurrentMembers()); } } private void updateCommitted(RaftStateContext ctx) { ConfigurationState configurationState = ctx.getConfigurationState(); - long committed = getQuorumMatchIndex(configurationState); + long committed = getQuorumMatchIndex(ctx, configurationState); log.commitIndex(committed); if (committed >= configurationState.getId()) { handleConfigurationUpdate(ctx); } - + } private void handleConfigurationUpdate(RaftStateContext ctx) { ConfigurationState configurationState = ctx.getConfigurationState(); - + // Upon committing a configuration that excludes itself, the leader // steps down. if (!configurationState.hasVote(configurationState.self())) { - stepDown(ctx /*logcabin: currentTerm + 1*/); - return; + stepDown(ctx /* logcabin: currentTerm + 1 */); + return; } // Upon committing a reconfiguration (Cold,new) entry, the leader @@ -253,33 +296,32 @@ private void handleConfigurationUpdate(RaftStateContext ctx) { Membership.Builder members = Membership.newBuilder(); members.addAllMembers(membership.getProposedMembersList()); - - Futures.addCallback(commitMembership(ctx, members.build()), - new FutureCallback() { - @Override - public void onSuccess(Object result) { - if (Boolean.TRUE.equals(result)) { - LOGGER.info("Committed new cluster configuration: {}", membership); - } else { - LOGGER.warn("Failed to commit new cluster configuration: {}", membership); - } - } + Futures.addCallback(commitMembership(ctx, members.build()), new FutureCallback() { - @Override - public void onFailure(Throwable t) { - LOGGER.warn("Error committing new cluster configuration: {}", membership); - } - }); - } + @Override + public void onSuccess(Object result) { + if (Boolean.TRUE.equals(result)) { + LOGGER.info("Committed new cluster configuration: {}", membership); + } else { + LOGGER.warn("Failed to commit new cluster configuration: {}", membership); + } + } + + @Override + public void onFailure(Throwable t) { + LOGGER.warn("Error committing new cluster configuration: {}", membership); + } + }); + } } private void checkTermOnResponse(RaftStateContext ctx, AppendEntriesResponse response) { - if (response.getTerm() > log.currentTerm()) { - log.currentTerm(response.getTerm()); - stepDown(ctx); - } + if (response.getTerm() > log.currentTerm()) { + log.currentTerm(response.getTerm()); + stepDown(ctx); + } } @@ -292,7 +334,13 @@ private void checkTermOnResponse(RaftStateContext ctx, AppendEntriesResponse res @VisibleForTesting List> sendRequests(final RaftStateContext ctx) { List> responses = newArrayList(); - for (ReplicaManager replicaManager : managers.values()) { + Replica self = ctx.getConfigurationState().self(); + for (Replica replica : ctx.getConfigurationState().getAllVotingMembers()) { + if (replica == self) { + continue; + } + + ReplicaManager replicaManager = getReplicaManager(ctx, replica); ListenableFuture response = replicaManager.requestUpdate(); responses.add(response); Futures.addCallback(response, new FutureCallback() { @@ -303,7 +351,9 @@ public void onSuccess(@Nullable AppendEntriesResponse result) { } @Override - public void onFailure(Throwable t) {} + public void onFailure(Throwable t) { + LOGGER.debug("Failure response from replica", t); + } }); @@ -316,32 +366,54 @@ public void onFailure(Throwable t) {} } @Override - public ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, long oldId, final Membership nextConfiguration) throws RaftException { - if (nextConfiguration.getProposedMembersCount() != 0) { - // We expect members to be passed in, not proposed_members - throw new IllegalArgumentException(); + public ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, RaftMembership oldMembership, + RaftMembership newMembership) throws RaftException { + // TODO: Check quorums overlap? + final Membership targetConfiguration; + { + Membership.Builder b = Membership.newBuilder(); + + List members = Lists.newArrayList(newMembership.getMembers()); + Collections.sort(members); + b.addAllMembers(members); + targetConfiguration = b.build(); } final ConfigurationState configuration = ctx.getConfigurationState(); - if (configuration.getId() != oldId || configuration.isTransitional()) { - // configurations has changed in the meantime + if (configuration.isTransitional()) { + LOGGER.warn("Failing setConfiguration due to transitional configuration"); + return Futures.immediateFuture(Boolean.FALSE); + } + + if (configuration.getId() != oldMembership.getId()) { + // configuration has changed in the meantime + LOGGER.warn("Failing setConfiguration due to version mismatch: {} vs {}", configuration.getId(), oldMembership); return Futures.immediateFuture(Boolean.FALSE); } // TODO: Introduce Staging state; wait for staging servers to catch up // Commit a transitional configuration with old and new - Membership.Builder transitionalMembership = Membership.newBuilder(); - transitionalMembership.addAllMembers(configuration.getMembership().getMembersList()); - transitionalMembership.addAllProposedMembers(nextConfiguration.getMembersList()); - ListenableFuture transitionFuture = commitMembership(ctx, transitionalMembership.build()); - + final Membership transitionalMembership; + { + Membership.Builder b = Membership.newBuilder(); + + List members = Lists.newArrayList(oldMembership.getMembers()); + Collections.sort(members); + b.addAllMembers(members); + + b.addAllProposedMembers(targetConfiguration.getMembersList()); + transitionalMembership = b.build(); + } + ListenableFuture transitionFuture = commitMembership(ctx, transitionalMembership); + return Futures.transform(transitionFuture, new AsyncFunction() { // In response to the transitional configuration, the leader commits the final configuration // We poll for this configuration @Override public ListenableFuture apply(Object input) throws Exception { if (!Boolean.TRUE.equals(input)) { + LOGGER.warn("Failed to apply transitional configuration"); return Futures.immediateFuture(Boolean.FALSE); } @@ -349,7 +421,13 @@ public ListenableFuture apply(Object input) throws Exception { @Override protected Optional poll() { if (!configuration.isTransitional()) { - return Optional.of(configuration.getMembership().equals(nextConfiguration)); + boolean success = configuration.getMembership().equals(targetConfiguration); + if (success) { + LOGGER.info("Applied new configuration: {}", configuration); + } else { + LOGGER.warn("Could not apply configuration: wanted={} actual={}", targetConfiguration, configuration.getMembership()); + } + return Optional.of(success); } return Optional.absent(); } @@ -358,4 +436,9 @@ protected Optional poll() { }); } + @Override + public String toString() { + return "Leader [" + log.getName() + " @ " + log.self() + "]"; + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java index 1594a84..a104073 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java @@ -18,6 +18,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -64,6 +65,13 @@ public ListenableFuture commitOperation(@Nonnull byte[] op) throws RaftE checkNotNull(op); return delegate.commitOperation(this, op); } + + @Nonnull + public ListenableFuture setConfiguration(@Nonnull RaftMembership oldMembership, @Nonnull RaftMembership newMembership) throws RaftException { + checkNotNull(oldMembership); + checkNotNull(newMembership); + return delegate.setConfiguration(this, oldMembership, newMembership); + } public synchronized void setState(@Nonnull State oldState, @Nonnull StateType state) { if (this.delegate != oldState) { diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java index 48e3568..b4af635 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java @@ -3,6 +3,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; @@ -44,8 +45,8 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ } @Override - public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) - throws RaftException { + public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMembership oldMembership, + RaftMembership newMembership) throws RaftException { throw new RaftException("Service has not started yet"); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/State.java b/barge-core/src/main/java/org/robotninjas/barge/state/State.java index a8bafe6..d63f438 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/State.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/State.java @@ -18,6 +18,7 @@ import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; @@ -38,6 +39,6 @@ interface State { ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @Nonnull byte[] operation) throws RaftException; @Nonnull - ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, long oldId, @Nonnull Membership nextConfiguration) throws RaftException; + ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, @Nonnull RaftMembership oldMembership, @Nonnull RaftMembership newMembership) throws RaftException; } diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java index 2531174..ed16f20 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java @@ -8,6 +8,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robotninjas.barge.RaftException; +import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; @@ -178,8 +179,8 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ } @Override - public ListenableFuture setConfiguration(RaftStateContext ctx, long oldId, Membership nextConfiguration) - throws RaftException { + public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMembership oldMembership, + RaftMembership newMembership) throws RaftException { return null; } From 74d19e9481851bed1d89a342204752e7ef7cf2ae Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 23:00:50 -0500 Subject: [PATCH 07/26] Force NIO event group to be single threaded As otherwise thread guarantees aren't enforced? --- barge-core/src/main/java/org/robotninjas/barge/RaftModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java index b80b5c5..ee2b63b 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java @@ -74,7 +74,7 @@ protected void configure() { if (eventLoopGroup.isPresent()) { eventLoop = eventLoopGroup.get(); } else { - eventLoop = new NioEventLoopGroup(); + eventLoop = new NioEventLoopGroup(1); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { eventLoop.shutdownGracefully(); From 147f27f0d1475268bb21ad6e1fd62df005865539 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 23:01:17 -0500 Subject: [PATCH 08/26] Turn off snapshots for now (in this branch) --- barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java | 1 + 1 file changed, 1 insertion(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index ceea7e5..8abcd46 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -123,6 +123,7 @@ public void append(Entry entry, long index) { private SettableFuture storeEntry(final long index, @Nonnull Entry entry) { LOGGER.debug("{}", entry); + journal.appendEntry(entry, index); log.put(index, entry); From 8eda2f7ad817f761bd671e365c94b7a07ddb5cec Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Tue, 14 Jan 2014 23:07:09 -0500 Subject: [PATCH 09/26] Fix copy-and-paste error --- .../src/main/java/org/robotninjas/barge/state/Candidate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index 09c3b7d..610b7dd 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -75,7 +75,7 @@ public void init(@Nonnull final RaftStateContext ctx) { log.currentTerm(log.currentTerm() + 1); log.lastVotedFor(Optional.of(log.self())); - if (configurationState.getAllVotingMembers().isEmpty()) { + if (ctx.getConfigurationState().getAllVotingMembers().isEmpty()) { // If there is nobody to vote in an election, we can't run it... LOGGER.debug("No voting members; won't run election"); return; From 8d650ddb7c55a82f99e691cca956d057c441f025 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:21:13 -0500 Subject: [PATCH 10/26] Manage threads using BargeThreadPool So we can close it cleanly --- .../robotninjas/barge/BargeThreadPools.java | 91 +++++++++++++++++++ .../org/robotninjas/barge/RaftModule.java | 33 ++----- .../org/robotninjas/barge/RaftService.java | 9 +- .../org/robotninjas/barge/log/LogModule.java | 14 +-- .../org/robotninjas/barge/log/RaftLog.java | 8 +- .../barge/log/StateMachineProxy.java | 7 +- .../robotninjas/barge/rpc/RaftExecutor.java | 33 ------- .../robotninjas/barge/rpc/RaftScheduler.java | 31 ------- .../org/robotninjas/barge/rpc/RpcModule.java | 57 ++++++------ .../robotninjas/barge/state/Candidate.java | 8 +- .../org/robotninjas/barge/state/Follower.java | 8 +- .../org/robotninjas/barge/state/Leader.java | 6 +- .../barge/state/CandidateTest.java | 21 +++-- 13 files changed, 177 insertions(+), 149 deletions(-) create mode 100644 barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java delete mode 100644 barge-core/src/main/java/org/robotninjas/barge/rpc/RaftExecutor.java delete mode 100644 barge-core/src/main/java/org/robotninjas/barge/rpc/RaftScheduler.java diff --git a/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java b/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java new file mode 100644 index 0000000..61b7089 --- /dev/null +++ b/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java @@ -0,0 +1,91 @@ +package org.robotninjas.barge; + +import java.io.Closeable; +import java.io.IOException; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.ListeningScheduledExecutorService; +import com.google.common.util.concurrent.MoreExecutors; + +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.DefaultThreadFactory; + +public class BargeThreadPools implements Closeable { + + private static final int NUM_THREADS = 1; + + boolean closed; + final NioEventLoopGroup raftEventLoop; + final boolean closeEventLoop; + final ListeningExecutorService stateMachineExecutor; + final boolean closeStateMachineExecutor; + final ListeningScheduledExecutorService raftExecutor; + + public BargeThreadPools(Optional eventLoopGroup, + Optional stateMachineExecutor) { + if (eventLoopGroup.isPresent()) { + this.raftEventLoop = eventLoopGroup.get(); + this.closeEventLoop = false; + } else { + this.raftEventLoop = new NioEventLoopGroup(1, new DefaultThreadFactory("pool-raft")); + this.closeEventLoop = true; + // Runtime.getRuntime().addShutdownHook(new Thread() { + // public void run() { + // eventLoop.shutdownGracefully(); + // } + // }); + } + + this.raftExecutor = MoreExecutors.listeningDecorator(this.raftEventLoop); + + if (stateMachineExecutor.isPresent()) { + this.stateMachineExecutor = stateMachineExecutor.get(); + this.closeStateMachineExecutor = false; + } else { + this.stateMachineExecutor = MoreExecutors.listeningDecorator(Executors + .newCachedThreadPool(new DefaultThreadFactory("pool-raft-worker"))); + this.closeStateMachineExecutor = true; + // + // Runtime.getRuntime().addShutdownHook(new Thread() { + // public void run() { + // executor.shutdownNow(); + // } + // }); + } + + } + + public NioEventLoopGroup getEventLoopGroup() { + Preconditions.checkState(!closed); + return raftEventLoop; + } + + @Override + public void close() throws IOException { + if (closeEventLoop) { + raftEventLoop.shutdownGracefully(); + } + if (closeStateMachineExecutor) { + stateMachineExecutor.shutdown(); + } + closed = true; + } + + public ListeningExecutorService getStateMachineExecutor() { + Preconditions.checkState(!closed); + return stateMachineExecutor; + } + + public ListeningExecutorService getRaftExecutor() { + return raftExecutor; + } + + public ScheduledExecutorService getRaftScheduler() { + return raftExecutor; + } + +} diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java index ee2b63b..9473626 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java @@ -20,13 +20,17 @@ import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.inject.PrivateModule; + import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.util.concurrent.DefaultThreadFactory; + import org.robotninjas.barge.log.LogModule; import org.robotninjas.barge.rpc.RpcModule; import org.robotninjas.barge.state.StateModule; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; + import java.io.File; import java.util.concurrent.Executors; @@ -70,31 +74,10 @@ protected void configure() { Replica local = config.local(); install(new StateModule(local, timeout)); - final NioEventLoopGroup eventLoop; - if (eventLoopGroup.isPresent()) { - eventLoop = eventLoopGroup.get(); - } else { - eventLoop = new NioEventLoopGroup(1); - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - eventLoop.shutdownGracefully(); - } - }); - } - install(new RpcModule(local.address(), eventLoop)); - - final ListeningExecutorService executor; - if (stateMachineExecutor.isPresent()) { - executor = stateMachineExecutor.get(); - } else { - executor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - executor.shutdownNow(); - } - }); - } - install(new LogModule(logDir, stateMachine, executor)); + BargeThreadPools bargeThreadPools = new BargeThreadPools(eventLoopGroup, stateMachineExecutor); + install(new RpcModule(local.address(), bargeThreadPools)); + + install(new LogModule(logDir, stateMachine)); bind(ClusterConfig.class) .toInstance(config); diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 16498f2..4435374 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -27,7 +27,6 @@ import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.proto.RaftProto; -import org.robotninjas.barge.rpc.RaftExecutor; import org.robotninjas.barge.state.RaftStateContext; import org.robotninjas.protobuf.netty.server.RpcServer; import org.slf4j.Logger; @@ -58,10 +57,13 @@ public class RaftService extends AbstractService { private final RaftStateContext ctx; private final RaftLog raftLog; + private final BargeThreadPools bargeThreadPools; + @Inject - RaftService(@Nonnull RpcServer rpcServer, @RaftExecutor ListeningExecutorService executor, @Nonnull RaftStateContext ctx, @Nonnull RaftLog raftLog) { + RaftService(@Nonnull RpcServer rpcServer, @Nonnull BargeThreadPools bargeThreadPools, @Nonnull RaftStateContext ctx, @Nonnull RaftLog raftLog) { - this.executor = checkNotNull(executor); + this.bargeThreadPools = checkNotNull(bargeThreadPools); + this.executor = checkNotNull(bargeThreadPools.getRaftExecutor()); this.rpcServer = checkNotNull(rpcServer); this.ctx = checkNotNull(ctx); this.raftLog = raftLog; @@ -104,6 +106,7 @@ protected void doStop() { try { rpcServer.stopAsync().awaitTerminated(); + bargeThreadPools.close(); notifyStopped(); } catch (Exception e) { notifyFailed(e); diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java b/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java index d756bde..53cdfb3 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java @@ -16,15 +16,17 @@ package org.robotninjas.barge.log; -import com.google.common.util.concurrent.ListeningExecutorService; import com.google.inject.PrivateModule; import com.google.inject.Provides; import com.google.inject.Singleton; + import journal.io.api.Journal; import journal.io.api.JournalBuilder; + import org.robotninjas.barge.StateMachine; import javax.annotation.Nonnull; + import java.io.File; import java.io.IOException; @@ -35,12 +37,10 @@ public class LogModule extends PrivateModule { private final File logDirectory; private final StateMachine stateMachine; - private final ListeningExecutorService executor; - public LogModule(@Nonnull File logDirectory, @Nonnull StateMachine stateMachine, @Nonnull ListeningExecutorService executor) { + public LogModule(@Nonnull File logDirectory, @Nonnull StateMachine stateMachine) { this.logDirectory = checkNotNull(logDirectory); this.stateMachine = checkNotNull(stateMachine); - this.executor = checkNotNull(executor); } @Override @@ -49,9 +49,9 @@ protected void configure() { bind(StateMachine.class).toInstance(stateMachine); bind(StateMachineProxy.class); bind(RaftLog.class).asEagerSingleton(); - bind(ListeningExecutorService.class) - .annotatedWith(StateMachineExecutor.class) - .toInstance(executor); +// bind(ListeningExecutorService.class) +// .annotatedWith(StateMachineExecutor.class) +// .toInstance(executor); expose(RaftLog.class); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 8abcd46..fa81193 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -23,12 +23,13 @@ import com.google.common.util.concurrent.*; import com.google.inject.Inject; import com.google.protobuf.ByteString; + import journal.io.api.Journal; +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.Replica; import org.robotninjas.barge.proto.RaftEntry.Entry; import org.robotninjas.barge.proto.RaftEntry.Membership; -import org.robotninjas.barge.rpc.RaftExecutor; import org.robotninjas.barge.state.ConfigurationState; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,6 +39,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; + import java.nio.ByteBuffer; import java.util.List; import java.util.TreeMap; @@ -72,11 +74,11 @@ public class RaftLog { @Inject RaftLog(@Nonnull Journal journal, @Nonnull ConfigurationState config, - @Nonnull StateMachineProxy stateMachine, @RaftExecutor ListeningExecutorService raftThread) { + @Nonnull StateMachineProxy stateMachine, @Nonnull BargeThreadPools bargeThreadPools) { this.journal = new RaftJournal(checkNotNull(journal)); this.config = checkNotNull(config); this.stateMachine = checkNotNull(stateMachine); - this.executor = checkNotNull(raftThread); + this.executor = checkNotNull(bargeThreadPools.getRaftExecutor()); this.name = journal.getDirectory().getName(); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java b/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java index 88e181a..d1ce7b8 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java @@ -4,10 +4,13 @@ import com.google.common.collect.Queues; import com.google.common.util.concurrent.*; import com.google.inject.Inject; + +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.StateMachine; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; + import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -29,8 +32,8 @@ class StateMachineProxy { private final AtomicBoolean running; @Inject - StateMachineProxy(@Nonnull @StateMachineExecutor ListeningExecutorService executor, @Nonnull StateMachine stateMachine) { - this.executor = checkNotNull(executor); + StateMachineProxy(@Nonnull BargeThreadPools bargeThreadPools, @Nonnull StateMachine stateMachine) { + this.executor = checkNotNull(bargeThreadPools.getStateMachineExecutor()); this.stateMachine = checkNotNull(stateMachine); this.operations = Queues.newLinkedBlockingQueue(); this.running = new AtomicBoolean(false); diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftExecutor.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftExecutor.java deleted file mode 100644 index 6af6d72..0000000 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftExecutor.java +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Copyright 2013 David Rusek - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.robotninjas.barge.rpc; - -import com.google.inject.BindingAnnotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@BindingAnnotation -@Target({FIELD, PARAMETER, METHOD}) -@Retention(RUNTIME) -public @interface RaftExecutor { -} diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftScheduler.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftScheduler.java deleted file mode 100644 index 34836af..0000000 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftScheduler.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2013 David Rusek - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.robotninjas.barge.rpc; - -import com.google.inject.BindingAnnotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.*; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@BindingAnnotation -@Target({FIELD, PARAMETER, METHOD}) -@Retention(RUNTIME) -public @interface RaftScheduler { -} diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java index 1d8ff8d..cc26a3b 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java @@ -16,51 +16,52 @@ package org.robotninjas.barge.rpc; -import com.google.common.util.concurrent.ListeningExecutorService; import com.google.inject.PrivateModule; -import io.netty.channel.nio.NioEventLoopGroup; + +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.protobuf.netty.client.RpcClient; import org.robotninjas.protobuf.netty.server.RpcServer; import javax.annotation.Nonnull; + import java.net.SocketAddress; -import java.util.concurrent.ScheduledExecutorService; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; public class RpcModule extends PrivateModule { - private static final int NUM_THREADS = 1; private final SocketAddress saddr; - private final NioEventLoopGroup eventLoopGroup; + private final BargeThreadPools bargeThreadPools; - public RpcModule(@Nonnull SocketAddress saddr, NioEventLoopGroup eventLoopGroup) { + public RpcModule(@Nonnull SocketAddress saddr, BargeThreadPools bargeThreadPools) { this.saddr = checkNotNull(saddr); - this.eventLoopGroup = checkNotNull(eventLoopGroup); + this.bargeThreadPools = checkNotNull(bargeThreadPools); } @Override protected void configure() { - - bind(ListeningExecutorService.class) - .annotatedWith(RaftExecutor.class) - .toInstance(listeningDecorator(eventLoopGroup)); - - expose(ListeningExecutorService.class) - .annotatedWith(RaftExecutor.class); - - bind(ScheduledExecutorService.class) - .annotatedWith(RaftScheduler.class) - .toInstance(listeningDecorator(eventLoopGroup)); - - expose(ScheduledExecutorService.class) - .annotatedWith(RaftScheduler.class); - - bind(NioEventLoopGroup.class) - .toInstance(eventLoopGroup); - - RpcServer rpcServer = new RpcServer(eventLoopGroup, saddr); + bind(BargeThreadPools.class) + .toInstance(bargeThreadPools); + expose(BargeThreadPools.class); + +// bind(ListeningExecutorService.class) +// .annotatedWith(RaftExecutor.class) +// .toInstance(listeningDecorator(eventLoopGroup)); +// +// expose(ListeningExecutorService.class) +// .annotatedWith(RaftExecutor.class); +// +// bind(ScheduledExecutorService.class) +// .annotatedWith(RaftScheduler.class) +// .toInstance(listeningDecorator(eventLoopGroup)); +// +// expose(ScheduledExecutorService.class) +// .annotatedWith(RaftScheduler.class); +// +// bind(NioEventLoopGroup.class) +// .toInstance(eventLoopGroup); + + RpcServer rpcServer = new RpcServer(bargeThreadPools.getEventLoopGroup(), saddr); bind(RpcServer.class) .toInstance(rpcServer); expose(RpcServer.class); @@ -69,7 +70,7 @@ protected void configure() { .asEagerSingleton(); bind(RpcClient.class) - .toInstance(new RpcClient(eventLoopGroup)); + .toInstance(new RpcClient(bargeThreadPools.getEventLoopGroup())); bind(Client.class).asEagerSingleton(); expose(Client.class); diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index 610b7dd..7f4b846 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -22,13 +22,14 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; + +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.NoLeaderException; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.rpc.Client; -import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +37,7 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import javax.inject.Inject; + import java.util.List; import java.util.Random; import java.util.concurrent.ScheduledExecutorService; @@ -61,10 +63,10 @@ class Candidate extends BaseState { private ListenableFuture electionResult; @Inject - Candidate(RaftLog log, @RaftScheduler ScheduledExecutorService scheduler, + Candidate(RaftLog log, BargeThreadPools bargeThreadPools, @ElectionTimeout long electionTimeout, Client client) { this.log = log; - this.scheduler = scheduler; + this.scheduler = bargeThreadPools.getRaftScheduler(); this.electionTimeout = electionTimeout; this.client = client; } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 9d6f8c9..92e2806 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -19,6 +19,8 @@ import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; + +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.NoLeaderException; import org.robotninjas.barge.NotLeaderException; import org.robotninjas.barge.RaftException; @@ -26,13 +28,13 @@ import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; -import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; + import java.util.concurrent.ScheduledExecutorService; import static com.google.common.base.Preconditions.checkArgument; @@ -52,10 +54,10 @@ class Follower extends BaseState { private DeadlineTimer timeoutTask; @Inject - Follower(RaftLog log, @RaftScheduler ScheduledExecutorService scheduler, @ElectionTimeout @Nonnegative long timeout) { + Follower(RaftLog log, BargeThreadPools bargeThreadPools, @ElectionTimeout @Nonnegative long timeout) { this.log = checkNotNull(log); - this.scheduler = checkNotNull(scheduler); + this.scheduler = checkNotNull(bargeThreadPools.getRaftScheduler()); checkArgument(timeout >= 0); this.timeout = timeout; diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 9adb806..9d2d067 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -25,12 +25,12 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; -import org.robotninjas.barge.rpc.RaftScheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,11 +70,11 @@ class Leader extends BaseState { private ScheduledFuture heartbeatTask; @Inject - Leader(RaftLog log, @RaftScheduler ScheduledExecutorService scheduler, @ElectionTimeout @Nonnegative long timeout, + Leader(RaftLog log, BargeThreadPools bargeThreadPools, @ElectionTimeout @Nonnegative long timeout, ReplicaManagerFactory replicaManagerFactory) { this.log = checkNotNull(log); - this.scheduler = checkNotNull(scheduler); + this.scheduler = checkNotNull(bargeThreadPools.getRaftScheduler()); checkArgument(timeout > 0); this.timeout = timeout; this.replicaManagerFactory = checkNotNull(replicaManagerFactory); diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java index 8631dfc..f6a4988 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/CandidateTest.java @@ -1,10 +1,12 @@ package org.robotninjas.barge.state; import com.google.common.base.Optional; + import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.Replica; import org.robotninjas.barge.StateMachine; import org.robotninjas.barge.log.RaftLog; @@ -28,7 +30,7 @@ public class CandidateTest { private final long term = 2L; private final Replica self = Replica.fromString("localhost:1000"); - private @Mock ScheduledExecutorService mockScheduler; + private @Mock BargeThreadPools mockThreadPools; private @Mock Replica mockReplica; private @Mock Client mockRaftClient; private @Mock StateFactory mockStateFactory; @@ -53,8 +55,11 @@ public void initMocks() { when(mockRaftLog.lastLogIndex()).thenReturn(0L); when(mockRaftLog.currentTerm()).thenReturn(term); + ScheduledExecutorService mockRaftScheduler = mock(ScheduledExecutorService.class); + when(mockThreadPools.getRaftScheduler()).thenReturn(mockRaftScheduler); + ScheduledFuture mockScheduledFuture = mock(ScheduledFuture.class); - when(mockScheduler.schedule(any(Runnable.class), anyLong(), any(TimeUnit.class))) + when(mockRaftScheduler.schedule(any(Runnable.class), anyLong(), any(TimeUnit.class))) .thenReturn(mockScheduledFuture); } @@ -62,7 +67,7 @@ public void initMocks() { @Test public void testRequestVoteWithNewerTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 150, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 150, mockRaftClient); candidate.init(mockRaftStateContext); Replica mockCandidate = Replica.fromString("localhost:10001"); @@ -98,7 +103,7 @@ public void testRequestVoteWithNewerTerm() throws Exception { @Test public void testRequestVoteWithOlderTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 150, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 150, mockRaftClient); candidate.init(mockRaftStateContext); Replica mockCandidate = Replica.fromString("localhost:10001"); @@ -131,7 +136,7 @@ public void testRequestVoteWithOlderTerm() throws Exception { @Test public void testRequestVoteWithSameTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 150, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 150, mockRaftClient); candidate.init(mockRaftStateContext); Replica mockCandidate = Replica.fromString("localhost:10001"); @@ -166,7 +171,7 @@ public void testRequestVoteWithSameTerm() throws Exception { @Test public void testAppendEntriesWithNewerTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 1, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 1, mockRaftClient); candidate.init(mockRaftStateContext); Replica mockLeader = Replica.fromString("localhost:10001"); @@ -203,7 +208,7 @@ public void testAppendEntriesWithNewerTerm() throws Exception { @Test public void testAppendEntriesWithOlderTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 1, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 1, mockRaftClient); candidate.init(mockRaftStateContext); Replica mockLeader = Replica.fromString("localhost:10001"); @@ -238,7 +243,7 @@ public void testAppendEntriesWithOlderTerm() throws Exception { @Test public void testAppendEntriesWithSameTerm() throws Exception { - Candidate candidate = new Candidate(mockRaftLog, mockScheduler, 1, mockRaftClient); + Candidate candidate = new Candidate(mockRaftLog, mockThreadPools, 1, mockRaftClient); candidate.init(mockRaftStateContext); AppendEntries request = From e21ffb9456d9469a40dff509a830bb0cf155e5f9 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:22:26 -0500 Subject: [PATCH 11/26] Add isEmpty function to log So we know if it's safe to bootstrap, without having to replay --- .../src/main/java/org/robotninjas/barge/RaftService.java | 2 +- .../src/main/java/org/robotninjas/barge/log/RaftJournal.java | 4 ++++ .../src/main/java/org/robotninjas/barge/log/RaftLog.java | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 4435374..a6f16ac 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -73,7 +73,7 @@ public class RaftService extends AbstractService { public void bootstrap(Membership membership) { LOGGER.info("Bootstrapping log with {}", membership); - if (raftLog.lastLogTerm() != 0 || raftLog.lastLogIndex() != 0) { + if (!raftLog.isEmpty()) { LOGGER.warn("Cannot bootstrap, as raft log already contains data"); throw new IllegalStateException(); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java index 49a1a34..ea5c6f4 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java @@ -27,6 +27,10 @@ public RaftJournal(Journal journal) { this.journal = journal; } + public boolean isEmpty() { + return journal.getFiles().isEmpty(); + } + public void init() { try { diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index fa81193..2f69c69 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -302,4 +302,8 @@ public String getName() { return name; } + public boolean isEmpty() { + return journal.isEmpty(); + } + } From 585acfcedf5c072db284d6038d5b2a16a178cfc6 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:23:21 -0500 Subject: [PATCH 12/26] Add STOPPED state to RaftStateContext And close everything down more cleanly --- .../org/robotninjas/barge/RaftService.java | 6 ++++ .../robotninjas/barge/log/RaftJournal.java | 4 +++ .../org/robotninjas/barge/log/RaftLog.java | 4 +++ .../barge/state/RaftStateContext.java | 32 ++++++++++++++++--- 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index a6f16ac..0593f7e 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -106,6 +106,12 @@ protected void doStop() { try { rpcServer.stopAsync().awaitTerminated(); + ctx.stop(); + while (!ctx.isStopped()) { + Thread.sleep(10); + } + raftLog.close(); + bargeThreadPools.close(); notifyStopped(); } catch (Exception e) { diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java index ea5c6f4..7604071 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftJournal.java @@ -27,6 +27,10 @@ public RaftJournal(Journal journal) { this.journal = journal; } + public void close() throws IOException { + this.journal.close(); + } + public boolean isEmpty() { return journal.getFiles().isEmpty(); } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 2f69c69..b170bac 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -83,6 +83,10 @@ public class RaftLog { this.name = journal.getDirectory().getName(); } + public void close() throws IOException { + this.journal.close(); + } + public void load() { LOGGER.info("Replaying log"); diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java index a104073..5376585 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java @@ -33,7 +33,7 @@ @NotThreadSafe public class RaftStateContext { - public enum StateType {START, FOLLOWER, CANDIDATE, LEADER} + public enum StateType {START, FOLLOWER, CANDIDATE, LEADER,STOPPED} private static final Logger LOGGER = LoggerFactory.getLogger(RaftStateContext.class); @@ -42,6 +42,8 @@ public enum StateType {START, FOLLOWER, CANDIDATE, LEADER} private volatile State delegate; private final ConfigurationState configurationState; + private boolean stop; + @Inject RaftStateContext(StateFactory stateFactory, ConfigurationState configurationState) { this.stateFactory = stateFactory; @@ -82,8 +84,13 @@ public synchronized void setState(@Nonnull State oldState, @Nonnull StateType st } LOGGER.info("old state: {}, new state: {}", this.state, state); - this.state = checkNotNull(state); - switch (state) { + if (stop) { + this.state = StateType.STOPPED; + LOGGER.info("Service stopped; replaced state with: {}", this.state); + } else { + this.state = checkNotNull(state); + } + switch (this.state) { case START: delegate = stateFactory.start(); break; @@ -96,9 +103,14 @@ public synchronized void setState(@Nonnull State oldState, @Nonnull StateType st case CANDIDATE: delegate = stateFactory.candidate(); break; + case STOPPED: + delegate = null; + break; } MDC.put("state", this.state.toString()); - delegate.init(this); + if (delegate != null) { + delegate.init(this); + } } @Nonnull @@ -110,4 +122,16 @@ public StateType getState() { public ConfigurationState getConfigurationState() { return configurationState; } + + public synchronized boolean shouldStop() { + return stop; + } + + public synchronized void stop() { + stop = true; + } + + public synchronized boolean isStopped() { + return this.state == StateType.STOPPED; + } } From 43a9c9fcb7af0a96a07d375c0c8333fb3db063ac Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:23:48 -0500 Subject: [PATCH 13/26] Particularly on reply, we may not have a future for the operation --- .../java/org/robotninjas/barge/log/RaftLog.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index b170bac..c51b92a 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -23,9 +23,7 @@ import com.google.common.util.concurrent.*; import com.google.inject.Inject; import com.google.protobuf.ByteString; - import journal.io.api.Journal; - import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.Replica; import org.robotninjas.barge.proto.RaftEntry.Entry; @@ -34,17 +32,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; - import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; - +import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; import java.util.TreeMap; import java.util.concurrent.ConcurrentMap; - import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; @@ -220,6 +216,15 @@ void fireComitted() { } if (!entry.hasMembership() && !entry.hasCommand()){ + if (returnedResult != null) { + Futures.addCallback(returnedResult, new PromiseBridge(returnedResult)); + } + // TODO: If this fails during replay, what should we do? + } else if (entry.hasMembership()) { + if (returnedResult != null) { + returnedResult.set(Boolean.TRUE); + } + } else { LOGGER.warn("Ignoring unusual log entry: {}", entry); } } From 850e1e7a4672ef8f9d81ddecc04bc8d7e77e29e9 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:24:11 -0500 Subject: [PATCH 14/26] Add Follower.toString --- .../src/main/java/org/robotninjas/barge/state/Follower.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 92e2806..3d2d5ee 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -157,5 +157,9 @@ public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMemb throw throwMustBeLeader(); } + @Override + public String toString() { + return "Follower [" + log.getName() + " @ " + log.self() + "]"; + } } From 6dbc7ba2cbed0d7dd4c2b2b3a0c2af625eb77f8d Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 13:25:28 -0500 Subject: [PATCH 15/26] Stop leader when Raft is stopped Otherwise won't stop when have no peers --- .../src/main/java/org/robotninjas/barge/state/Leader.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 9d2d067..2ef045c 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -117,7 +117,9 @@ private ReplicaManager getReplicaManager(RaftStateContext ctx, Replica replica) } private void stepDown(RaftStateContext ctx) { - heartbeatTask.cancel(false); + if (heartbeatTask != null) { + heartbeatTask.cancel(false); + } for (ReplicaManager mgr : replicaManagers.values()) { mgr.shutdown(); } @@ -333,6 +335,10 @@ private void checkTermOnResponse(RaftStateContext ctx, AppendEntriesResponse res @Nonnull @VisibleForTesting List> sendRequests(final RaftStateContext ctx) { + if (ctx.shouldStop()) { + stepDown(ctx); + return null; + } List> responses = newArrayList(); Replica self = ctx.getConfigurationState().self(); for (Replica replica : ctx.getConfigurationState().getAllVotingMembers()) { From 6e23af8e26318e44a8b3157d3a652cdf6e47ed58 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 15 Jan 2014 19:20:34 -0500 Subject: [PATCH 16/26] Wait for log replay to complete before proceeding --- .../java/org/robotninjas/barge/log/RaftLog.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index c51b92a..173c918 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -89,6 +89,8 @@ public void load() { journal.init(); + long oldCommitIndex = commitIndex; + journal.replay(new RaftJournal.Visitor() { @Override public void term(long term) { @@ -117,8 +119,20 @@ public void append(Entry entry, long index) { } }); + final SettableFuture lastResult; + if (oldCommitIndex != commitIndex) { + lastResult = SettableFuture.create(); + operationResults.put(commitIndex, lastResult); + } else { + lastResult = null; + } + fireComitted(); + if (lastResult != null) { + Futures.getUnchecked(lastResult); + } + LOGGER.info("Finished replaying log lastIndex {}, currentTerm {}, commitIndex {}, lastVotedFor {}", lastLogIndex, currentTerm, commitIndex, votedFor.orNull()); } From 24630f0495afc7edd1759c4d75c476a718cacef3 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Thu, 16 Jan 2014 10:08:48 -0500 Subject: [PATCH 17/26] Use a single thread for the state machine executor --- .../src/main/java/org/robotninjas/barge/BargeThreadPools.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java b/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java index 61b7089..98793a5 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java +++ b/barge-core/src/main/java/org/robotninjas/barge/BargeThreadPools.java @@ -46,8 +46,8 @@ public BargeThreadPools(Optional eventLoopGroup, this.stateMachineExecutor = stateMachineExecutor.get(); this.closeStateMachineExecutor = false; } else { - this.stateMachineExecutor = MoreExecutors.listeningDecorator(Executors - .newCachedThreadPool(new DefaultThreadFactory("pool-raft-worker"))); + this.stateMachineExecutor = MoreExecutors.listeningDecorator( + Executors.newSingleThreadExecutor(new DefaultThreadFactory("pool-raft-worker"))); this.closeStateMachineExecutor = true; // // Runtime.getRuntime().addShutdownHook(new Thread() { From 795502627ff171df8709038306cdf2affc6aa1ea Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Thu, 16 Jan 2014 10:10:13 -0500 Subject: [PATCH 18/26] Add isLeader method --- .../src/main/java/org/robotninjas/barge/RaftService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 0593f7e..15410d9 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -28,6 +28,7 @@ import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.proto.RaftProto; import org.robotninjas.barge.state.RaftStateContext; +import org.robotninjas.barge.state.RaftStateContext.StateType; import org.robotninjas.protobuf.netty.server.RpcServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -223,5 +224,9 @@ public String getServerKey() { return ctx.getConfigurationState().self().getKey(); } + public boolean isLeader() { + return ctx.getState() == StateType.LEADER; + } + } From a7f7a9d6f2e5b41d411544880bb53197d27f1a8e Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Thu, 16 Jan 2014 10:10:37 -0500 Subject: [PATCH 19/26] Add note about firing commit more often --- barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 173c918..22c4f26 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -91,6 +91,8 @@ public void load() { long oldCommitIndex = commitIndex; + // TODO: fireCommitted more often?? + journal.replay(new RaftJournal.Visitor() { @Override public void term(long term) { From f2aeff242eb0f1ed038f1e28fecb4e0d89e03ca1 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Thu, 16 Jan 2014 10:10:57 -0500 Subject: [PATCH 20/26] Remove (unused) StateMachineExecutor --- .../barge/log/StateMachineExecutor.java | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 barge-core/src/main/java/org/robotninjas/barge/log/StateMachineExecutor.java diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineExecutor.java b/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineExecutor.java deleted file mode 100644 index c5b7e5e..0000000 --- a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineExecutor.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.robotninjas.barge.log; - -import com.google.inject.BindingAnnotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@BindingAnnotation -@Target({FIELD, PARAMETER, METHOD}) -@Retention(RUNTIME) -@interface StateMachineExecutor { -} From 6cf8e6d60052e0cd18aa170e2ae61a211cb411fe Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Thu, 16 Jan 2014 10:11:34 -0500 Subject: [PATCH 21/26] Remove some unused imports --- .../src/main/java/org/robotninjas/barge/state/Follower.java | 1 - barge-core/src/main/java/org/robotninjas/barge/state/Start.java | 1 - barge-core/src/main/java/org/robotninjas/barge/state/State.java | 1 - 3 files changed, 3 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 3d2d5ee..4c3031d 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -27,7 +27,6 @@ import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; import org.robotninjas.barge.log.RaftLog; -import org.robotninjas.barge.proto.RaftEntry.Membership; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java index b4af635..2c96bd9 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java @@ -5,7 +5,6 @@ import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.log.RaftLog; -import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; import static com.google.inject.internal.util.$Preconditions.checkNotNull; import static org.robotninjas.barge.proto.RaftProto.*; diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/State.java b/barge-core/src/main/java/org/robotninjas/barge/state/State.java index d63f438..19e8db4 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/State.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/State.java @@ -19,7 +19,6 @@ import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; -import org.robotninjas.barge.proto.RaftEntry.Membership; import javax.annotation.Nonnull; From eb696d96d73b5a36f67142f67b611a2626f11e40 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Wed, 29 Jan 2014 12:10:18 -0500 Subject: [PATCH 22/26] Track and expose cluster health at the leader --- .../robotninjas/barge/RaftClusterHealth.java | 23 ++++++++++++++ .../org/robotninjas/barge/RaftModule.java | 6 ---- .../org/robotninjas/barge/RaftService.java | 14 ++++++++- .../org/robotninjas/barge/log/LogModule.java | 3 -- .../org/robotninjas/barge/log/RaftLog.java | 2 ++ .../barge/log/StateMachineProxy.java | 2 -- .../org/robotninjas/barge/rpc/RaftClient.java | 1 - .../org/robotninjas/barge/rpc/RpcModule.java | 2 -- .../robotninjas/barge/state/Candidate.java | 8 +++-- .../org/robotninjas/barge/state/Follower.java | 8 +++-- .../org/robotninjas/barge/state/Leader.java | 31 +++++++++++++++++++ .../barge/state/RaftStateContext.java | 5 +++ .../barge/state/ReplicaManager.java | 10 ++++++ .../org/robotninjas/barge/state/Start.java | 6 ++++ .../org/robotninjas/barge/state/State.java | 3 ++ .../barge/state/BaseStateTest.java | 6 ++++ 16 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 barge-core/src/main/java/org/robotninjas/barge/RaftClusterHealth.java diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftClusterHealth.java b/barge-core/src/main/java/org/robotninjas/barge/RaftClusterHealth.java new file mode 100644 index 0000000..23a1cba --- /dev/null +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftClusterHealth.java @@ -0,0 +1,23 @@ +package org.robotninjas.barge; + +import java.util.List; + +public class RaftClusterHealth { + + final RaftMembership membership; + final List deadPeers; + + public RaftClusterHealth(RaftMembership membership, List deadPeers) { + this.membership = membership; + this.deadPeers = deadPeers; + } + + public RaftMembership getClusterMembership() { + return membership; + } + + public List getDeadPeers() { + return deadPeers; + } + +} diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java index 9473626..8a6c1f4 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftModule.java @@ -18,21 +18,15 @@ import com.google.common.base.Optional; import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import com.google.inject.PrivateModule; - import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.util.concurrent.DefaultThreadFactory; - import org.robotninjas.barge.log.LogModule; import org.robotninjas.barge.rpc.RpcModule; import org.robotninjas.barge.state.StateModule; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; - import java.io.File; -import java.util.concurrent.Executors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 15410d9..1b65bda 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -23,7 +23,6 @@ import com.google.inject.Injector; import com.google.protobuf.Service; import io.netty.channel.nio.NioEventLoopGroup; - import org.robotninjas.barge.log.RaftLog; import org.robotninjas.barge.proto.RaftEntry.Membership; import org.robotninjas.barge.proto.RaftProto; @@ -228,5 +227,18 @@ public boolean isLeader() { return ctx.getState() == StateType.LEADER; } + public RaftClusterHealth getClusterHealth() throws RaftException { + + // Make sure this happens on the Barge thread + ListenableFuture response = executor.submit(new Callable() { + @Override + public RaftClusterHealth call() throws Exception { + return ctx.getClusterHealth(); + } + }); + + return Futures.get(response, RaftException.class); + + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java b/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java index 53cdfb3..8a23b9d 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/LogModule.java @@ -19,14 +19,11 @@ import com.google.inject.PrivateModule; import com.google.inject.Provides; import com.google.inject.Singleton; - import journal.io.api.Journal; import journal.io.api.JournalBuilder; - import org.robotninjas.barge.StateMachine; import javax.annotation.Nonnull; - import java.io.File; import java.io.IOException; diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 22c4f26..11170ae 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -32,6 +32,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.slf4j.MDC; + import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -41,6 +42,7 @@ import java.util.List; import java.util.TreeMap; import java.util.concurrent.ConcurrentMap; + import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Throwables.propagate; diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java b/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java index d1ce7b8..0784583 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/StateMachineProxy.java @@ -4,13 +4,11 @@ import com.google.common.collect.Queues; import com.google.common.util.concurrent.*; import com.google.inject.Inject; - import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.StateMachine; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; - import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java index f958e52..ebe9e86 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java +++ b/barge-core/src/main/java/org/robotninjas/barge/rpc/RaftClient.java @@ -21,7 +21,6 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.RpcCallback; import com.google.protobuf.RpcController; - import org.apache.commons.pool.ObjectPool; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.Replica; diff --git a/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java b/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java index cc26a3b..09ca36f 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java +++ b/barge-core/src/main/java/org/robotninjas/barge/rpc/RpcModule.java @@ -17,13 +17,11 @@ package org.robotninjas.barge.rpc; import com.google.inject.PrivateModule; - import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.protobuf.netty.client.RpcClient; import org.robotninjas.protobuf.netty.server.RpcServer; import javax.annotation.Nonnull; - import java.net.SocketAddress; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java index 7f4b846..ac985d5 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Candidate.java @@ -22,9 +22,9 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; - import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.NoLeaderException; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; @@ -37,7 +37,6 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import javax.inject.Inject; - import java.util.List; import java.util.Random; import java.util.concurrent.ScheduledExecutorService; @@ -235,6 +234,11 @@ public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMemb throw new NoLeaderException(); } + @Override + public RaftClusterHealth getClusterHealth(@Nonnull RaftStateContext ctx) throws NoLeaderException { + throw new NoLeaderException(); + } + @Override public String toString() { return "Candidate [" + log.getName() + " @ " + log.self() + "]"; diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 4c3031d..1e9bce2 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -19,10 +19,10 @@ import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; - import org.robotninjas.barge.BargeThreadPools; import org.robotninjas.barge.NoLeaderException; import org.robotninjas.barge.NotLeaderException; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; @@ -33,7 +33,6 @@ import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.concurrent.NotThreadSafe; - import java.util.concurrent.ScheduledExecutorService; import static com.google.common.base.Preconditions.checkArgument; @@ -155,6 +154,11 @@ public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMemb RaftMembership newMembership) throws RaftException { throw throwMustBeLeader(); } + + @Override + public RaftClusterHealth getClusterHealth(@Nonnull RaftStateContext ctx) throws RaftException { + throw throwMustBeLeader(); + } @Override public String toString() { diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index 2ef045c..c6eb837 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -26,6 +26,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import org.robotninjas.barge.BargeThreadPools; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; @@ -61,6 +62,8 @@ class Leader extends BaseState { private static final Logger LOGGER = LoggerFactory.getLogger(Leader.class); + private static final long HEALTH_TIMEOUT = TimeUnit.MINUTES.toNanos(1); + private final RaftLog log; private final ScheduledExecutorService scheduler; private final long timeout; @@ -447,4 +450,32 @@ public String toString() { return "Leader [" + log.getName() + " @ " + log.self() + "]"; } + @Override + public RaftClusterHealth getClusterHealth(final RaftStateContext ctx) { + ConfigurationState configurationState = ctx.getConfigurationState(); + if (configurationState.isTransitional()) { + return null; + } + + List deadPeers = Lists.newArrayList(); + + Replica self = log.self(); + for (Replica replica : configurationState.getAllVotingMembers()) { + if (replica == self) { + continue; + } + + ReplicaManager replicaManager = getReplicaManager(ctx, replica); + long now = System.nanoTime(); + long lastSeen = replicaManager.getLastProofOfLife(); + if ((now - lastSeen) > HEALTH_TIMEOUT) { + deadPeers.add(replica); + } + } + + RaftMembership membership = configurationState.getClusterMembership(); + RaftClusterHealth health = new RaftClusterHealth(membership, deadPeers); + return health; + } + } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java index 5376585..da77131 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java @@ -17,6 +17,7 @@ package org.robotninjas.barge.state; import com.google.common.util.concurrent.ListenableFuture; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.slf4j.Logger; @@ -134,4 +135,8 @@ public synchronized void stop() { public synchronized boolean isStopped() { return this.state == StateType.STOPPED; } + + public RaftClusterHealth getClusterHealth() throws RaftException { + return delegate.getClusterHealth(this); + } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/ReplicaManager.java b/barge-core/src/main/java/org/robotninjas/barge/state/ReplicaManager.java index 559fbbc..d7df579 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/ReplicaManager.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/ReplicaManager.java @@ -59,6 +59,7 @@ class ReplicaManager { private boolean forwards = false; private boolean shutdown = false; private SettableFuture nextResponse = SettableFuture.create(); + private volatile long lastResponse; @Inject ReplicaManager(Client client, RaftLog log, @Assisted Replica remote) { @@ -106,6 +107,7 @@ public void onSuccess(@Nullable AppendEntriesResponse result) { if (result.getSuccess()) { previousResponse.set(result); } + updateLastResponse(); } @Override @@ -123,6 +125,14 @@ public void onFailure(Throwable t) { } + protected void updateLastResponse() { + lastResponse = System.nanoTime(); + } + + public long getLastProofOfLife() { + return lastResponse; + } + private void updateNextIndex(@Nonnull AppendEntries request, @Nonnull AppendEntriesResponse response) { boolean runAgain = requested || !response.getSuccess(); diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java index 2c96bd9..53eb93f 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Start.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Start.java @@ -2,6 +2,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.inject.Inject; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.log.RaftLog; @@ -43,6 +44,11 @@ public ListenableFuture commitOperation(@Nonnull RaftStateContext ctx, @ throw new RaftException("Service has not started yet"); } + @Override + public RaftClusterHealth getClusterHealth(@Nonnull RaftStateContext ctx) throws RaftException { + throw new RaftException("Service has not started yet"); + } + @Override public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMembership oldMembership, RaftMembership newMembership) throws RaftException { diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/State.java b/barge-core/src/main/java/org/robotninjas/barge/state/State.java index 19e8db4..a5113e0 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/State.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/State.java @@ -17,6 +17,7 @@ package org.robotninjas.barge.state; import com.google.common.util.concurrent.ListenableFuture; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; @@ -40,4 +41,6 @@ interface State { @Nonnull ListenableFuture setConfiguration(@Nonnull RaftStateContext ctx, @Nonnull RaftMembership oldMembership, @Nonnull RaftMembership newMembership) throws RaftException; + RaftClusterHealth getClusterHealth(@Nonnull RaftStateContext ctx) throws RaftException; + } diff --git a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java index ed16f20..087e5c3 100644 --- a/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java +++ b/barge-core/src/test/java/org/robotninjas/barge/state/BaseStateTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robotninjas.barge.RaftClusterHealth; import org.robotninjas.barge.RaftException; import org.robotninjas.barge.RaftMembership; import org.robotninjas.barge.Replica; @@ -184,6 +185,11 @@ public ListenableFuture setConfiguration(RaftStateContext ctx, RaftMemb return null; } + @Override + public RaftClusterHealth getClusterHealth(RaftStateContext ctx) { + return null; + } + } } From 6dcc4fa69fa866804748765db55684b38664f394 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 31 Jan 2014 00:08:39 -0500 Subject: [PATCH 23/26] Add isUnitialized function to help with bootstrapping --- .../src/main/java/org/robotninjas/barge/RaftService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java index 1b65bda..07ef2c9 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/RaftService.java +++ b/barge-core/src/main/java/org/robotninjas/barge/RaftService.java @@ -241,4 +241,8 @@ public RaftClusterHealth call() throws Exception { } + public boolean isUninitialized() { + return raftLog.isEmpty(); + } + } From c687584e5226af8335e381ba68e26e901627b532 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 31 Jan 2014 00:09:17 -0500 Subject: [PATCH 24/26] Fix logic with RaftLog callbacks Got broken in all the rebasing! --- .../main/java/org/robotninjas/barge/log/RaftLog.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java index 11170ae..a47aa66 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java +++ b/barge-core/src/main/java/org/robotninjas/barge/log/RaftLog.java @@ -220,24 +220,21 @@ void fireComitted() { for (long i = lastApplied + 1; i <= Math.min(commitIndex, lastLogIndex); ++i, ++lastApplied) { Entry entry = log.get(i); + // returnedResult may be null during log replay final SettableFuture returnedResult = operationResults.remove(i); - assert returnedResult != null; if (entry.hasCommand()) { + assert !entry.hasMembership(); + ByteString command = entry.getCommand(); // byte[] rawCommand = command.toByteArray(); // final ByteBuffer operation = ByteBuffer.wrap(rawCommand).asReadOnlyBuffer(); final ByteBuffer operation = command.asReadOnlyByteBuffer(); ListenableFuture result = stateMachine.dispatchOperation(operation); - Futures.addCallback(result, new PromiseBridge(returnedResult)); - } - - if (!entry.hasMembership() && !entry.hasCommand()){ if (returnedResult != null) { - Futures.addCallback(returnedResult, new PromiseBridge(returnedResult)); + Futures.addCallback(result, new PromiseBridge(returnedResult)); } - // TODO: If this fails during replay, what should we do? } else if (entry.hasMembership()) { if (returnedResult != null) { returnedResult.set(Boolean.TRUE); From d53047a42ebdc66ce1633b9d24b2144c5b90a1b3 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 31 Jan 2014 00:10:24 -0500 Subject: [PATCH 25/26] More verbose logging --- .../org/robotninjas/barge/state/DeadlineTimer.java | 14 ++++++++++++-- .../java/org/robotninjas/barge/state/Follower.java | 2 +- .../java/org/robotninjas/barge/state/Leader.java | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/DeadlineTimer.java b/barge-core/src/main/java/org/robotninjas/barge/state/DeadlineTimer.java index 3c8c8e9..a7a6436 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/DeadlineTimer.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/DeadlineTimer.java @@ -3,6 +3,8 @@ import com.google.common.base.Optional; import javax.annotation.concurrent.NotThreadSafe; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; @@ -12,6 +14,8 @@ @NotThreadSafe class DeadlineTimer { + private static final Logger LOGGER = LoggerFactory.getLogger(DeadlineTimer.class); + private final ScheduledExecutorService scheduler; private final Runnable action; private final long timeout; @@ -34,7 +38,10 @@ public void start() { public void reset() { checkState(started); if (future.isPresent()) { - future.get().cancel(false); + boolean cancelled = future.get().cancel(false); + if (!cancelled) { + LOGGER.error("Unable to cancel execution of task"); + } } future = Optional.of(scheduler.schedule(action, timeout, MILLISECONDS)); } @@ -42,7 +49,10 @@ public void reset() { public void cancel() { checkState(started); if (future.isPresent()) { - future.get().cancel(false); + boolean cancelled = future.get().cancel(false); + if (!cancelled) { + LOGGER.error("Unable to cancel execution of task"); + } } } diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java index 1e9bce2..e660213 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Follower.java @@ -66,7 +66,7 @@ public void init(@Nonnull final RaftStateContext ctx) { timeoutTask = DeadlineTimer.start(scheduler, new Runnable() { @Override public void run() { - LOGGER.debug("DeadlineTimer expired, starting election"); + LOGGER.info("DeadlineTimer expired, starting election"); ctx.setState(Follower.this, CANDIDATE); } }, timeout * 2); diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java index c6eb837..48279c7 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/Leader.java @@ -120,6 +120,8 @@ private ReplicaManager getReplicaManager(RaftStateContext ctx, Replica replica) } private void stepDown(RaftStateContext ctx) { + LOGGER.info("Stepping down from leadership"); + if (heartbeatTask != null) { heartbeatTask.cancel(false); } @@ -138,6 +140,7 @@ public RequestVoteResponse requestVote(@Nonnull RaftStateContext ctx, @Nonnull R boolean voteGranted = false; if (request.getTerm() > log.currentTerm()) { + LOGGER.info("Got request-for-vote with newer term; stepping down: {}", request); log.currentTerm(request.getTerm()); stepDown(ctx); @@ -172,6 +175,7 @@ public AppendEntriesResponse appendEntries(@Nonnull RaftStateContext ctx, @Nonnu } if (request.getTerm() > currentTerm) { + LOGGER.info("Caller has newer term; stepping down: {}", request); log.currentTerm(request.getTerm()); stepDown(ctx); success = log.append(request); From 99b3e9a3c27f99207f02708ea556d973782f4056 Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Fri, 31 Jan 2014 00:11:34 -0500 Subject: [PATCH 26/26] Add STOPPED state --- .../main/java/org/robotninjas/barge/state/RaftStateContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java index da77131..111d630 100644 --- a/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java +++ b/barge-core/src/main/java/org/robotninjas/barge/state/RaftStateContext.java @@ -34,7 +34,7 @@ @NotThreadSafe public class RaftStateContext { - public enum StateType {START, FOLLOWER, CANDIDATE, LEADER,STOPPED} + public enum StateType {START, FOLLOWER, CANDIDATE, LEADER, STOPPED} private static final Logger LOGGER = LoggerFactory.getLogger(RaftStateContext.class);