InterruptedException,
MasterSyncException {
final long startNs = System.nanoTime();
final InputWireRecord wireRecord = entry.getWireRecord();
final LogEntry logEntry = wireRecord.getLogEntry();
/*
* Sanity check that the replication stream is in sequence. We want to
* forestall any possible corruption from replaying invalid entries.
*/
if (!wireRecord.getVLSN().follows(lastReplayedVLSN)) {
throw new EnvironmentFailureException
(repImpl,
EnvironmentFailureReason.UNEXPECTED_STATE,
"Rep stream not sequential. Current VLSN: " +
lastReplayedVLSN +
" next log entry VLSN: " + wireRecord.getVLSN());
}
if (logger.isLoggable(Level.FINEST)) {
LoggerUtils.finest(logger, repImpl, "Replaying " + wireRecord);
}
final ReplayTxn repTxn = getReplayTxn(logEntry.getTransactionId());
updateReplicaSequences(logEntry);
final byte entryType = wireRecord.getEntryType();
lastReplayedVLSN = wireRecord.getVLSN();
final RepNode repNode = repImpl.getRepNode();
try {
if (LOG_TXN_COMMIT.equalsType(entryType)) {
Protocol.Commit commitEntry = (Protocol.Commit) entry;
final boolean needsAck = commitEntry.getNeedsAck();
final SyncPolicy syncPolicy =
needsAck ?
commitEntry.getReplicaSyncPolicy() :
noAckSyncPolicy;
logReplay(repTxn, needsAck, syncPolicy);
final TxnCommit masterCommit =
(TxnCommit) logEntry.getMainItem();
if (needsAck) {
/*
* Only wait if the replica is not lagging and the
* durability requires it.
*/
repNode.getVLSNFreezeLatch().awaitThaw();
repNode.getMasterStatus().assertSync();
}
repTxn.commit(syncPolicy,
new ReplicationContext(lastReplayedVLSN),
masterCommit.getMasterNodeId());
final long masterCommitTimeMs =
masterCommit.getTime().getTime();
lastReplayedTxn = new TxnInfo(lastReplayedVLSN,
masterCommitTimeMs);
updateCommitStats(needsAck, syncPolicy, startNs);
/* Respond to the feeder. */
if (needsAck) {
protocol.write(protocol.new Ack(repTxn.getId()),
namedChannel);
}
/*
* The group refresh and recalculation can be expensive, since
* it may require a database read. Do it after the ack.
*/
if (repTxn.getRepGroupDbChange() && canRefreshGroup(repTxn)) {
repNode.refreshCachedGroup();
repNode.recalculateGlobalCBVLSN();
}
nElapsedTxnTime.add(repTxn.elapsedTime());
} else if (LOG_TXN_ABORT.equalsType(entryType)) {
nAborts.increment();
final TxnAbort masterAbort = (TxnAbort) logEntry.getMainItem();
final ReplicationContext abortContext =
new ReplicationContext(wireRecord.getVLSN());
if (logger.isLoggable(Level.FINEST)) {
LoggerUtils.finest(logger, repImpl,
"abort called for " + repTxn.getId() +