/**
   * checks to see if the previous node along the path was missing a RT entry if so, we send the
   * previous node the corresponding RT row to patch the hole
   *
   * @param msg the RouteMessage being routed
   * @param handle the next hop handle
   */
  private void checkForRouteTableHole(RouteMessage msg, NodeHandle handle) {
    if (logger.level <= Logger.FINEST)
      logger.log("checkForRouteTableHole(" + msg + "," + handle + ")");

    NodeHandle prevNode = msg.getPrevNode();
    if (prevNode == null) {
      if (logger.level <= Logger.FINER) logger.log("No prevNode defined in " + msg);
      return;
    }

    if (prevNode.equals(getNodeHandle())) {
      if (logger.level <= Logger.FINER) logger.log("prevNode is me in " + msg);
      return;
    }

    // we don't want to send the repair if they just routed in the leafset
    LeafSet ls = thePastryNode.getLeafSet();
    if (ls.overlaps()) return; // small network, don't bother
    if (ls.member(prevNode)) {
      // ok, it's in my leafset, so I'm in his, but make sure that it's not on the edge
      int index = ls.getIndex(prevNode);
      if ((index == ls.cwSize()) || (index == -ls.ccwSize())) {
        // it is the edge... continue with repair
      } else {
        return;
      }
    }

    Id prevId = prevNode.getNodeId();
    Id key = msg.getTarget();

    int diffDigit = prevId.indexOfMSDD(key, thePastryNode.getRoutingTable().baseBitLength());

    // if we both have the same prefix (in other words the previous node didn't make a prefix of
    // progress)
    if (diffDigit >= 0
        && diffDigit
            == thePastryNode
                .getNodeId()
                .indexOfMSDD(key, thePastryNode.getRoutingTable().baseBitLength())) {
      synchronized (lastTimeSentRouteTablePatch) {
        if (lastTimeSentRouteTablePatch.containsKey(prevNode)) {
          long lastTime = lastTimeSentRouteTablePatch.get(prevNode);
          if (lastTime
              > (thePastryNode.getEnvironment().getTimeSource().currentTimeMillis()
                  - ROUTE_TABLE_PATCH_THROTTLE)) {
            if (logger.level <= Logger.INFO)
              logger.log(
                  "not sending route table patch to "
                      + prevNode
                      + " because throttled.  Last Time:"
                      + lastTime);
            return;
          }
        }
        lastTimeSentRouteTablePatch.put(
            prevNode, thePastryNode.getEnvironment().getTimeSource().currentTimeMillis());
      }

      // the previous node is missing a RT entry, send the row
      // for now, we send the entire row for simplicity

      RouteSet[] row = thePastryNode.getRoutingTable().getRow(diffDigit);
      BroadcastRouteRow brr = new BroadcastRouteRow(thePastryNode.getLocalHandle(), row);

      if (prevNode.isAlive()) {
        if (logger.level <= Logger.FINE) {
          logger.log(
              "Found hole in " + prevNode + "'s routing table. Sending " + brr.toStringFull());
        }
        thePastryNode.send(prevNode, brr, null, options);
      }
    }
  }