use of org.apache.ignite.raft.jraft.rpc.RpcResponseClosureAdapter in project ignite-3 by apache.
the class Replicator method sendEntries.
/**
* Send log entries to follower, returns true when success, otherwise false and unlock the id.
*
* @param nextSendingIndex next sending index
* @return send result.
*/
private boolean sendEntries(final long nextSendingIndex) {
final AppendEntriesRequestBuilder rb = raftOptions.getRaftMessagesFactory().appendEntriesRequest();
if (!fillCommonFields(rb, nextSendingIndex - 1, false)) {
// unlock id in installSnapshot
installSnapshot();
return false;
}
ByteBufferCollector dataBuf = null;
final int maxEntriesSize = this.raftOptions.getMaxEntriesSize();
final RecyclableByteBufferList byteBufList = RecyclableByteBufferList.newInstance();
try {
List<RaftOutter.EntryMeta> entries = new ArrayList<>();
for (int i = 0; i < maxEntriesSize; i++) {
final EntryMetaBuilder emb = raftOptions.getRaftMessagesFactory().entryMeta();
if (!prepareEntry(nextSendingIndex, i, emb, byteBufList)) {
break;
}
entries.add(emb.build());
}
rb.entriesList(entries);
if (entries.isEmpty()) {
if (nextSendingIndex < this.options.getLogManager().getFirstLogIndex()) {
installSnapshot();
return false;
}
// _id is unlock in _wait_more
waitMoreEntries(nextSendingIndex);
return false;
}
if (byteBufList.getCapacity() > 0) {
dataBuf = ByteBufferCollector.allocateByRecyclers(byteBufList.getCapacity());
for (final ByteBuffer b : byteBufList) {
dataBuf.put(b);
}
final ByteBuffer buf = dataBuf.getBuffer();
buf.flip();
rb.data(new ByteString(buf));
}
} finally {
RecycleUtil.recycle(byteBufList);
}
final AppendEntriesRequest request = rb.build();
if (LOG.isDebugEnabled()) {
LOG.debug("Node {} send AppendEntriesRequest to {} term {} lastCommittedIndex {} prevLogIndex {} prevLogTerm {} logIndex {} count {}", this.options.getNode().getNodeId(), this.options.getPeerId(), this.options.getTerm(), request.committedIndex(), request.prevLogIndex(), request.prevLogTerm(), nextSendingIndex, Utils.size(request.entriesList()));
}
this.statInfo.runningState = RunningState.APPENDING_ENTRIES;
this.statInfo.firstLogIndex = request.prevLogIndex() + 1;
this.statInfo.lastLogIndex = request.prevLogIndex() + Utils.size(request.entriesList());
final Recyclable recyclable = dataBuf;
final int v = this.version;
final long monotonicSendTimeMs = Utils.monotonicMs();
final int seq = getAndIncrementReqSeq();
Future<Message> rpcFuture = null;
try {
rpcFuture = this.rpcService.appendEntries(this.options.getPeerId().getEndpoint(), request, -1, new RpcResponseClosureAdapter<AppendEntriesResponse>() {
@Override
public void run(final Status status) {
if (status.isOk()) {
// TODO: recycle on send success, not response received IGNITE-14832.
// Also, this closure can be executed when rpcFuture was cancelled, but the request was not sent (meaning
// it's too early to recycle byte buffer)
RecycleUtil.recycle(recyclable);
}
onRpcReturned(Replicator.this.id, RequestType.AppendEntries, status, request, getResponse(), seq, v, monotonicSendTimeMs);
}
});
} catch (final Throwable t) {
RecycleUtil.recycle(recyclable);
ThrowUtil.throwException(t);
}
addInflight(RequestType.AppendEntries, nextSendingIndex, Utils.size(request.entriesList()), request.data() == null ? 0 : request.data().size(), seq, rpcFuture);
return true;
}
Aggregations