// Pass a response through the duplicate counters. public void handleInitiateResponseMessage(InitiateResponseMessage message) { // All single-partition reads are short-circuit reads and will have no duplicate counter. // SpScheduler will only see InitiateResponseMessages for SP transactions, so if it's // read-only here, it's short-circuited. Avoid all the lookup below. Also, don't update // the truncation handle, since it won't have meaning for anyone. if (message.isReadOnly()) { // the initiatorHSId is the ClientInterface mailbox. Yeah. I know. m_mailbox.send(message.getInitiatorHSId(), message); return; } final long spHandle = message.getSpHandle(); final DuplicateCounterKey dcKey = new DuplicateCounterKey(message.getTxnId(), spHandle); DuplicateCounter counter = m_duplicateCounters.get(dcKey); if (counter != null) { int result = counter.offer(message); if (result == DuplicateCounter.DONE) { m_duplicateCounters.remove(dcKey); m_repairLogTruncationHandle = spHandle; m_mailbox.send(counter.m_destinationId, counter.getLastResponse()); } else if (result == DuplicateCounter.MISMATCH) { VoltDB.crashLocalVoltDB("HASH MISMATCH: replicas produced different results.", true, null); } } else { // the initiatorHSId is the ClientInterface mailbox. Yeah. I know. m_repairLogTruncationHandle = spHandle; m_mailbox.send(message.getInitiatorHSId(), message); } }
// This is going to run in the BabySitter's thread. This and deliver are synchronized by // virtue of both being called on InitiatorMailbox and not directly called. // (That is, InitiatorMailbox's API, used by BabySitter, is synchronized on the same // lock deliver() is synchronized on.) @Override public void updateReplicas(List<Long> replicas) { // First - correct the official replica set. m_replicaHSIds = replicas; // Update the list of remote replicas that we'll need to send to List<Long> sendToHSIds = new ArrayList<Long>(m_replicaHSIds); sendToHSIds.remove(m_mailbox.getHSId()); m_sendToHSIds = Longs.toArray(sendToHSIds); // Cleanup duplicate counters and collect DONE counters // in this list for further processing. List<DuplicateCounterKey> doneCounters = new LinkedList<DuplicateCounterKey>(); for (Entry<DuplicateCounterKey, DuplicateCounter> entry : m_duplicateCounters.entrySet()) { DuplicateCounter counter = entry.getValue(); int result = counter.updateReplicas(m_replicaHSIds); if (result == DuplicateCounter.DONE) { doneCounters.add(entry.getKey()); } } // Maintain the CI invariant that responses arrive in txnid order. Collections.sort(doneCounters); for (DuplicateCounterKey key : doneCounters) { DuplicateCounter counter = m_duplicateCounters.remove(key); VoltMessage resp = counter.getLastResponse(); if (resp != null) { // MPI is tracking deps per partition HSID. We need to make // sure we write ours into the message getting sent to the MPI if (resp instanceof FragmentResponseMessage) { FragmentResponseMessage fresp = (FragmentResponseMessage) resp; fresp.setExecutorSiteId(m_mailbox.getHSId()); } m_mailbox.send(counter.m_destinationId, resp); } else { hostLog.warn( "TXN " + counter.getTxnId() + " lost all replicas and " + "had no responses. This should be impossible?"); } } writeIv2ViableReplayEntry(); }
// Eventually, the master for a partition set will need to be able to dedupe // FragmentResponses from its replicas. public void handleFragmentResponseMessage(FragmentResponseMessage message) { // Send the message to the duplicate counter, if any DuplicateCounter counter = m_duplicateCounters.get(new DuplicateCounterKey(message.getTxnId(), message.getSpHandle())); if (counter != null) { int result = counter.offer(message); if (result == DuplicateCounter.DONE) { m_duplicateCounters.remove( new DuplicateCounterKey(message.getTxnId(), message.getSpHandle())); m_repairLogTruncationHandle = message.getSpHandle(); FragmentResponseMessage resp = (FragmentResponseMessage) counter.getLastResponse(); // MPI is tracking deps per partition HSID. We need to make // sure we write ours into the message getting sent to the MPI resp.setExecutorSiteId(m_mailbox.getHSId()); m_mailbox.send(counter.m_destinationId, resp); } else if (result == DuplicateCounter.MISMATCH) { VoltDB.crashLocalVoltDB("HASH MISMATCH running multi-part procedure.", true, null); } // doing duplicate suppresion: all done. return; } m_mailbox.send(message.getDestinationSiteId(), message); }