Beispiel #1
0
  /**
   * Adds the given node reference to the finger table and successor list, if appropriate. The
   * reference is NOT set as predecessor, even if is closer to this node. Therefore use {@link
   * #addReferenceAsPredecessor(Node)}.
   *
   * @param newReference Reference to be added to the local data structures.
   * @throws NullPointerException If the given reference is null.
   */
  final synchronized void addReference(Node newReference) {

    if (newReference == null) {
      NullPointerException e =
          new NullPointerException("Node reference to be added must not be null!");
      this.logger.error("Null pointer", e);
      throw e;
    }

    boolean debug = this.logger.isEnabledFor(DEBUG);
    // June 21, 2006. Moved here by sven to avoid failing of checkIfProxy()
    if (newReference.getNodeID().equals(this.localID)) {
      if (debug) {
        this.logger.debug("Reference on myself was not added");
      }
      return;
    }

    // check parameters
    this.checkIfProxy(newReference);

    this.fingerTable.addReference(newReference);
    this.successorList.addSuccessor(newReference);

    if (debug) {
      this.logger.debug(
          "Attempted to add reference "
              + newReference.getNodeID().toString()
              + " to finger table and successor list. Whether it fit "
              + "or not depends on those data structures.");
    }
  }
Beispiel #2
0
  /**
   * Sets the given reference as this node's predecessor. If the former value of this predecessor's
   * node was <code>null</code> and if this reference is not used any more (eg. in finger table or
   * successor list), the connection to it is closed.
   *
   * @param potentialPredecessor Reference on the node to be set as new predecessor; may not be null
   * @throws NullPointerException If potential predecessor is null.
   */
  final synchronized void setPredecessor(Node potentialPredecessor) {

    if (potentialPredecessor == null) {
      NullPointerException e =
          new NullPointerException(
              "Potential predecessor of method setPredecessor may not be " + "null!");
      this.logger.error("Null pointer", e);
      throw e;
    }
    this.checkIfProxy(potentialPredecessor);

    boolean info = this.logger.isEnabledFor(INFO);
    if (!(potentialPredecessor.equals(this.predecessor))) {
      Node formerPredecessor = this.predecessor;
      this.predecessor = potentialPredecessor;
      if (formerPredecessor != null) {
        this.disconnectIfUnreferenced(formerPredecessor);
        /*
         * The replicas, which are in the range between the old and the
         * new predecessor, on the last successor of this node have to
         * be removed if the successor list is full. => capacity of sl ==
         * length of sl.
         */
        int sLSize = this.successorList.getSize();
        if (this.successorList.getCapacity() == sLSize) {
          Node lastSuccessor = this.successorList.getReferences().get(sLSize - 1);
          try {
            lastSuccessor.removeReplicas(this.predecessor.getNodeID(), new HashSet<Entry>());
          } catch (CommunicationException e) {
            logger.warn("Could not remove replicas on last predecessor", e);
          }
        }
        if (this.logger.isEnabledFor(DEBUG)) {
          this.logger.debug(
              "Old predecessor " + formerPredecessor + " was replaced by " + potentialPredecessor);
        }
      } else {
        if (info) {
          this.logger.info(
              "Predecessor reference set to " + potentialPredecessor + "; was null before.");
        }
        Set<Entry> entriesToRep =
            this.entries.getEntriesInInterval(this.predecessor.getNodeID(), this.localID);
        List<Node> successors = this.successorList.getReferences();
        for (Node successor : successors) {
          try {
            successor.insertReplicas(entriesToRep);
          } catch (CommunicationException e) {
            this.logger.warn("Damn. Could not replicate to successor " + successor.getNodeID(), e);
          }
        }
      }
    }
  }
Beispiel #3
0
  /**
   * Adds the given node reference to the finger table and successor list AND sets it as new
   * predecessor reference, if appropriate. Appropriateness is given if either the former
   * predecessor reference was <code>null</code> or the new reference's ID is located between the
   * old predecessor ID and this node's ID. Even if not appropriate as predecessor, the reference is
   * added to finger table and successor list.
   *
   * @param potentialPredecessor Reference which should be this node's predecessor.
   * @throws NullPointerException If the given reference is <code>null</code>.
   */
  void addReferenceAsPredecessor(Node potentialPredecessor) {

    this.checkIfProxy(potentialPredecessor);
    if (potentialPredecessor == null) {
      NullPointerException e =
          new NullPointerException("Reference to potential predecessor may not be null!");
      this.logger.error("Null pointer", e);
      throw e;
    }

    // if the local node did not have a predecessor reference before
    // or if the potential predecessor is closer to this local node,
    // replace the predecessor reference
    if (this.predecessor == null
        || potentialPredecessor
            .getNodeID()
            .isInInterval(this.predecessor.getNodeID(), this.localID)) {

      if (this.logger.isEnabledFor(INFO)) {
        this.logger.info(
            "Setting a new predecessor reference: New reference is "
                + potentialPredecessor
                + ", old reference was "
                + (this.predecessor == null ? "null" : this.predecessor));
      }

      // replace predecessor reference
      this.setPredecessor(potentialPredecessor);

      /*
       * If a new predecessor, better than the old one has arrived, we
       * have to copy the entries, that are relevant for this new
       * predecessor. This has to be done by the predecessor itself, NOT
       * here. 18.06.2007. sven
       */
      // final Set<Entry> entries = this.entries.getEntriesInInterval(
      // this.predecessor.nodeID, this.localID);
      // this.localChord.getAsyncExecutor().execute(new Runnable() {
      // public void run() {
      // try {
      // for (Entry entryToInsert : entries) {
      // getPredecessor().insertEntry(entryToInsert);
      // }
      // } catch (CommunicationException e) {
      // }
      // }
      // });
    }

    // add reference
    this.addReference(potentialPredecessor);
  }
Beispiel #4
0
 /** {@inheritDoc} */
 @Override
 public final void leavesNetwork(Node predecessor) {
   if (this.logger.isEnabledFor(INFO)) {
     this.logger.info("Leaves network invoked; " + this.nodeID + ". Updating references.");
     this.logger.info("New predecessor " + predecessor.getNodeID());
   }
   if (this.logger.isEnabledFor(DEBUG)) {
     this.logger.debug("References before update: " + this.references.toString());
   }
   this.references.removeReference(this.references.getPredecessor());
   if (this.logger.isEnabledFor(DEBUG)) {
     this.logger.debug("References after update: " + this.references.toString());
   }
 }
Beispiel #5
0
  /** {@inheritDoc} */
  @Override
  public final RefsAndEntries notifyAndCopyEntries(Node potentialPredecessor)
      throws CommunicationException {
    /*
     * Mutual exclusion between notify and notifyAndCopyEntries. 17.03.2008. sven.
     */
    this.notifyLock.lock();
    try {
      // copy all entries which lie between the local node ID and the ID
      // of
      // the potential predecessor, including those equal to potential
      // predecessor
      Set<Entry> copiedEntries =
          this.entries.getEntriesInInterval(this.nodeID, potentialPredecessor.getNodeID());

      return new RefsAndEntries(this.notify(potentialPredecessor), copiedEntries);
    } finally {
      this.notifyLock.unlock();
    }
  }
Beispiel #6
0
  /**
   * Determines the closest preceding node for the given ID based on finger table, successor list,
   * and predecessor, but without testing the node's liveliness.
   *
   * @param key ID to find closest preceding node for.
   * @throws NullPointerException If ID is <code>null</code>.
   * @return Reference on closest preceding node.
   */
  final synchronized Node getClosestPrecedingNode(ID key) {

    if (key == null) {
      NullPointerException e = new NullPointerException("ID may not be null!");
      this.logger.error("Null pointer", e);
      throw e;
    }

    Map<ID, Node> foundNodes = new HashMap<ID, Node>();
    // determine closest preceding reference of finger table
    Node closestNodeFT = this.fingerTable.getClosestPrecedingNode(key);
    if (closestNodeFT != null) {
      foundNodes.put(closestNodeFT.getNodeID(), closestNodeFT);
    }

    // determine closest preceding reference of successor list
    Node closestNodeSL = this.successorList.getClosestPrecedingNode(key);
    if (closestNodeSL != null) {
      foundNodes.put(closestNodeSL.getNodeID(), closestNodeSL);
    }

    // predecessor is appropriate only if it precedes the given id
    Node predecessorIfAppropriate = null;
    if (this.predecessor != null && key.isInInterval(this.predecessor.getNodeID(), this.localID)) {
      predecessorIfAppropriate = this.predecessor;
      foundNodes.put(this.predecessor.getNodeID(), predecessor);
    }

    // with three references which may be null, there are eight (8) cases we
    // have to enumerate...
    Node closestNode = null;
    List<ID> orderedIDList = new ArrayList<ID>(foundNodes.keySet());
    orderedIDList.add(key);
    int sizeOfList = orderedIDList.size();
    // size of list must be greater than one to not only contain the key.
    // if (sizeOfList > 1) {

    /*
     * Sort list in ascending order
     */
    Collections.sort(orderedIDList);
    /*
     * The list item with one index lower than that of the key must be the
     * id of the closest predecessor or the key.
     */
    int keyIndex = orderedIDList.indexOf(key);
    /*
     * As all ids are located on a ring if the key is the first item in the
     * list we have to select the last item as predecessor with help of this
     * calculation.
     */
    int index = (sizeOfList + (keyIndex - 1)) % sizeOfList;
    /*
     * Get the references to the node from the map of collected nodes.
     */
    ID idOfclosestNode = orderedIDList.get(index);
    closestNode = foundNodes.get(idOfclosestNode);
    if (closestNode == null) {
      throw new NullPointerException("closestNode must not be null!");
    }

    /*
     * Following code is too complicated.
     */
    // if (closestNodeFT == null) {
    // if (closestNodeSL == null) {
    // if (predecessorIfAppropriate == null) {
    // // no reference is appropriate
    // closestNode = null;
    // } else {
    // // only predecessor is appropriate (case should not occur,
    // // but anyway...
    // closestNode = predecessorIfAppropriate;
    // }
    // } else {
    // if (predecessorIfAppropriate == null) {
    // // only reference of successor list is appropriate
    // closestNode = closestNodeSL;
    // } else {
    // // either predecessor or reference of successor list is
    // // appropriate; determine one of both
    // if (predecessorIfAppropriate.nodeID.isInInterval(
    // closestNodeSL.nodeID, key)) {
    // closestNode = predecessorIfAppropriate;
    // } else {
    // closestNode = closestNodeSL;
    // }
    // }
    // }
    // } else {
    // if (closestNodeSL == null) {
    // if (predecessorIfAppropriate == null) {
    // // only reference of finger table is appropriate
    // closestNode = closestNodeFT;
    // } else {
    // // either predecessor or reference of finger table is
    // // appropriate; determine one of both
    // if (predecessorIfAppropriate.nodeID.isInInterval(
    // closestNodeFT.nodeID, key)) {
    // closestNode = predecessorIfAppropriate;
    // } else {
    // closestNode = closestNodeFT;
    // }
    // }
    // } else {
    // if (predecessorIfAppropriate == null) {
    // // either reference of successor list or reference of finger
    // // table is appropriate; determine one of both
    // if (closestNodeSL.nodeID.isInInterval(closestNodeFT.nodeID,
    // key)) {
    // closestNode = closestNodeSL;
    // } else {
    // closestNode = closestNodeFT;
    // }
    // } else {
    // // either of the three reference is appropriate; determine
    // // first one of the references of successor list and finger
    // // table is more appropriate and afterwards compare with
    // // predecessor
    // if (closestNodeSL.nodeID.isInInterval(closestNodeFT.nodeID,
    // key)) {
    // if (predecessorIfAppropriate.nodeID.isInInterval(
    // closestNodeSL.nodeID, key)) {
    // closestNode = predecessorIfAppropriate;
    // } else {
    // closestNode = closestNodeSL;
    // }
    // } else {
    // if (predecessorIfAppropriate.nodeID.isInInterval(
    // closestNodeFT.nodeID, key)) {
    // closestNode = predecessorIfAppropriate;
    // } else {
    // closestNode = closestNodeFT;
    // }
    // }
    // }
    // }
    // }
    if (this.logger.isEnabledFor(DEBUG)) {
      this.logger.debug(
          "Closest preceding node of ID "
              + key
              + " at node "
              + this.localID.toString()
              + " is "
              + closestNode.getNodeID()
              + " with closestNodeFT="
              + (closestNodeFT == null ? "null" : "" + closestNodeFT.getNodeID())
              + " and closestNodeSL="
              + (closestNodeSL == null ? "null" : "" + closestNodeSL.getNodeID())
              + " and predecessor (only if it precedes given ID)="
              + (predecessorIfAppropriate == null
                  ? "null"
                  : "" + predecessorIfAppropriate.getNodeID()));
    }
    return closestNode;
  }
Beispiel #7
0
  // TODO: implement this function in TTP
  @Override
  public final void broadcast(Broadcast info) throws CommunicationException {
    if (this.logger.isEnabledFor(DEBUG)) {
      this.logger.debug(" Send broadcast message");
    }
    // System.out.println("NodeImpl: Send broadcast: " + info);

    // Check transaction Number, only accept ascending Numbers
    if (info.getTransaction() > this.getTransactionCount()) {
      System.out.println(
          "NodeImpl: Updating transaction Number from "
              + this.getTransactionCount()
              + " to "
              + info.getTransaction());
      this.setTransactionCount(info.getTransaction());
    } else {
      System.out.println("NodeImpl: Ignoring old transaction ID " + info.getTransaction());
      System.out.println("################################################################");
      return;
    }

    // Get and sort known nodes
    List<Node> fingerTable = references.getFingerTableEntries();

    // make IDs in fingerTable unique
    HashSet<Node> fingerSet = new HashSet<Node>(fingerTable);
    // but list is better for iteration (we'll frequently need next's next)
    List<Node> knownNodes = new ArrayList<Node>(fingerSet);
    Collections.sort(knownNodes);

    // Iterate over nodes
    for (int i = 0; i < knownNodes.size(); ++i) {
      Node n = knownNodes.get(i);

      // Only broadcast to nodes between own ID and range
      if (!n.getNodeID().isInInterval(this.getNodeID(), info.getRange())) {
        System.out.println("NodeImpl: Not in range, not sending broadcast");
        break;
      }

      // find successor of Node n (stays if we're at the last node)
      ID successorID = info.getRange();
      if (knownNodes.size() > i + 1) {
        successorID = knownNodes.get(i + 1).getNodeID();
      }

      // Create broadcast object and send
      Broadcast bc =
          new Broadcast(
              successorID,
              this.getNodeID(),
              info.getTarget(),
              info.getTransaction(),
              info.getHit());
      // System.out.println("NodeImpl: Broadcasting: " + bc);
      n.broadcast(bc);
    }

    // finally inform application
    if (this.notifyCallback != null) {
      this.notifyCallback.broadcast(info.getSource(), info.getTarget(), info.getHit());
    }

    System.out.println("################################################################");
  }