Package freenet.clients.http

Source Code of freenet.clients.http.FProxyFetchTracker

package freenet.clients.http;

import java.util.ArrayList;
import java.util.Enumeration;

import freenet.client.FetchContext;
import freenet.client.FetchException;
import freenet.client.async.ClientContext;
import freenet.clients.http.FProxyFetchInProgress.REFILTER_POLICY;
import freenet.keys.FreenetURI;
import freenet.node.RequestClient;
import freenet.support.LogThresholdCallback;
import freenet.support.Logger;
import freenet.support.MultiValueTable;
import freenet.support.Logger.LogLevel;

public class FProxyFetchTracker implements Runnable {

  private static volatile boolean logMINOR;
 
  static {
    Logger.registerLogThresholdCallback(new LogThresholdCallback() {
     
      @Override
      public void shouldUpdate() {
        logMINOR = Logger.shouldLog(LogLevel.MINOR, this);
      }
    });
  }
 
  final MultiValueTable<FreenetURI, FProxyFetchInProgress> fetchers;
  final ClientContext context;
  private long fetchIdentifiers;
  private final FetchContext fctx;
  private final RequestClient rc;
  private boolean queuedJob;
  private boolean requeue;

  public FProxyFetchTracker(ClientContext context, FetchContext fctx, RequestClient rc) {
    fetchers = new MultiValueTable<FreenetURI, FProxyFetchInProgress>();
    this.context = context;
    this.fctx = fctx;
    this.rc = rc;
  }
 
  public FProxyFetchWaiter makeFetcher(FreenetURI key, long maxSize, FetchContext fctx, REFILTER_POLICY refilterPolicy) throws FetchException {
    FProxyFetchInProgress progress;
    /* LOCKING:
     * Call getWaiter() inside the fetchers lock, since we will purge old
     * fetchers inside that lock, hence avoid a race condition. FetchInProgress
     * lock is always taken last. */
    synchronized(fetchers) {
      FProxyFetchWaiter waiter=makeWaiterForFetchInProgress(key, maxSize, fctx != null ? fctx : this.fctx);
      if(waiter!=null){
        return waiter;
      }
      progress = new FProxyFetchInProgress(this, key, maxSize, fetchIdentifiers++, context, fctx != null ? fctx : this.fctx, rc, refilterPolicy);
      fetchers.put(key, progress);
    }
    try {
      progress.start(context);
    } catch (FetchException e) {
      synchronized(fetchers) {
        fetchers.removeElement(key, progress);
      }
      throw e;
    }
    if(logMINOR) Logger.minor(this, "Created new fetcher: "+progress, new Exception());
    return progress.getWaiter();
    // FIXME promote a fetcher when it is re-used
    // FIXME get rid of fetchers over some age
  }
 
  void removeFetcher(FProxyFetchInProgress progress) {
    synchronized(fetchers) {
      fetchers.removeElement(progress.uri, progress);
    }
  }
 
  public FProxyFetchWaiter makeWaiterForFetchInProgress(FreenetURI key,long maxSize, FetchContext fctx){
    FProxyFetchInProgress progress=getFetchInProgress(key, maxSize, fctx);
    if(progress!=null){
      return progress.getWaiter();
    }
    return null;
  }
 
  /** Gets an FProxyFetchInProgress identified by the URI and the maxsize. If no such FetchInProgress exists, then returns null.
   * @param key - The URI of the fetch
   * @param maxSize - The maxSize of the fetch
   * @param fctx TODO
   * @return The FetchInProgress if found, null otherwise*/
  public FProxyFetchInProgress getFetchInProgress(FreenetURI key, long maxSize, FetchContext fctx){
    synchronized (fetchers) {
      Object[] check = fetchers.getArray(key);
      if(check != null) {
        for(int i=0;i<check.length;i++) {
          FProxyFetchInProgress progress = (FProxyFetchInProgress) check[i];
          if((progress.maxSize == maxSize && progress.notFinishedOrFatallyFinished())
              || progress.hasData()){
            if(logMINOR) Logger.minor(this, "Found "+progress);
            if(fctx != null && !progress.fetchContextEquivalent(fctx)) continue;
            if(logMINOR) Logger.minor(this, "Using "+progress);
            return progress;
          } else
            if(logMINOR) Logger.minor(this, "Skipping "+progress);
        }
      }
    }
    return null;
  }

  public void queueCancel(FProxyFetchInProgress progress) {
    if(logMINOR) Logger.minor(this, "Queueing removal of old FProxyFetchInProgress's");
    synchronized(this) {
      if(queuedJob) {
        requeue = true;
        return;
      }
      queuedJob = true;
    }
    context.ticker.queueTimedJob(this, FProxyFetchInProgress.LIFETIME);
  }

  @Override
  public void run() {
    if(logMINOR) Logger.minor(this, "Removing old FProxyFetchInProgress's");
    ArrayList<FProxyFetchInProgress> toRemove = null;
    boolean needRequeue = false;
    synchronized(fetchers) {
      if(requeue) {
        requeue = false;
        needRequeue = true;
      } else {
        queuedJob = false;
      }
      // Horrible hack, FIXME
      Enumeration<FreenetURI> e = fetchers.keys();
      while(e.hasMoreElements()) {
        FreenetURI uri = (FreenetURI) e.nextElement();
        // Really horrible hack, FIXME
        for(FProxyFetchInProgress f : fetchers.iterateAll(uri)) {
          // FIXME remove on the fly, although cancel must wait
          if(f.canCancel()) {
            if(toRemove == null) toRemove = new ArrayList<FProxyFetchInProgress>();
            toRemove.add(f);
          }
        }
      }
      if(toRemove != null)
      for(FProxyFetchInProgress r : toRemove) {
        if(logMINOR){
          Logger.minor(this,"Removed fetchinprogress:"+r);
        }
        fetchers.removeElement(r.uri, r);
      }
    }
    if(toRemove != null)
    for(FProxyFetchInProgress r : toRemove) {
      if(logMINOR)
        Logger.minor(this, "Cancelling for "+r);
      r.finishCancel();
    }
    if(needRequeue)
      context.ticker.queueTimedJob(this, FProxyFetchInProgress.LIFETIME);
  }

  public int makeRandomElementID() {
    return context.fastWeakRandom.nextInt();
  }

}
TOP

Related Classes of freenet.clients.http.FProxyFetchTracker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.