use of io.dingodb.raft.conf.ConfigurationEntry in project dingo by dingodb.
the class LogManagerImpl method setSnapshot.
@Override
public void setSnapshot(final SnapshotMeta meta) {
LOG.debug("set snapshot: {}.", meta);
boolean isUnLock = true;
this.writeLock.lock();
try {
if (meta.getLastIncludedIndex() <= this.lastSnapshotId.getIndex()) {
return;
}
final Configuration conf = confFromMeta(meta);
final Configuration oldConf = oldConfFromMeta(meta);
final ConfigurationEntry entry = new ConfigurationEntry(new LogId(meta.getLastIncludedIndex(), meta.getLastIncludedTerm()), conf, oldConf);
this.configManager.setSnapshot(entry);
final long term = unsafeGetTerm(meta.getLastIncludedIndex());
final long savedLastSnapshotIndex = this.lastSnapshotId.getIndex();
this.lastSnapshotId.setIndex(meta.getLastIncludedIndex());
this.lastSnapshotId.setTerm(meta.getLastIncludedTerm());
if (this.lastSnapshotId.compareTo(this.appliedId) > 0) {
this.appliedId = this.lastSnapshotId.copy();
}
// NOTICE: not to update disk_id here as we are not sure if this node really
// has these logs on disk storage. Just leave disk_id as it was, which can keep
// these logs in memory all the time until they are flushed to disk. By this
// way we can avoid some corner cases which failed to get logs.
// See https://github.com/baidu/braft/pull/224/commits/8ef6fdbf70d23f5a4ee147356a889e2c0fa22aac
// if (this.lastSnapshotId.compareTo(this.diskId) > 0) {
// this.diskId = this.lastSnapshotId.copy();
// }
long firstKeepedIndex = 0L;
if (term == 0) {
// last_included_index is larger than last_index
// FIXME: what if last_included_index is less than first_index?
firstKeepedIndex = meta.getLastIncludedIndex() + 1;
truncatePrefix(firstKeepedIndex);
isUnLock = false;
writeLock.unlock();
} else if (term == meta.getLastIncludedTerm()) {
// TODO if there are still be need?
if (savedLastSnapshotIndex > 0) {
firstKeepedIndex = savedLastSnapshotIndex + 1;
truncatePrefix(firstKeepedIndex);
isUnLock = false;
writeLock.unlock();
}
} else {
final long lastIncludeIndex = meta.getLastIncludedIndex() + 1;
boolean isOK = reset(lastIncludeIndex);
isUnLock = false;
writeLock.unlock();
if (isOK) {
final ResetClosure c = new ResetClosure(lastIncludeIndex);
doPublish(c, EventType.RESET);
LOG.warn("Reset log manager, nextLogIndex={}", lastIncludeIndex);
} else {
LOG.warn("Reset log manager failed, nextLogIndex={}.", lastIncludeIndex);
}
}
if (firstKeepedIndex != 0) {
final TruncatePrefixClosure c = new TruncatePrefixClosure(firstKeepedIndex);
doPublish(c, EventType.TRUNCATE_PREFIX);
}
} finally {
if (isUnLock) {
this.writeLock.unlock();
}
}
}
use of io.dingodb.raft.conf.ConfigurationEntry in project dingo by dingodb.
the class LogManagerImpl method appendEntries.
@Override
public void appendEntries(final List<LogEntry> entries, final StableClosure done) {
Requires.requireNonNull(done, "done");
if (this.hasError) {
entries.clear();
Utils.runClosureInThread(done, new Status(RaftError.EIO, "Corrupted LogStorage"));
return;
}
boolean doUnlock = true;
this.writeLock.lock();
try {
if (!entries.isEmpty() && !checkAndResolveConflict(entries, done)) {
// If checkAndResolveConflict returns false, the done will be called in it.
entries.clear();
return;
}
for (int i = 0; i < entries.size(); i++) {
final LogEntry entry = entries.get(i);
// Set checksum after checkAndResolveConflict
if (this.raftOptions.isEnableLogEntryChecksum()) {
entry.setChecksum(entry.checksum());
}
if (entry.getType() == EntryType.ENTRY_TYPE_CONFIGURATION) {
Configuration oldConf = new Configuration();
if (entry.getOldPeers() != null) {
oldConf = new Configuration(entry.getOldPeers(), entry.getOldLearners());
}
final ConfigurationEntry conf = new ConfigurationEntry(entry.getId(), new Configuration(entry.getPeers(), entry.getLearners()), oldConf);
this.configManager.add(conf);
}
}
if (!entries.isEmpty()) {
done.setFirstLogIndex(entries.get(0).getId().getIndex());
this.logsInMemory.addAll(entries);
}
done.setEntries(entries);
// 1. release the lock.
doUnlock = false;
if (!wakeupAllWaiter(this.writeLock)) {
notifyLastLogIndexListeners();
}
// 2. Publish Event to Disruptor Queue.
final EventTranslator<StableClosureEvent> translator = (event, sequence) -> {
event.reset();
event.type = EventType.OTHER;
event.done = done;
};
doPublish(done, translator);
} finally {
if (doUnlock) {
this.writeLock.unlock();
}
}
}
use of io.dingodb.raft.conf.ConfigurationEntry in project dingo by dingodb.
the class RocksDBLogStorage method load.
private void load(final ConfigurationManager confManager) {
checkState();
try (final RocksIterator it = this.db.newIterator(this.confHandle, this.totalOrderReadOptions)) {
it.seekToFirst();
while (it.isValid()) {
final byte[] ks = it.key();
final byte[] bs = it.value();
// LogEntry index
if (ks.length == 8) {
final LogEntry entry = this.logEntryDecoder.decode(bs);
if (entry != null) {
if (entry.getType() == EntryType.ENTRY_TYPE_CONFIGURATION) {
final ConfigurationEntry confEntry = new ConfigurationEntry();
confEntry.setId(new LogId(entry.getId().getIndex(), entry.getId().getTerm()));
confEntry.setConf(new Configuration(entry.getPeers(), entry.getLearners()));
if (entry.getOldPeers() != null) {
confEntry.setOldConf(new Configuration(entry.getOldPeers(), entry.getOldLearners()));
}
if (confManager != null) {
confManager.add(confEntry);
}
}
} else {
LOG.warn("Fail to decode conf entry at index {}, the log data is: {}.", Bits.getLong(ks, 0), BytesUtil.toHex(bs));
}
} else {
if (Arrays.equals(FIRST_LOG_IDX_KEY, ks)) {
setFirstLogIndex(Bits.getLong(bs, 0));
truncatePrefixInBackground(0L, this.firstLogIndex);
} else {
LOG.warn("Unknown entry in configuration storage key={}, value={}.", BytesUtil.toHex(ks), BytesUtil.toHex(bs));
}
}
it.next();
}
}
}
use of io.dingodb.raft.conf.ConfigurationEntry in project dingo by dingodb.
the class NodeImpl method checkAndSetConfiguration.
/**
* Check and set configuration for node.At the same time, if configuration is changed,
* then compute and update the target priority value.
*
* @param inLock whether the writeLock has already been locked in other place.
*/
private void checkAndSetConfiguration(final boolean inLock) {
if (!inLock) {
this.writeLock.lock();
}
try {
final ConfigurationEntry prevConf = this.conf;
this.conf = this.logManager.checkAndSetConfiguration(prevConf);
if (this.conf != prevConf) {
// Update target priority value
final int prevTargetPriority = this.targetPriority;
this.targetPriority = getMaxPriorityOfNodes(this.conf.getConf().getPeers());
if (prevTargetPriority != this.targetPriority) {
LOG.info("Node {} target priority value has changed from: {}, to: {}.", getNodeId(), prevTargetPriority, this.targetPriority);
}
this.electionTimeoutCounter = 0;
}
} finally {
if (!inLock) {
this.writeLock.unlock();
}
}
}
use of io.dingodb.raft.conf.ConfigurationEntry in project dingo by dingodb.
the class NodeImpl method init.
@Override
public boolean init(final NodeOptions opts) {
Requires.requireNonNull(opts, "Null node options");
Requires.requireNonNull(opts.getRaftOptions(), "Null raft options");
Requires.requireNonNull(opts.getServiceFactory(), "Null jraft service factory");
this.serviceFactory = opts.getServiceFactory();
this.options = opts;
this.raftOptions = opts.getRaftOptions();
this.metrics = new NodeMetrics(opts.isEnableMetrics());
this.serverId.setPriority(opts.getElectionPriority());
this.electionTimeoutCounter = 0;
if (this.serverId.getIp().equals(Utils.IP_ANY)) {
LOG.error("Node can't started from IP_ANY.");
return false;
}
if (!NodeManager.getInstance().serverExists(this.serverId.getEndpoint())) {
LOG.error("No RPC server attached to, did you forget to call addService?");
return false;
}
this.timerManager = TIMER_FACTORY.getRaftScheduler(this.options.isSharedTimerPool(), this.options.getTimerPoolSize(), "JRaft-Node-ScheduleThreadPool");
// Init timers
final String suffix = getNodeId().toString();
String name = "JRaft-VoteTimer-" + suffix;
this.voteTimer = new RepeatedTimer(name, this.options.getElectionTimeoutMs(), TIMER_FACTORY.getVoteTimer(this.options.isSharedVoteTimer(), name)) {
@Override
protected void onTrigger() {
handleVoteTimeout();
}
@Override
protected int adjustTimeout(final int timeoutMs) {
return randomTimeout(timeoutMs);
}
};
name = "JRaft-ElectionTimer-" + suffix;
this.electionTimer = new RepeatedTimer(name, this.options.getElectionTimeoutMs(), TIMER_FACTORY.getElectionTimer(this.options.isSharedElectionTimer(), name)) {
@Override
protected void onTrigger() {
handleElectionTimeout();
}
@Override
protected int adjustTimeout(final int timeoutMs) {
return randomTimeout(timeoutMs);
}
};
name = "JRaft-StepDownTimer-" + suffix;
this.stepDownTimer = new RepeatedTimer(name, this.options.getElectionTimeoutMs() >> 1, TIMER_FACTORY.getStepDownTimer(this.options.isSharedStepDownTimer(), name)) {
@Override
protected void onTrigger() {
handleStepDownTimeout();
}
};
name = "JRaft-SnapshotTimer-" + suffix;
this.snapshotTimer = new RepeatedTimer(name, this.options.getSnapshotIntervalSecs() * 1000, TIMER_FACTORY.getSnapshotTimer(this.options.isSharedSnapshotTimer(), name)) {
private volatile boolean firstSchedule = true;
@Override
protected void onTrigger() {
handleSnapshotTimeout();
}
@Override
protected int adjustTimeout(final int timeoutMs) {
if (!this.firstSchedule) {
return timeoutMs;
}
// Randomize the first snapshot trigger timeout
this.firstSchedule = false;
if (timeoutMs > 0) {
int half = timeoutMs / 2;
return half + ThreadLocalRandom.current().nextInt(half);
} else {
return timeoutMs;
}
}
};
this.configManager = new ConfigurationManager();
this.applyDisruptor = //
DisruptorBuilder.<LogEntryAndClosure>newInstance().setRingBufferSize(//
this.raftOptions.getDisruptorBufferSize()).setEventFactory(//
new LogEntryAndClosureFactory()).setThreadFactory(//
new NamedThreadFactory("JRaft-NodeImpl-Disruptor-", true)).setProducerType(//
ProducerType.MULTI).setWaitStrategy(//
new BlockingWaitStrategy()).build();
this.applyDisruptor.handleEventsWith(new LogEntryAndClosureHandler());
this.applyDisruptor.setDefaultExceptionHandler(new LogExceptionHandler<Object>(getClass().getSimpleName()));
this.applyQueue = this.applyDisruptor.start();
if (this.metrics.getMetricRegistry() != null) {
this.metrics.getMetricRegistry().register("jraft-node-impl-disruptor", new DisruptorMetricSet(this.applyQueue));
}
this.fsmCaller = new FSMCallerImpl();
if (!initLogStorage()) {
LOG.error("Node {} initLogStorage failed.", getNodeId());
return false;
}
if (!initMetaStorage()) {
LOG.error("Node {} initMetaStorage failed.", getNodeId());
return false;
}
if (!initFSMCaller(new LogId(0, 0))) {
LOG.error("Node {} initFSMCaller failed.", getNodeId());
return false;
}
this.ballotBox = new BallotBox();
final BallotBoxOptions ballotBoxOpts = new BallotBoxOptions();
ballotBoxOpts.setWaiter(this.fsmCaller);
ballotBoxOpts.setClosureQueue(this.closureQueue);
if (!this.ballotBox.init(ballotBoxOpts)) {
LOG.error("Node {} init ballotBox failed.", getNodeId());
return false;
}
if (!initSnapshotStorage()) {
LOG.error("Node {} initSnapshotStorage failed.", getNodeId());
return false;
}
final Status st = this.logManager.checkConsistency();
if (!st.isOk()) {
LOG.error("Node {} is initialized with inconsistent log, status={}.", getNodeId(), st);
return false;
}
this.conf = new ConfigurationEntry();
this.conf.setId(new LogId());
// if have log using conf in log, else using conf in options
if (this.logManager.getLastLogIndex() > 0) {
checkAndSetConfiguration(false);
} else {
this.conf.setConf(this.options.getInitialConf());
// initially set to max(priority of all nodes)
this.targetPriority = getMaxPriorityOfNodes(this.conf.getConf().getPeers());
}
if (!this.conf.isEmpty()) {
Requires.requireTrue(this.conf.isValid(), "Invalid conf: %s", this.conf);
} else {
LOG.info("Init node {} with empty conf.", this.serverId);
}
// TODO RPC service and ReplicatorGroup is in cycle dependent, refactor it
this.replicatorGroup = new ReplicatorGroupImpl();
this.rpcService = new DefaultRaftClientService(this.replicatorGroup);
final ReplicatorGroupOptions rgOpts = new ReplicatorGroupOptions();
rgOpts.setHeartbeatTimeoutMs(heartbeatTimeout(this.options.getElectionTimeoutMs()));
rgOpts.setElectionTimeoutMs(this.options.getElectionTimeoutMs());
rgOpts.setLogManager(this.logManager);
rgOpts.setBallotBox(this.ballotBox);
rgOpts.setNode(this);
rgOpts.setRaftRpcClientService(this.rpcService);
rgOpts.setSnapshotStorage(this.snapshotExecutor != null ? this.snapshotExecutor.getSnapshotStorage() : null);
rgOpts.setRaftOptions(this.raftOptions);
rgOpts.setTimerManager(this.timerManager);
// Adds metric registry to RPC service.
this.options.setMetricRegistry(this.metrics.getMetricRegistry());
if (!this.rpcService.init(this.options)) {
LOG.error("Fail to init rpc service.");
return false;
}
this.replicatorGroup.init(new NodeId(this.groupId, this.serverId), rgOpts);
this.readOnlyService = new ReadOnlyServiceImpl();
final ReadOnlyServiceOptions rosOpts = new ReadOnlyServiceOptions();
rosOpts.setFsmCaller(this.fsmCaller);
rosOpts.setNode(this);
rosOpts.setRaftOptions(this.raftOptions);
if (!this.readOnlyService.init(rosOpts)) {
LOG.error("Fail to init readOnlyService.");
return false;
}
// set state to follower
this.state = State.STATE_FOLLOWER;
if (LOG.isInfoEnabled()) {
LOG.info("Node {} init, term={}, lastLogId={}, conf={}, oldConf={}.", getNodeId(), this.currTerm, this.logManager.getLastLogId(false), this.conf.getConf(), this.conf.getOldConf());
}
if (this.snapshotExecutor != null && this.options.getSnapshotIntervalSecs() > 0) {
LOG.debug("Node {} start snapshot timer, term={}.", getNodeId(), this.currTerm);
this.snapshotTimer.start();
}
if (!this.conf.isEmpty()) {
stepDown(this.currTerm, false, new Status());
}
if (!NodeManager.getInstance().add(this)) {
LOG.error("NodeManager add {} failed.", getNodeId());
return false;
}
// Now the raft node is started , have to acquire the writeLock to avoid race
// conditions
this.writeLock.lock();
if (this.conf.isStable() && this.conf.getConf().size() == 1 && this.conf.getConf().contains(this.serverId)) {
// The group contains only this server which must be the LEADER, trigger
// the timer immediately.
electSelf();
} else {
this.writeLock.unlock();
}
return true;
}
Aggregations