/* * Copyright 2014 WANdisco * * WANdisco licenses this file to you 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 c5db.replication; import c5db.interfaces.replication.IndexCommitNotice; import c5db.interfaces.replication.QuorumConfiguration; import c5db.interfaces.replication.Replicator; import c5db.interfaces.replication.ReplicatorInstanceEvent; import c5db.interfaces.replication.ReplicatorReceipt; import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import org.jetlang.channels.Channel; import org.jetlang.channels.MemoryChannel; import org.jetlang.channels.Subscriber; import org.jetlang.fibers.Fiber; import java.nio.ByteBuffer; import java.util.Collection; import java.util.List; public class SingleNodeFakeReplicator implements Replicator { private final long nodeId; private final String quorumId; private final Channel<State> stateChannel = new MemoryChannel<>(); private final Channel<ReplicatorInstanceEvent> eventChannel = new MemoryChannel<>(); private final Channel<IndexCommitNotice> commitNoticeChannel = new MemoryChannel<>(); private final Fiber fiber; private long nextSeqNum = 1; private long term = 1; private State state = State.FOLLOWER; public SingleNodeFakeReplicator(Fiber fiber, long nodeId, String quorumId) { this.fiber = fiber; this.nodeId = nodeId; this.quorumId = quorumId; } @Override public String getQuorumId() { return quorumId; } @Override public ListenableFuture<QuorumConfiguration> getQuorumConfiguration() { return Futures.immediateFuture( QuorumConfiguration.of( Sets.newHashSet(nodeId))); } @Override public ListenableFuture<ReplicatorReceipt> changeQuorum(Collection<Long> newPeers) throws InterruptedException { throw new UnsupportedOperationException(); } @Override public synchronized ListenableFuture<ReplicatorReceipt> logData(List<ByteBuffer> data) { SettableFuture<ReplicatorReceipt> receiptFuture = SettableFuture.create(); final long thisSeqNum = nextSeqNum; nextSeqNum++; doLater(() -> { receiptFuture.set(new ReplicatorReceipt(term, thisSeqNum)); doLater(() -> commitNoticeChannel.publish(new IndexCommitNotice(quorumId, nodeId, thisSeqNum, thisSeqNum, term))); }); return receiptFuture; } @Override public long getId() { return nodeId; } public void start() { state = State.LEADER; doLater(() -> stateChannel.publish(state)); } @Override public Subscriber<State> getStateChannel() { return stateChannel; } @Override public Subscriber<ReplicatorInstanceEvent> getEventChannel() { return eventChannel; } @Override public Subscriber<IndexCommitNotice> getCommitNoticeChannel() { return commitNoticeChannel; } private void doLater(Runnable runnable) { fiber.execute(runnable); } }