/** * 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; }