}
final String procedureName = message.getStoredProcedureName();
long newSpHandle;
long uniqueId = Long.MIN_VALUE;
Iv2InitiateTaskMessage msg = message;
if (m_isLeader || message.isReadOnly()) {
/*
* A short circuit read is a read where the client interface is local to
* this node. The CI will let a replica perform a read in this case and
* it does looser tracking of client handles since it can't be
* partitioned from the local replica.
*/
if (!m_isLeader &&
CoreUtils.getHostIdFromHSId(msg.getInitiatorHSId()) !=
CoreUtils.getHostIdFromHSId(m_mailbox.getHSId())) {
VoltDB.crashLocalVoltDB("Only allowed to do short circuit reads locally", true, null);
}
/*
* If this is for CL replay or DR, update the unique ID generator
*/
if (message.isForReplay()) {
uniqueId = message.getUniqueId();
try {
m_uniqueIdGenerator.updateMostRecentlyGeneratedUniqueId(uniqueId);
}
catch (Exception e) {
hostLog.fatal(e.getMessage());
hostLog.fatal("Invocation: " + message);
VoltDB.crashLocalVoltDB(e.getMessage(), true, e);
}
} else if (message.isForDR()) {
uniqueId = message.getStoredProcedureInvocation().getOriginalUniqueId();
// @LoadSinglepartitionTable does not have a valid uid
if (UniqueIdGenerator.getPartitionIdFromUniqueId(uniqueId) == m_partitionId) {
m_uniqueIdGenerator.updateMostRecentlyGeneratedUniqueId(uniqueId);
}
}
/*
* If this is CL replay use the txnid from the CL and also
* update the txnid to match the one from the CL
*/
if (message.isForReplay()) {
newSpHandle = message.getTxnId();
setMaxSeenTxnId(newSpHandle);
} else if (m_isLeader && !message.isReadOnly()) {
TxnEgo ego = advanceTxnEgo();
newSpHandle = ego.getTxnId();
uniqueId = m_uniqueIdGenerator.getNextUniqueId();
} else {
/*
* The short circuit read case. Since we are not a master
* we can't create new transaction IDs, so reuse the last seen
* txnid. For a timestamp, might as well give a reasonable one
* for a read heavy workload so time isn't bursty.
*/
uniqueId = UniqueIdGenerator.makeIdFromComponents(
Math.max(System.currentTimeMillis(), m_uniqueIdGenerator.lastUsedTime),
0,
m_uniqueIdGenerator.partitionId);
//Don't think it wise to make a new one for a short circuit read
newSpHandle = getMaxTaskedSpHandle();
}
// Need to set the SP handle on the received message
// Need to copy this or the other local sites handling
// the same initiate task message will overwrite each
// other's memory -- the message isn't copied on delivery
// to other local mailboxes.
msg = new Iv2InitiateTaskMessage(
message.getInitiatorHSId(),
message.getCoordinatorHSId(),
m_repairLogTruncationHandle,
message.getTxnId(),
message.getUniqueId(),
message.isReadOnly(),
message.isSinglePartition(),
message.getStoredProcedureInvocation(),
message.getClientInterfaceHandle(),
message.getConnectionId(),
message.isForReplay());
msg.setSpHandle(newSpHandle);
// Also, if this is a vanilla single-part procedure, make the TXNID
// be the SpHandle (for now)
// Only system procedures are every-site, so we'll check through the SystemProcedureCatalog
if (SystemProcedureCatalog.listing.get(procedureName) == null ||
!SystemProcedureCatalog.listing.get(procedureName).getEverysite()) {
msg.setTxnId(newSpHandle);
msg.setUniqueId(uniqueId);
}
//Don't replicate reads, this really assumes that DML validation
//is going to be integrated soonish
if (m_isLeader && !msg.isReadOnly() && m_sendToHSIds.length > 0) {
Iv2InitiateTaskMessage replmsg =
new Iv2InitiateTaskMessage(m_mailbox.getHSId(),
m_mailbox.getHSId(),
m_repairLogTruncationHandle,
msg.getTxnId(),
msg.getUniqueId(),
msg.isReadOnly(),
msg.isSinglePartition(),
msg.getStoredProcedureInvocation(),
msg.getClientInterfaceHandle(),
msg.getConnectionId(),
msg.isForReplay());
// Update the handle in the copy since the constructor doesn't set it
replmsg.setSpHandle(newSpHandle);
m_mailbox.send(m_sendToHSIds, replmsg);
DuplicateCounter counter = new DuplicateCounter(
msg.getInitiatorHSId(),
msg.getTxnId(), m_replicaHSIds, msg.getStoredProcedureName());
m_duplicateCounters.put(new DuplicateCounterKey(msg.getTxnId(), newSpHandle), counter);