public void removeCallback(USKCallback cb) { Long[] hints; synchronized(this) { subscribers.remove(cb); subscriberHints.remove(cb); hints = subscriberHints.values().toArray(new Long[subscriberHints.size()]); } watchingKeys.updateSubscriberHints(hints, uskManager.lookupLatestSlot(origUSK)); }
public void addHintEdition(long suggestedEdition) { watchingKeys.addHintEdition(suggestedEdition, uskManager.lookupLatestSlot(origUSK)); }
public void removeSubscriber(USKCallback cb, ClientContext context) { Long[] hints; synchronized(this) { subscribers.remove(cb); subscriberHints.remove(cb); hints = subscriberHints.values().toArray(new Long[subscriberHints.size()]); } updatePriorities(); watchingKeys.updateSubscriberHints(hints, uskManager.lookupLatestSlot(origUSK)); }
/** * Add a subscriber. Subscribers are not directly sent onFoundEdition()'s by the * USKFetcher, we just use them to determine the priority of our requests and * whether we should continue to request. * @param cb */ public void addSubscriber(USKCallback cb, long hint) { Long[] hints; synchronized(this) { subscribers.add(cb); subscriberHints.put(cb, hint); hints = subscriberHints.values().toArray(new Long[subscriberHints.size()]); } updatePriorities(); watchingKeys.updateSubscriberHints(hints, uskManager.lookupLatestSlot(origUSK)); }
private void innerRoundFinished(ClientContext context, boolean finishedRound) { long ed; boolean meta; short codec; byte[] data; boolean wasKnownGood; synchronized(this) { if(finishedRound) roundFinished = true; if(lastSent == lastEdition) return; lastSent = ed = lastEdition; meta = lastMetadata; codec = lastCodec; data = lastData; wasKnownGood = lastWasKnownGoodToo; } if(ed == -1) { ed = context.uskManager.lookupLatestSlot(key); if(ed == -1) return; meta = false; codec = -1; data = null; wasKnownGood = false; } if(ed == -1) return; target.onFoundEdition(ed, key, context, meta, codec, data, wasKnownGood, wasKnownGood); }
@Override public short definitelyWantKey(Key key, byte[] saltedKey, ClientContext context) { if(!(key instanceof NodeSSK)) return -1; NodeSSK k = (NodeSSK) key; if(!origUSK.samePubKeyHash(k)) return -1; long lastSlot = uskManager.lookupLatestSlot(origUSK) + 1; synchronized(this) { if(watchingKeys.match(k, lastSlot) != -1) return progressPollPriority; } return -1; }
@Override public boolean probablyWantKey(Key key, byte[] saltedKey) { if(!(key instanceof NodeSSK)) return false; NodeSSK k = (NodeSSK) key; if(!origUSK.samePubKeyHash(k)) return false; long lastSlot = uskManager.lookupLatestSlot(origUSK) + 1; synchronized(this) { return watchingKeys.match(k, lastSlot) != -1; } }
private void registerAttempts(ClientContext context) { USKAttempt[] attempts; synchronized(USKFetcher.this) { if(cancelled || completed) return; attempts = attemptsToStart.toArray(new USKAttempt[attemptsToStart.size()]); attemptsToStart.clear(); } if(attempts.length > 0) parent.toNetwork(context); if(logMINOR) Logger.minor(this, "Registering "+attempts.length+" USKChecker's for "+this+" running="+runningAttempts.size()+" polling="+pollingAttempts.size()); for(USKAttempt attempt: attempts) { // Look up on each iteration since scheduling can cause new editions to be found sometimes. long lastEd = uskManager.lookupLatestSlot(origUSK); synchronized(USKFetcher.this) { // FIXME not sure this condition works, test it! if(keepLastData && lastRequestData == null && lastEd == origUSK.suggestedEdition) lastEd--; // If we want the data, then get it for the known edition, so we always get the data, so USKInserter can compare it and return the old edition if it is identical. } if(attempt == null) continue; if(attempt.number > lastEd) attempt.schedule(context); else { synchronized(USKFetcher.this) { runningAttempts.remove(attempt.number); } } } }
void onDNF(USKAttempt att, ClientContext context) { if(logMINOR) Logger.minor(this, "DNF: "+att); boolean finished = false; long curLatest = uskManager.lookupLatestSlot(origUSK); synchronized(this) { if(completed || cancelled) return; lastFetchedEdition = Math.max(lastFetchedEdition, att.number); runningAttempts.remove(att.number); if(runningAttempts.isEmpty()) { if(logMINOR) Logger.minor(this, "latest: "+curLatest+", last fetched: "+lastFetchedEdition+", curLatest+MIN_FAILURES: "+(curLatest+origMinFailures)); if(started) { finished = true; } } else if(logMINOR) Logger.minor(this, "Remaining: "+runningAttempts()); } if(finished) { finishSuccess(context); } }
long lastEd = uskManager.lookupLatestSlot(origUSK); synchronized(USKFetcher.this) { long lastEd = uskManager.lookupLatestSlot(origUSK);
watchingKeys = new USKWatchingKeys(origUSK, Math.max(0, uskManager.lookupLatestSlot(origUSK)+1)); attemptsToStart = new ArrayList<USKAttempt>();
@Override public boolean handleBlock(Key key, byte[] saltedKey, KeyBlock found, ClientContext context) { if(!(found instanceof SSKBlock)) return false; long lastSlot = uskManager.lookupLatestSlot(origUSK) + 1; long edition = watchingKeys.match((NodeSSK)key, lastSlot); if(edition == -1) return false; if(logMINOR) Logger.minor(this, "Matched edition "+edition+" for "+origUSK); ClientSSKBlock data; try { data = watchingKeys.decode((SSKBlock)found, edition); } catch (SSKVerifyException e) { data = null; } onSuccess(null, edition, false, data, context); return true; }
toFetch = new ArrayList<USK>(); USK clear = entry.getKey(); long l = lookupLatestSlot(clear); if(lookupKnownGood(clear) < l) toFetch.add(clear.copy(l));
private void scheduleInsert(ClientContext context) { long edNo = Math.max(edition, context.uskManager.lookupLatestSlot(pubUSK)+1); synchronized(this) { if(finished) return; edition = edNo; if(logMINOR) Logger.minor(this, "scheduling insert for "+pubUSK.getURI()+ ' ' +edition); sbi = new SingleBlockInserter(parent, data, compressionCodec, privUSK.getInsertableSSK(edition).getInsertURI(), ctx, realTimeFlag, this, isMetadata, sourceLength, token, false, true /* we don't use it */, tokenObject, context, persistent, false, extraInserts, cryptoAlgorithm, forceCryptoKey); } try { sbi.schedule(context); } catch (InsertException e) { synchronized(this) { finished = true; } if(freeData) { data.free(); synchronized(this) { data = null; } } cb.onFailure(e, this, context); } }
Logger.minor(this, "finishSuccess() on "+this); if(backgroundPoll) { long valAtEnd = uskManager.lookupLatestSlot(origUSK); long end; long now = System.currentTimeMillis(); uskManager.onFinished(this); context.getSskFetchScheduler(realTimeFlag).schedTransient.removePendingKeys((KeyListener)this); long ed = uskManager.lookupLatestSlot(origUSK); byte[] data; synchronized(this) {
if(newKnownGood && !newSlotToo) return; // Only interested in slots final long lastEd = uskManager.lookupLatestSlot(origUSK); boolean decode = false; List<USKAttempt> killAttempts = null;
/** * A non-authoritative hint that a specific edition *might* exist. At the moment, * we just fetch the block. We do not fetch the contents, and it is possible that * USKFetcher's are also fetching the block. FIXME would it be more efficient to * pass it along to a USKFetcher? * @param context * @throws MalformedURLException If the uri passed in is not a USK. */ public void hintUpdate(FreenetURI uri, ClientContext context, short priority) throws MalformedURLException { if(uri.getSuggestedEdition() < lookupLatestSlot(USK.create(uri))) { if(logMINOR) Logger.minor(this, "Ignoring hint because edition is "+uri.getSuggestedEdition()+" but latest is "+lookupLatestSlot(USK.create(uri))); return; } uri = uri.sskForUSK(); if(logMINOR) Logger.minor(this, "Doing hint fetch for "+uri); final ClientGetter get = new ClientGetter(new NullClientCallback(rcBulk), uri, new FetchContext(backgroundFetchContext, FetchContext.IDENTICAL_MASK), priority, new NullBucket(), null, null); try { get.start(context); } catch (FetchException e) { if(logMINOR) Logger.minor(this, "Cannot start hint fetch for "+uri+" : "+e, e); // Ignore } }
long fetchTime = -1; long slot = lookupLatestSlot(clear); long good = lookupKnownGood(clear); if(slot > -1 && good != slot)
/** * A non-authoritative hint that a specific edition *might* exist. At the moment, * we just fetch the block. We do not fetch the contents, and it is possible that * USKFetcher's are also fetching the block. FIXME would it be more efficient to * pass it along to a USKFetcher? * @param usk * @param edition * @param context */ public void hintUpdate(USK usk, long edition, ClientContext context) { if(edition < lookupLatestSlot(usk)) return; FreenetURI uri = usk.copy(edition).getURI().sskForUSK(); final ClientGetter get = new ClientGetter(new NullClientCallback(rcBulk), uri, new FetchContext(backgroundFetchContext, FetchContext.IDENTICAL_MASK), RequestStarter.UPDATE_PRIORITY_CLASS, new NullBucket(), null, null); try { get.start(context); } catch (FetchException e) { // Ignore } }
return null; } else if(edition == -1 && context.uskManager.lookupLatestSlot(usk) == -1) { // We do not want to be going round and round here!