code: public Long safeToRecover() {
          boolean safe = true;
          for (LastInitiatorData data : m_initiatorData.values()) {
              final long lastSeenTxnId = data.m_lastSeenTxnId;
              if (lastSeenTxnId == DtxnConstants.DUMMY_LAST_SEEN_TXN_ID) {
                  safe = false;
              }
          }
          if (!safe) {
              return null;
          }
  
          OrderableTransaction next = peek();
          if (next == null) {
              // no work - have heard from all initiators. use a heartbeat
              if (m_state == QueueState.BLOCKED_EMPTY) {
                  return m_newestCandidateTransaction;
              }
              // waiting for some txn to be 2pc to this site.
              else if (m_state == QueueState.BLOCKED_SAFETY) {
                  return null;
              } else if (m_state == QueueState.BLOCKED_ORDERING){
                  return null;
              }
              m_recoveryLog.error("Unexpected RPQ state " + m_state + " when attempting to start recovery at " +
                      " the source site. Consider killing the recovering node and trying again");
              return null; // unreachable
          }
          else {
              // bingo - have a real transaction to return as the recovery point
              return next.txnId;
          }
      }
docs: Determine if it is safe to recover and if it is, what txnid it is safe to recover at.
  Recovery is initiated by the recovering source partition. It can't be initiated until the recovering
  partition has heard from every initiator. This is because it is not possible to pick a point
  in the global txn ordering for the recovery to start at where all subsequent procedure invocations
  that need to be applied after recovery are available unless every initiator has been heard from.
  
  Once the initiators have all been heard from it is necessary to pick the lowest txnid possible for all pending
  work. This means taking the min of the newest candidate transaction | the txnid of the next txn in the queue.
  
  The newest candidate transaction is used if there are no pending txns so recovery can start when
  the system is idle.