private void processRejoiningFragmentWork(
      FragmentTaskMessage ftask, HashMap<Integer, List<VoltTable>> dependencies) {
    assert (ftask.getFragmentCount() > 0);
    assert (m_rejoinState == RejoinState.REJOINING);

    FragmentResponseMessage response = new FragmentResponseMessage(ftask, m_hsId);
    response.setRecovering(true);
    response.setStatus(FragmentResponseMessage.SUCCESS, null);

    // log the work done for replay
    if (!ftask.isReadOnly() && !ftask.isSysProcTask()) {
      assert (m_notice.isReadOnly() == false);
      assert (m_loggedFragments != null);
      m_loggedFragments.appendFragmentTask(ftask);
    }

    // add a dummy table for all of the expected dependency ids
    for (int i = 0; i < ftask.getFragmentCount(); i++) {
      response.addDependency(
          ftask.getOutputDepId(i),
          new VoltTable(new VoltTable.ColumnInfo("DUMMY", VoltType.BIGINT)));
    }

    m_mbox.send(response.getDestinationSiteId(), response);

    // If we're not the coordinator, the transaction is read-only,
    // and this was the final task, then we can try to move on after
    // we've finished this work.
    if (!isCoordinator() && isReadOnly() && ftask.isFinalTask()) {
      m_done = true;
    }
  }
  // Currently emulates the code in ProcedureRunner.slowPath()
  // So any change to how that stuff is built will need to
  // be reflected here
  MpTestPlan createTestPlan(
      int batchSize,
      boolean readOnly,
      boolean replicatedTable,
      boolean rollback,
      long[] remoteHSIds)
      throws IOException {
    boolean single_frag = readOnly && replicatedTable;
    MpTestPlan plan = new MpTestPlan();

    List<Integer> distributedOutputDepIds = new ArrayList<Integer>();
    List<Integer> depsToResumeList = new ArrayList<Integer>();
    List<Integer> depsForLocalTask = new ArrayList<Integer>();
    for (int i = 0; i < batchSize; i++) {
      // each SQL statement in the batch gets an output dep ID
      // which corresponds to a local fragment ID
      depsToResumeList.add(i);
      // each local fragment ID needs an input dep.  If this is
      // not replicated read only, generate a new value and add it to
      // the distributed output deps
      if (!single_frag) {
        // take the dep and add 1000
        depsForLocalTask.add(i + 1000);
        distributedOutputDepIds.add(i + 1000);
      } else {
        depsForLocalTask.add(-1);
      }
    }

    // store resume dependencies in the MpTestPlan for later.
    plan.depsToResume = depsToResumeList;

    // generate remote task with output IDs, fill in lists appropriately
    plan.remoteWork =
        new FragmentTaskMessage(
            Long.MIN_VALUE, // try not to care?
            Long.MIN_VALUE, // try not to care?
            Long.MIN_VALUE, // try not to care?
            1234l, // magic, change if it matters
            readOnly,
            false,
            false); // IV2 doesn't use final task (yet)

    for (int i = 0; i < distributedOutputDepIds.size(); i++) {
      plan.remoteWork.addFragment(
          Long.MIN_VALUE, distributedOutputDepIds.get(i), createDummyParameterSet());
    }
    System.out.println("REMOTE TASK: " + plan.remoteWork.toString());

    if (!single_frag) {
      // generate a remote fragment response for each remote message
      for (int i = 0; i < remoteHSIds.length; i++) {
        FragmentResponseMessage resp = new FragmentResponseMessage(plan.remoteWork, remoteHSIds[i]);
        if (rollback && i == (remoteHSIds.length - 1)) {
          resp.setStatus(FragmentResponseMessage.UNEXPECTED_ERROR, new EEException(1234));
        } else {
          resp.setStatus(FragmentResponseMessage.SUCCESS, null);
          for (int j = 0; j < distributedOutputDepIds.size(); j++) {
            resp.addDependency(
                distributedOutputDepIds.get(j),
                new VoltTable(new VoltTable.ColumnInfo("BOGO", VoltType.BIGINT)));
          }
        }
        System.out.println("RESPONSE: " + resp);
        plan.generatedResponses.add(resp);
      }
    }

    // generate local task with new output IDs, use above outputs as inputs, if any
    plan.localWork =
        new FragmentTaskMessage(
            Long.MIN_VALUE, // try not to care
            Long.MIN_VALUE,
            Long.MIN_VALUE,
            1234l,
            readOnly,
            false,
            false);

    for (int i = 0; i < batchSize; i++) {
      plan.localWork.addFragment(0L, depsToResumeList.get(i), createDummyParameterSet());
    }

    for (int i = 0; i < depsForLocalTask.size(); i++) {
      if (depsForLocalTask.get(i) < 0) continue;
      plan.localWork.addInputDepId(i, depsForLocalTask.get(i));
    }
    // create the FragmentResponse for the BorrowTask
    FragmentResponseMessage resp = new FragmentResponseMessage(plan.remoteWork, remoteHSIds[0]);
    resp.setStatus(FragmentResponseMessage.SUCCESS, null);
    for (int j = 0; j < batchSize; j++) {
      resp.addDependency(
          depsToResumeList.get(j),
          new VoltTable(new VoltTable.ColumnInfo("BOGO", VoltType.BIGINT)));
    }
    System.out.println("BORROW RESPONSE: " + resp);
    plan.generatedResponses.add(resp);

    System.out.println("LOCAL TASK: " + plan.localWork.toString());

    return plan;
  }