/** {@inheritDoc} */ @Override public final Set<Entry> retrieveEntries(ID id) throws CommunicationException { // Possible, but rare situation: a new node has joined which now is // responsible for the id! if (this.references.getPredecessor() != null && !id.isInInterval(this.references.getPredecessor().getNodeID(), this.nodeID)) { this.logger.fatal( "The rare situation has occured at time " + System.currentTimeMillis() + ", id to look up=" + id + ", id of local node=" + this.nodeID + ", id of predecessor=" + this.references.getPredecessor().getNodeID()); return this.references.getPredecessor().retrieveEntries(id); } // return entries from local repository // for this purpose create a copy of the Set in order to allow the // thread retrieving the entries to modify the Set without modifying the // internal Set of entries. sven return this.entries.getEntries(id); }
/** * 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; }