/** * De-serialize the data stored in buffer to cluster configuration * this is used for the peers to get the cluster configuration from log entry value * @param data the binary data * @return cluster configuration */ public static ClusterConfiguration fromBytes(byte[] data){ return fromBytes(ByteBuffer.wrap(data)); }
private void removeServerFromCluster(int serverId){ ClusterConfiguration newConfig = new ClusterConfiguration(); newConfig.setLastLogIndex(this.config.getLogIndex()); newConfig.setLogIndex(this.logStore.getFirstAvailableIndex()); for(ClusterServer server: this.config.getServers()){ if(server.getId() != serverId){ newConfig.getServers().add(server); } } this.logger.info("removed a server from configuration and save the configuration to log store at %d", newConfig.getLogIndex()); this.configChanging = true; this.logStore.append(new LogEntry(this.state.getTerm(), newConfig.toBytes(), LogValueType.Configuration)); this.requestAppendEntries(); }
public static ClusterConfiguration fromBytes(ByteBuffer buffer){ ClusterConfiguration configuration = new ClusterConfiguration(); configuration.setLogIndex(buffer.getLong()); configuration.setLastLogIndex(buffer.getLong()); while(buffer.hasRemaining()){ configuration.getServers().add(new ClusterServer(buffer)); } return configuration; }
private void reconfigure(ClusterConfiguration newConfig){ this.logger.debug( "system is reconfigured to have %d servers, last config index: %d, this config index: %d", newConfig.getServers().size(), newConfig.getLastLogIndex(), newConfig.getLogIndex()); List<Integer> serversRemoved = new LinkedList<Integer>(); List<ClusterServer> serversAdded = new LinkedList<ClusterServer>(); for(ClusterServer s : newConfig.getServers()){ if(!this.peers.containsKey(s.getId()) && s.getId() != this.id){ serversAdded.add(s); if(newConfig.getServer(id.intValue()) == null){ serversRemoved.add(id); if(newConfig.getServer(this.id) == null){ serversRemoved.add(this.id);
}else if(logEntry.getValueType() == LogValueType.Configuration){ synchronized(server){ ClusterConfiguration newConfig = ClusterConfiguration.fromBytes(logEntry.getValue()); server.logger.info("configuration at index %d is committed", newConfig.getLogIndex()); server.context.getServerStateManager().saveClusterConfiguration(newConfig); server.configChanging = false; if(server.config.getLogIndex() < newConfig.getLogIndex()){ server.reconfigure(newConfig); if(server.catchingUp && newConfig.getServer(server.id) != null){ server.logger.info("this server is committed as one of cluster members"); server.catchingUp = false;
private void becomeLeader(){ this.stopElectionTimer(); this.role = ServerRole.Leader; this.leader = this.id; this.serverToJoin = null; for(PeerServer server : this.peers.values()){ server.setNextLogIndex(this.logStore.getFirstAvailableIndex()); server.setSnapshotInSync(null); server.setFree(); this.enableHeartbeatForPeer(server); } // if current config is not committed, try to commit it if(this.config.getLogIndex() == 0){ this.config.setLogIndex(this.logStore.getFirstAvailableIndex()); this.logStore.append(new LogEntry(this.state.getTerm(), this.config.toBytes(), LogValueType.Configuration)); this.logger.info("add initial configuration to log store"); this.configChanging = true; } this.requestAppendEntries(); }
while(config.getLogIndex() > indexCommitted && config.getLastLogIndex() >= this.logStore.getStartIndex()){ config = ClusterConfiguration.fromBytes(this.logStore.getLogEntryAt(config.getLastLogIndex()).getValue()); if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() > 0 && config.getLastLogIndex() < this.logStore.getStartIndex()){ Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(lastSnapshot == null){ }else if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() == 0){ this.logger.error("BUG!!! stop the system, there must be a configuration at index one"); System.exit(-1);
public byte[] toBytes(){ byte[] configData = this.snapshot.getLastConfig().toBytes(); int size = Long.BYTES * 3 + configData.length + Integer.BYTES * 2 + data.length + 1; ByteBuffer buffer = ByteBuffer.allocate(size); buffer.putLong(snapshot.getLastLogIndex()); buffer.putLong(snapshot.getLastLogTerm()); buffer.putInt(configData.length); buffer.put(configData); buffer.putLong(this.offset); buffer.putInt(this.data.length); buffer.put(this.data); buffer.put(this.done ? (byte)1 : (byte)0); return buffer.array(); }
if(--this.steppingDown == 0){ this.logger.info("no hearing further news from leader, remove this server from config and step down"); ClusterServer server = this.config.getServer(this.id); if(server != null){ this.config.getServers().remove(server); this.context.getServerStateManager().saveClusterConfiguration(this.config);
RpcClient rpcClient = this.rpcClients.get(leaderId); if(rpcClient == null){ ClusterServer leader = config.getServer(leaderId); if(leader == null){ result.complete(false);
public RaftClient(RpcClientFactory rpcClientFactory, ClusterConfiguration configuration, LoggerFactory loggerFactory){ this.random = new Random(Calendar.getInstance().getTimeInMillis()); this.rpcClientFactory = rpcClientFactory; this.configuration = configuration; this.leaderId = configuration.getServers().get(this.random.nextInt(configuration.getServers().size())).getId(); this.randomLeader = true; this.logger = loggerFactory.getLogger(getClass()); this.timer = new Timer(); }
this.stateMachine.rollback(index, oldEntry.getValue()); }else if(oldEntry.getValueType() == LogValueType.Configuration){ this.logger.info("revert a previous config change to config at %d", this.config.getLogIndex()); this.configChanging = false;
private void reconfigure(ClusterConfiguration newConfig){ this.logger.debug( "system is reconfigured to have %d servers, last config index: %d, this config index: %d", newConfig.getServers().size(), newConfig.getLastLogIndex(), newConfig.getLogIndex()); List<Integer> serversRemoved = new LinkedList<Integer>(); List<ClusterServer> serversAdded = new LinkedList<ClusterServer>(); for(ClusterServer s : newConfig.getServers()){ if(!this.peers.containsKey(s.getId()) && s.getId() != this.id){ serversAdded.add(s); if(newConfig.getServer(id.intValue()) == null){ serversRemoved.add(id); if(newConfig.getServer(this.id) == null){ serversRemoved.add(this.id);
}else if(logEntry.getValueType() == LogValueType.Configuration){ synchronized(server){ ClusterConfiguration newConfig = ClusterConfiguration.fromBytes(logEntry.getValue()); server.logger.info("configuration at index %d is committed", newConfig.getLogIndex()); server.context.getServerStateManager().saveClusterConfiguration(newConfig); server.configChanging = false; if(server.config.getLogIndex() < newConfig.getLogIndex()){ server.reconfigure(newConfig); if(server.catchingUp && newConfig.getServer(server.id) != null){ server.logger.info("this server is committed as one of cluster members"); server.catchingUp = false;
/** * De-serialize the data stored in buffer to cluster configuration * this is used for the peers to get the cluster configuration from log entry value * @param buffer the binary data * @return cluster configuration */ public static ClusterConfiguration fromBytes(ByteBuffer buffer){ ClusterConfiguration configuration = new ClusterConfiguration(); configuration.setLogIndex(buffer.getLong()); configuration.setLastLogIndex(buffer.getLong()); while(buffer.hasRemaining()){ configuration.getServers().add(new ClusterServer(buffer)); } return configuration; }
private void becomeLeader(){ this.stopElectionTimer(); this.role = ServerRole.Leader; this.leader = this.id; this.serverToJoin = null; for(PeerServer server : this.peers.values()){ server.setNextLogIndex(this.logStore.getFirstAvailableIndex()); server.setSnapshotInSync(null); server.setFree(); this.enableHeartbeatForPeer(server); } // if current config is not committed, try to commit it if(this.config.getLogIndex() == 0){ this.config.setLogIndex(this.logStore.getFirstAvailableIndex()); this.logStore.append(new LogEntry(this.state.getTerm(), this.config.toBytes(), LogValueType.Configuration)); this.logger.info("add initial configuration to log store"); this.configChanging = true; } this.requestAppendEntries(); }
while(config.getLogIndex() > indexCommitted && config.getLastLogIndex() >= this.logStore.getStartIndex()){ config = ClusterConfiguration.fromBytes(this.logStore.getLogEntryAt(config.getLastLogIndex()).getValue()); if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() > 0 && config.getLastLogIndex() < this.logStore.getStartIndex()){ Snapshot lastSnapshot = this.stateMachine.getLastSnapshot(); if(lastSnapshot == null){ }else if(config.getLogIndex() > indexCommitted && config.getLastLogIndex() == 0){ this.logger.error("BUG!!! stop the system, there must be a configuration at index one"); this.stateMachine.exit(-1);
public byte[] toBytes(){ byte[] configData = this.snapshot.getLastConfig().toBytes(); int size = Long.BYTES * 3 + configData.length + Integer.BYTES * 2 + data.length + 1; ByteBuffer buffer = ByteBuffer.allocate(size); buffer.putLong(snapshot.getLastLogIndex()); buffer.putLong(snapshot.getLastLogTerm()); buffer.putInt(configData.length); buffer.put(configData); buffer.putLong(this.offset); buffer.putInt(this.data.length); buffer.put(this.data); buffer.put(this.done ? (byte)1 : (byte)0); return buffer.array(); }
if(--this.steppingDown == 0){ this.logger.info("no hearing further news from leader, remove this server from config and step down"); ClusterServer server = this.config.getServer(this.id); if(server != null){ this.config.getServers().remove(server); this.context.getServerStateManager().saveClusterConfiguration(this.config);
RpcClient rpcClient = this.rpcClients.get(leaderId); if(rpcClient == null){ ClusterServer leader = config.getServer(leaderId); if(leader == null){ result.complete(false);