private void done(Throwable cause) {
      PnfsId pnfsId = getFileAttributes().getPnfsId();
      if (cause != null) {
        if (cause instanceof InterruptedException || cause instanceof CancellationException) {
          cause = new TimeoutCacheException("Flush was cancelled.", cause);
        }

        if (cause instanceof CacheException) {
          infoMsg.setResult(((CacheException) cause).getRc(), cause.getMessage());
        } else {
          infoMsg.setResult(CacheException.DEFAULT_ERROR_CODE, cause.getMessage());
        }
      }

      infoMsg.setTransferTime(System.currentTimeMillis() - activatedAt);
      infoMsg.setFileSize(getFileAttributes().getSize());
      infoMsg.setTimeQueued(activatedAt - createdAt);

      if (!suppressedStoreErrors.contains(infoMsg.getResultCode())) {
        if (infoMsg.getResultCode() != 0) {
          LOGGER.warn("Flush of {} failed with: {}.", pnfsId, cause.toString());
        }
        billingStub.notify(infoMsg);
      }

      flushRequests.removeAndCallback(pnfsId, cause);
    }
 /** Cancels requests whose deadline has past. */
 public void cancelExpiredRequests() {
   long now = System.currentTimeMillis();
   for (R request : requests.values()) {
     if (request.getDeadline() <= now) {
       request.cancel();
     }
   }
 }
 public ListenableFuture<Void> activate() {
   if (!state.compareAndSet(State.QUEUED, State.ACTIVE)) {
     return Futures.immediateFailedFuture(
         new IllegalStateException("Request is no longer queued."));
   }
   activatedAt = System.currentTimeMillis();
   return Futures.immediateFuture(null);
 }
  @PreDestroy
  public void shutdown() throws InterruptedException {
    flushRequests.shutdown();
    stageRequests.shutdown();
    removeRequests.shutdown();

    if (timeoutFuture != null) {
      timeoutFuture.cancel(false);
    }
    repository.removeListener(this);

    /* Waits for all requests to have finished. This is blocking to avoid that the
     * repository gets closed nearline storage requests have had a chance to finish.
     */
    long deadline = System.currentTimeMillis() + 3000;
    if (flushRequests.awaitTermination(
        deadline - System.currentTimeMillis(), TimeUnit.MILLISECONDS)) {
      if (stageRequests.awaitTermination(
          deadline - System.currentTimeMillis(), TimeUnit.MILLISECONDS)) {
        removeRequests.awaitTermination(
            deadline - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
      }
    }
  }
 private void done(Throwable cause) {
   PnfsId pnfsId = getFileAttributes().getPnfsId();
   if (cause != null) {
     if (cause instanceof InterruptedException || cause instanceof CancellationException) {
       cause = new TimeoutCacheException("Stage was cancelled.", cause);
     }
     LOGGER.warn("Stage of {} failed with {}.", pnfsId, cause);
   }
   descriptor.close();
   if (cause instanceof CacheException) {
     infoMsg.setResult(((CacheException) cause).getRc(), cause.getMessage());
   } else if (cause != null) {
     infoMsg.setResult(CacheException.DEFAULT_ERROR_CODE, cause.toString());
   }
   infoMsg.setTransferTime(System.currentTimeMillis() - activatedAt);
   billingStub.notify(infoMsg);
   stageRequests.removeAndCallback(pnfsId, cause);
 }
  /**
   * Abstract base class for request implementations.
   *
   * <p>Provides support for registering callbacks and deregistering from a RequestContainer when
   * the request has completed.
   *
   * <p>Implements part of NearlineRequest, although the interface isn't formally implemented.
   * Subclasses implement subinterfaces of NearlineRequest.
   *
   * @param <K> key identifying a request
   */
  private abstract static class AbstractRequest<K> implements Comparable<AbstractRequest<K>> {
    protected enum State {
      QUEUED,
      ACTIVE,
      CANCELED
    }

    private final List<CompletionHandler<Void, K>> callbacks = new ArrayList<>();
    protected final long createdAt = System.currentTimeMillis();
    protected final UUID uuid = UUID.randomUUID();
    protected final NearlineStorage storage;
    protected final AtomicReference<State> state = new AtomicReference<>(State.QUEUED);
    protected volatile long activatedAt;

    private final List<Future<?>> asyncTasks = new ArrayList<>();

    AbstractRequest(NearlineStorage storage) {
      this.storage = storage;
    }

    // Implements NearlineRequest#setIncluded
    public UUID getId() {
      return uuid;
    }

    public long getCreatedAt() {
      return createdAt;
    }

    protected synchronized <T> ListenableFuture<T> register(ListenableFuture<T> future) {
      if (state.get() == State.CANCELED) {
        future.cancel(true);
      } else {
        asyncTasks.add(future);
      }
      return future;
    }

    public ListenableFuture<Void> activate() {
      if (!state.compareAndSet(State.QUEUED, State.ACTIVE)) {
        return Futures.immediateFailedFuture(
            new IllegalStateException("Request is no longer queued."));
      }
      activatedAt = System.currentTimeMillis();
      return Futures.immediateFuture(null);
    }

    // Guarded by the container containing this request
    public void addCallback(CompletionHandler<Void, K> callback) {
      callbacks.add(callback);
    }

    // Guarded by the container containing this request
    public Iterable<CompletionHandler<Void, K>> callbacks() {
      return this.callbacks;
    }

    public void cancel() {
      if (state.getAndSet(State.CANCELED) != State.CANCELED) {
        storage.cancel(uuid);
        synchronized (this) {
          for (Future<?> task : asyncTasks) {
            task.cancel(true);
          }
        }
      }
    }

    public void failed(int rc, String msg) {
      failed(CacheExceptionFactory.exceptionOf(rc, msg));
    }

    public abstract void failed(Exception cause);

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      sb.append(uuid).append(' ').append(state).append(' ').append(new Date(createdAt));
      long activatedAt = this.activatedAt;
      if (activatedAt > 0) {
        sb.append(' ').append(new Date(activatedAt));
      }
      return sb.toString();
    }

    @Override
    public int compareTo(AbstractRequest<K> o) {
      return Longs.compare(createdAt, o.createdAt);
    }
  }