/** Have we asked this peer for the key? */ public synchronized boolean askedFromPeer(PeerNodeUnlocked peer, long now) { boolean anyValid = false; boolean ret = false; for (int i = 0; i < requestedNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestedNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) { requestedNodes[i] = null; continue; } long bootID = pn.getBootID(); if (bootID != requestedBootIDs[i]) { requestedNodes[i] = null; continue; } anyValid = true; if (now - requestedTimes[i] < MAX_TIME_BETWEEN_REQUEST_AND_OFFER) { if (pn == peer) ret = true; anyValid = true; } } if (!anyValid) { requestedNodes = EMPTY_WEAK_REFERENCE; requestedTimes = requestedBootIDs = requestedTimeoutsRF = requestedTimeoutsFT = EMPTY_LONG_ARRAY; requestedTimeoutHTLs = EMPTY_SHORT_ARRAY; } return ret; }
public synchronized short minRequestorHTL(short htl) { long now = System.currentTimeMillis(); boolean anyValid = false; for (int i = 0; i < requestorNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestorNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) { requestorNodes[i] = null; continue; } long bootID = pn.getBootID(); if (bootID != requestorBootIDs[i]) { requestorNodes[i] = null; continue; } if (now - requestorTimes[i] < MAX_TIME_BETWEEN_REQUEST_AND_OFFER) { if (requestorHTLs[i] < htl) htl = requestorHTLs[i]; } anyValid = true; } if (!anyValid) { requestorNodes = EMPTY_WEAK_REFERENCE; requestorTimes = requestorBootIDs = EMPTY_LONG_ARRAY; ; requestorHTLs = EMPTY_SHORT_ARRAY; } return htl; }
private boolean cleanupRequestor(long now) { boolean empty = true; int x = 0; for (int i = 0; i < requestorNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestorNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) continue; long bootID = pn.getBootID(); if (bootID != requestorBootIDs[i]) continue; if (!pn.isConnected()) continue; if (now - requestorTimes[i] > MAX_TIME_BETWEEN_REQUEST_AND_OFFER) continue; empty = false; requestorNodes[x] = requestorNodes[i]; requestorTimes[x] = requestorTimes[i]; requestorBootIDs[x] = requestorBootIDs[i]; requestorHTLs[x] = requestorHTLs[i]; x++; } if (x < requestorNodes.length) { requestorNodes = Arrays.copyOf(requestorNodes, x); ; requestorTimes = Arrays.copyOf(requestorTimes, x); ; requestorBootIDs = Arrays.copyOf(requestorBootIDs, x); ; requestorHTLs = Arrays.copyOf(requestorHTLs, x); ; } return empty; }
/** * A request failed to a specific peer. * * @param routedTo The peer we routed to. * @param rfTimeout The time until we can route to the node again, for purposes of RecentlyFailed. * @param ftTimeout The time until we can route to the node again, for purposes of per-node * failure tables. * @param now The current time. * @param htl The HTL of the request. Note that timeouts only apply to the same HTL. */ public synchronized void failedTo( PeerNodeUnlocked routedTo, int rfTimeout, int ftTimeout, long now, short htl) { if (logMINOR) { Logger.minor( this, "Failed sending request to " + routedTo.shortToString() + " : timeout " + rfTimeout + " / " + ftTimeout); } int idx = addRequestedFrom(routedTo, htl, now); if (rfTimeout > 0) { long curTimeoutTime = requestedTimeoutsRF[idx]; long newTimeoutTime = now + rfTimeout; if (newTimeoutTime > curTimeoutTime) { requestedTimeoutsRF[idx] = newTimeoutTime; requestedTimeoutHTLs[idx] = htl; } } if (ftTimeout > 0) { long curTimeoutTime = requestedTimeoutsFT[idx]; long newTimeoutTime = now + ftTimeout; if (newTimeoutTime > curTimeoutTime) { requestedTimeoutsFT[idx] = newTimeoutTime; requestedTimeoutHTLs[idx] = htl; } } }
private boolean cleanupRequested(long now) { boolean empty = true; int x = 0; for (int i = 0; i < requestedNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestedNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) continue; long bootID = pn.getBootID(); if (bootID != requestedBootIDs[i]) continue; if (!pn.isConnected()) continue; if (now - requestedTimes[i] > MAX_TIME_BETWEEN_REQUEST_AND_OFFER) continue; empty = false; requestedNodes[x] = requestedNodes[i]; requestedTimes[x] = requestedTimes[i]; requestedBootIDs[x] = requestedBootIDs[i]; requestedLocs[x] = requestedLocs[i]; if (now < requestedTimeoutsRF[x] || now < requestedTimeoutsFT[x]) { requestedTimeoutsRF[x] = requestedTimeoutsRF[i]; requestedTimeoutsFT[x] = requestedTimeoutsFT[i]; requestedTimeoutHTLs[x] = requestedTimeoutHTLs[i]; } else { requestedTimeoutsRF[x] = -1; requestedTimeoutsFT[x] = -1; requestedTimeoutHTLs[x] = (short) -1; } x++; } if (x < requestedNodes.length) { requestedNodes = Arrays.copyOf(requestedNodes, x); ; requestedTimes = Arrays.copyOf(requestedTimes, x); ; requestedBootIDs = Arrays.copyOf(requestedBootIDs, x); ; requestedLocs = Arrays.copyOf(requestedLocs, x); ; requestedTimeoutsRF = Arrays.copyOf(requestedTimeoutsRF, x); ; requestedTimeoutsFT = Arrays.copyOf(requestedTimeoutsFT, x); ; requestedTimeoutHTLs = Arrays.copyOf(requestedTimeoutHTLs, x); ; } return empty; }
/** Has any node asked for this key? */ public synchronized boolean othersWant(PeerNodeUnlocked peer) { boolean anyValid = false; for (int i = 0; i < requestorNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestorNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) { requestorNodes[i] = null; continue; } long bootID = pn.getBootID(); if (bootID != requestorBootIDs[i]) { requestorNodes[i] = null; continue; } anyValid = true; } if (!anyValid) { requestorNodes = EMPTY_WEAK_REFERENCE; requestorTimes = requestorBootIDs = EMPTY_LONG_ARRAY; requestorHTLs = EMPTY_SHORT_ARRAY; } return anyValid; }
/** * Offer this key to all the nodes that have requested it, and all the nodes it has been requested * from. Called after a) the data has been stored, and b) this entry has been removed from the FT */ public void offer() { HashSet<PeerNodeUnlocked> set = new HashSet<PeerNodeUnlocked>(); final boolean logMINOR = FailureTableEntry.logMINOR; if (logMINOR) Logger.minor( this, "Sending offers to nodes which requested the key from us: (" + requestorNodes.length + ") for " + key); synchronized (this) { for (int i = 0; i < requestorNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestorNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) continue; if (pn.getBootID() != requestorBootIDs[i]) continue; if (!set.add(pn)) { Logger.error(this, "Node is in requestorNodes twice: " + pn); } } if (logMINOR) Logger.minor( this, "Sending offers to nodes which we sent the key to: (" + requestedNodes.length + ") for " + key); for (int i = 0; i < requestedNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestedNodes[i]; if (ref == null) continue; PeerNodeUnlocked pn = ref.get(); if (pn == null) continue; if (pn.getBootID() != requestedBootIDs[i]) continue; if (!set.add(pn)) continue; } } // Do the offers outside the lock. // We do not need to hold it, offer() doesn't do anything that affects us. for (PeerNodeUnlocked pn : set) { if (logMINOR) Logger.minor(this, "Offering to " + pn); pn.offer(key); } }
/** * Add a requested from entry to the node. If there already is one reuse it but only if the HTL * matches. Return the index so we can update timeouts etc. * * @param requestedFrom The node we have routed the request to. * @param htl The HTL at which the request was sent. * @param now The current time. * @return The index of the new or old entry. */ private synchronized int addRequestedFrom(PeerNodeUnlocked requestedFrom, short htl, long now) { if (logMINOR) Logger.minor(this, "Adding requested from: " + requestedFrom + " at " + now); sentTime = now; boolean includedAlready = false; int nulls = 0; int ret = -1; for (int i = 0; i < requestedNodes.length; i++) { PeerNodeUnlocked got = requestedNodes[i] == null ? null : requestedNodes[i].get(); if (got == requestedFrom && (requestedTimeoutsRF[i] == -1 || requestedTimeoutsFT[i] == -1 || requestedTimeoutHTLs[i] == htl)) { includedAlready = true; requestedLocs[i] = requestedFrom.getLocation(); requestedBootIDs[i] = requestedFrom.getBootID(); requestedTimes[i] = now; ret = i; } else if (got != null && (got.getBootID() != requestedBootIDs[i] || now - requestedTimes[i] > MAX_TIME_BETWEEN_REQUEST_AND_OFFER)) { requestedNodes[i] = null; got = null; } if (got == null) nulls++; } if (includedAlready && nulls == 0) return ret; int notIncluded = includedAlready ? 0 : 1; // Because weak, these can become null; doesn't matter, but we want to minimise memory usage if (nulls == 1 && !includedAlready) { // Nice special case for (int i = 0; i < requestedNodes.length; i++) { if (requestedNodes[i] == null || requestedNodes[i].get() == null) { requestedNodes[i] = requestedFrom.getWeakRef(); requestedLocs[i] = requestedFrom.getLocation(); requestedBootIDs[i] = requestedFrom.getBootID(); requestedTimes[i] = now; requestedTimeoutsRF[i] = -1; requestedTimeoutsFT[i] = -1; requestedTimeoutHTLs[i] = (short) -1; return i; } } } @SuppressWarnings("unchecked") WeakReference<? extends PeerNodeUnlocked>[] newRequestedNodes = new WeakReference[requestedNodes.length + notIncluded - nulls]; double[] newRequestedLocs = new double[requestedNodes.length + notIncluded - nulls]; long[] newRequestedBootIDs = new long[requestedNodes.length + notIncluded - nulls]; long[] newRequestedTimes = new long[requestedNodes.length + notIncluded - nulls]; long[] newRequestedTimeoutsFT = new long[requestedNodes.length + notIncluded - nulls]; long[] newRequestedTimeoutsRF = new long[requestedNodes.length + notIncluded - nulls]; short[] newRequestedTimeoutHTLs = new short[requestedNodes.length + notIncluded - nulls]; int toIndex = 0; for (int i = 0; i < requestedNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestedNodes[i]; PeerNodeUnlocked pn = ref == null ? null : ref.get(); if (pn == null) continue; if (pn == requestedFrom) ret = toIndex; newRequestedNodes[toIndex] = requestedNodes[i]; newRequestedTimes[toIndex] = requestedTimes[i]; newRequestedBootIDs[toIndex] = requestedBootIDs[i]; newRequestedLocs[toIndex] = requestedLocs[i]; newRequestedTimeoutsFT[toIndex] = requestedTimeoutsFT[i]; newRequestedTimeoutsRF[toIndex] = requestedTimeoutsRF[i]; newRequestedTimeoutHTLs[toIndex] = requestedTimeoutHTLs[i]; toIndex++; } if (!includedAlready) { ret = toIndex; newRequestedNodes[toIndex] = requestedFrom.getWeakRef(); newRequestedTimes[toIndex] = now; newRequestedBootIDs[toIndex] = requestedFrom.getBootID(); newRequestedLocs[toIndex] = requestedFrom.getLocation(); newRequestedTimeoutsFT[toIndex] = -1; newRequestedTimeoutsRF[toIndex] = -1; newRequestedTimeoutHTLs[toIndex] = (short) -1; ret = toIndex; toIndex++; } for (int i = toIndex; i < newRequestedNodes.length; i++) newRequestedNodes[i] = null; if (toIndex > newRequestedNodes.length + 2) { newRequestedNodes = Arrays.copyOf(newRequestedNodes, toIndex); ; newRequestedLocs = Arrays.copyOf(newRequestedLocs, toIndex); ; newRequestedBootIDs = Arrays.copyOf(newRequestedBootIDs, toIndex); ; newRequestedTimes = Arrays.copyOf(newRequestedTimes, toIndex); ; newRequestedTimeoutsRF = Arrays.copyOf(newRequestedTimeoutsRF, toIndex); ; newRequestedTimeoutsFT = Arrays.copyOf(newRequestedTimeoutsFT, toIndex); ; newRequestedTimeoutHTLs = Arrays.copyOf(newRequestedTimeoutHTLs, toIndex); ; } requestedNodes = newRequestedNodes; requestedLocs = newRequestedLocs; requestedBootIDs = newRequestedBootIDs; requestedTimes = newRequestedTimes; requestedTimeoutsRF = newRequestedTimeoutsRF; requestedTimeoutsFT = newRequestedTimeoutsFT; requestedTimeoutHTLs = newRequestedTimeoutHTLs; return ret; }
synchronized int addRequestor(PeerNodeUnlocked requestor, long now, short origHTL) { if (logMINOR) Logger.minor(this, "Adding requestors: " + requestor + " at " + now); receivedTime = now; boolean includedAlready = false; int nulls = 0; int ret = -1; for (int i = 0; i < requestorNodes.length; i++) { PeerNodeUnlocked got = requestorNodes[i] == null ? null : requestorNodes[i].get(); // No longer subscribed if they have rebooted, or expired if (got == requestor) { // Update existing entry includedAlready = true; requestorTimes[i] = now; requestorBootIDs[i] = requestor.getBootID(); requestorHTLs[i] = origHTL; ret = i; break; } else if (got != null && (got.getBootID() != requestorBootIDs[i] || now - requestorTimes[i] > MAX_TIME_BETWEEN_REQUEST_AND_OFFER)) { requestorNodes[i] = null; got = null; } if (got == null) nulls++; } if (nulls == 0 && includedAlready) return ret; int notIncluded = includedAlready ? 0 : 1; // Because weak, these can become null; doesn't matter, but we want to minimise memory usage if (nulls == 1 && !includedAlready) { // Nice special case for (int i = 0; i < requestorNodes.length; i++) { if (requestorNodes[i] == null || requestorNodes[i].get() == null) { requestorNodes[i] = requestor.getWeakRef(); requestorTimes[i] = now; requestorBootIDs[i] = requestor.getBootID(); requestorHTLs[i] = origHTL; return i; } } } @SuppressWarnings("unchecked") WeakReference<? extends PeerNodeUnlocked>[] newRequestorNodes = new WeakReference[requestorNodes.length + notIncluded - nulls]; long[] newRequestorTimes = new long[requestorNodes.length + notIncluded - nulls]; long[] newRequestorBootIDs = new long[requestorNodes.length + notIncluded - nulls]; short[] newRequestorHTLs = new short[requestorNodes.length + notIncluded - nulls]; int toIndex = 0; for (int i = 0; i < requestorNodes.length; i++) { WeakReference<? extends PeerNodeUnlocked> ref = requestorNodes[i]; PeerNodeUnlocked pn = ref == null ? null : ref.get(); if (pn == null) continue; if (pn == requestor) ret = toIndex; newRequestorNodes[toIndex] = requestorNodes[i]; newRequestorTimes[toIndex] = requestorTimes[i]; newRequestorBootIDs[toIndex] = requestorBootIDs[i]; newRequestorHTLs[toIndex] = requestorHTLs[i]; toIndex++; } if (!includedAlready) { newRequestorNodes[toIndex] = requestor.getWeakRef(); newRequestorTimes[toIndex] = now; newRequestorBootIDs[toIndex] = requestor.getBootID(); newRequestorHTLs[toIndex] = origHTL; ret = toIndex; toIndex++; } for (int i = toIndex; i < newRequestorNodes.length; i++) newRequestorNodes[i] = null; if (toIndex > newRequestorNodes.length + 2) { newRequestorNodes = Arrays.copyOf(newRequestorNodes, toIndex); newRequestorTimes = Arrays.copyOf(newRequestorTimes, toIndex); newRequestorBootIDs = Arrays.copyOf(newRequestorBootIDs, toIndex); newRequestorHTLs = Arrays.copyOf(newRequestorHTLs, toIndex); } requestorNodes = newRequestorNodes; requestorTimes = newRequestorTimes; requestorBootIDs = newRequestorBootIDs; requestorHTLs = newRequestorHTLs; return ret; }