@Override
  public synchronized void succeeded(final BaseSendableGet succeeded, boolean persistent) {
    if (persistent) {
      try {
        jobRunner.queue(
            new DBJob() {

              @Override
              public boolean run(ObjectContainer container, ClientContext context) {
                if (container.ext().isActive(succeeded))
                  Logger.error(this, "ALREADY ACTIVE in succeeded(): " + succeeded);
                container.activate(succeeded, 1);
                schedCore.succeeded(succeeded, container);
                container.deactivate(succeeded, 1);
                return false;
              }

              @Override
              public String toString() {
                return "BaseSendableGet succeeded";
              }
            },
            TRIP_PENDING_PRIORITY,
            false);
      } catch (DatabaseDisabledException e) {
        Logger.error(
            this,
            "succeeded() on a persistent request but database disabled",
            new Exception("error"));
      }
      // Boost the priority so the PersistentChosenRequest gets deleted reasonably quickly.
    } else schedTransient.succeeded(succeeded, null);
  }
 /**
  * Register a group of requests (not inserts): a GotKeyListener and/or one or more SendableGet's.
  *
  * @param listener Listens for specific keys. Can be null if the listener is already registered
  *     i.e. on retrying.
  * @param getters The actual requests to register to the request sender queue.
  * @param persistent True if the request is persistent.
  * @param onDatabaseThread True if we are running on the database thread. NOTE:
  *     delayedStoreCheck/probablyNotInStore is unnecessary because we only register the listener
  *     once.
  * @throws FetchException
  */
 public void register(
     final HasKeyListener hasListener,
     final SendableGet[] getters,
     final boolean persistent,
     ObjectContainer container,
     final BlockSet blocks,
     final boolean noCheckStore)
     throws KeyListenerConstructionException {
   if (logMINOR) Logger.minor(this, "register(" + persistent + "," + hasListener + "," + getters);
   if (isInsertScheduler) {
     IllegalStateException e = new IllegalStateException("finishRegister on an insert scheduler");
     throw e;
   }
   if (persistent) {
     innerRegister(hasListener, getters, blocks, noCheckStore, container);
   } else {
     final KeyListener listener;
     if (hasListener != null) {
       listener = hasListener.makeKeyListener(container, clientContext, false);
       if (listener != null) schedTransient.addPendingKeys(listener);
       else Logger.normal(this, "No KeyListener for " + hasListener);
     } else listener = null;
     if (getters != null && !noCheckStore) {
       for (SendableGet getter : getters) datastoreChecker.queueTransientRequest(getter, blocks);
     } else {
       boolean anyValid = false;
       for (int i = 0; i < getters.length; i++) {
         if (!(getters[i].isCancelled(null)
             || getters[i].getCooldownTime(container, clientContext, System.currentTimeMillis())
                 != 0)) anyValid = true;
       }
       finishRegister(getters, false, container, anyValid, null);
     }
   }
 }
 public void reregisterAll(
     final ClientRequester request, ObjectContainer container, short oldPrio) {
   schedTransient.reregisterAll(request, random, this, null, clientContext, oldPrio);
   if (schedCore != null)
     schedCore.reregisterAll(request, random, this, container, clientContext, oldPrio);
   starter.wakeUp();
 }
  public void registerInsert(
      final SendableRequest req, boolean persistent, boolean regmeOnly, ObjectContainer container) {
    if (!isInsertScheduler)
      throw new IllegalArgumentException("Adding a SendableInsert to a request scheduler!!");
    if (persistent) {
      if (regmeOnly) {
        long bootID = 0;
        boolean queueFull = jobRunner.getQueueSize(NativeThread.NORM_PRIORITY) >= QUEUE_THRESHOLD;
        if (!queueFull) bootID = this.node.bootID;
        final RegisterMe regme =
            new RegisterMe(req, req.getPriorityClass(container), schedCore, null, bootID);
        container.store(regme);
        if (logMINOR) Logger.minor(this, "Added insert RegisterMe: " + regme);
        if (!queueFull) {
          try {
            jobRunner.queue(
                new DBJob() {

                  @Override
                  public boolean run(ObjectContainer container, ClientContext context) {
                    container.delete(regme);
                    if (req.isCancelled(container)) {
                      if (logMINOR) Logger.minor(this, "Request already cancelled");
                      return false;
                    }
                    if (container.ext().isActive(req))
                      Logger.error(this, "ALREADY ACTIVE: " + req + " in delayed insert register");
                    container.activate(req, 1);
                    registerInsert(req, true, false, container);
                    container.deactivate(req, 1);
                    return true;
                  }

                  @Override
                  public String toString() {
                    return "registerInsert";
                  }
                },
                NativeThread.NORM_PRIORITY,
                false);
          } catch (DatabaseDisabledException e) {
            // Impossible, we are already on the database thread.
          }
        } else {
          schedCore.rerunRegisterMeRunner(jobRunner);
        }
        container.deactivate(req, 1);
        return;
      }
      schedCore.innerRegister(req, random, container, clientContext, null);
      starter.wakeUp();
    } else {
      schedTransient.innerRegister(req, random, null, clientContext, null);
      starter.wakeUp();
    }
  }
 public void removeFromAllRequestsByClientRequest(
     ClientRequester clientRequest,
     SendableRequest get,
     boolean dontComplain,
     ObjectContainer container) {
   if (get.persistent())
     schedCore.removeFromAllRequestsByClientRequest(get, clientRequest, dontComplain, container);
   else
     schedTransient.removeFromAllRequestsByClientRequest(get, clientRequest, dontComplain, null);
 }
  public void tripPendingKey(final KeyBlock block) {
    if (logMINOR) Logger.minor(this, "tripPendingKey(" + block.getKey() + ")");

    if (offeredKeys != null) {
      offeredKeys.remove(block.getKey());
    }
    final Key key = block.getKey();
    if (schedTransient.anyProbablyWantKey(key, clientContext)) {
      this.clientContext.mainExecutor.execute(
          new PrioRunnable() {

            @Override
            public void run() {
              schedTransient.tripPendingKey(key, block, null, clientContext);
            }

            @Override
            public int getPriority() {
              return TRIP_PENDING_PRIORITY;
            }
          },
          "Trip pending key (transient)");
    }
    if (schedCore == null) return;
    if (schedCore.anyProbablyWantKey(key, clientContext)) {
      try {
        jobRunner.queue(
            new DBJob() {

              @Override
              public boolean run(ObjectContainer container, ClientContext context) {
                if (logMINOR) Logger.minor(this, "tripPendingKey for " + key);
                if (schedCore.tripPendingKey(key, block, container, clientContext))
                  context.jobRunner.setCommitSoon();
                return false;
              }

              @Override
              public String toString() {
                return "tripPendingKey";
              }
            },
            TRIP_PENDING_PRIORITY,
            false);
      } catch (DatabaseDisabledException e) {
        // Nothing to do
      }
    } else schedCore.countNegative();
  }
 private void restoreKey(Key key, ObjectContainer container, long now) {
   SendableGet[] reqs =
       container == null
           ? null
           : (schedCore == null ? null : schedCore.requestsForKey(key, container, clientContext));
   SendableGet[] transientReqs = schedTransient.requestsForKey(key, container, clientContext);
   if (reqs == null && transientReqs == null) {
     // Not an error as this can happen due to race conditions etc.
     if (logMINOR) Logger.minor(this, "Restoring key but no keys queued?? for " + key);
   }
   if (reqs != null) {
     for (int i = 0; i < reqs.length; i++) {
       // Requests may or may not be returned activated from requestsForKey(), so don't check
       // But do deactivate them once we're done with them.
       container.activate(reqs[i], 1);
       reqs[i].requeueAfterCooldown(key, now, container, clientContext);
       container.deactivate(reqs[i], 1);
     }
   }
   if (transientReqs != null) {
     for (int i = 0; i < transientReqs.length; i++)
       transientReqs[i].requeueAfterCooldown(key, now, container, clientContext);
   }
 }
 /**
  * Remove a KeyListener from the list of KeyListeners.
  *
  * @param getter
  * @param complain
  */
 public void removePendingKeys(HasKeyListener getter, boolean complain) {
   boolean found = schedTransient.removePendingKeys(getter);
   if (schedCore != null) found |= schedCore.removePendingKeys(getter);
   if (complain && !found) Logger.error(this, "Listener not found when removing: " + getter);
 }
  void finishRegister(
      final SendableGet[] getters,
      boolean persistent,
      ObjectContainer container,
      final boolean anyValid,
      final DatastoreCheckerItem reg) {
    if (logMINOR)
      Logger.minor(
          this,
          "finishRegister for "
              + getters
              + " anyValid="
              + anyValid
              + " reg="
              + reg
              + " persistent="
              + persistent);
    if (isInsertScheduler) {
      IllegalStateException e = new IllegalStateException("finishRegister on an insert scheduler");
      for (int i = 0; i < getters.length; i++) {
        if (persistent) container.activate(getters[i], 1);
        getters[i].internalError(e, this, container, clientContext, persistent);
        if (persistent) container.deactivate(getters[i], 1);
      }
      throw e;
    }
    if (persistent) {
      // Add to the persistent registration queue
      if (!databaseExecutor.onThread()) {
        throw new IllegalStateException("Not on database thread!");
      }
      if (persistent) container.activate(getters, 1);
      if (logMINOR) Logger.minor(this, "finishRegister() for " + getters);
      if (anyValid) {
        boolean wereAnyValid = false;
        for (int i = 0; i < getters.length; i++) {
          SendableGet getter = getters[i];
          container.activate(getter, 1);
          // Just check isCancelled, we have already checked the cooldown.
          if (!(getter.isCancelled(container))) {
            wereAnyValid = true;
            if (!getter.preRegister(container, clientContext, true)) {
              schedCore.innerRegister(getter, random, container, clientContext, getters);
            }
          } else getter.preRegister(container, clientContext, false);
        }
        if (!wereAnyValid) {
          Logger.normal(this, "No requests valid: " + getters);
        }
      } else {
        Logger.normal(this, "No valid requests passed in: " + getters);
      }
      if (reg != null) container.delete(reg);
      queueFillRequestStarterQueue(true);
    } else {
      // Register immediately.
      for (int i = 0; i < getters.length; i++) {

        if ((!anyValid) || getters[i].isCancelled(null)) {
          getters[i].preRegister(container, clientContext, false);
          continue;
        } else {
          if (getters[i].preRegister(container, clientContext, true)) continue;
        }
        if (!getters[i].isCancelled(null))
          schedTransient.innerRegister(getters[i], random, null, clientContext, getters);
      }
      starter.wakeUp();
    }
  }
 public byte[] saltKey(boolean persistent, Key key) {
   return persistent ? schedCore.saltKey(key) : schedTransient.saltKey(key);
 }
 @Override
 public long countTransientQueuedRequests() {
   return schedTransient.countQueuedRequests(null, clientContext);
 }
 /* FIXME SECURITY When/if introduce tunneling or similar mechanism for starting requests
  * at a distance this will need to be reconsidered. See the comments on the caller in
  * RequestHandler (onAbort() handler). */
 @Override
 public boolean wantKey(Key key) {
   if (schedTransient.anyProbablyWantKey(key, clientContext)) return true;
   if (schedCore != null && schedCore.anyProbablyWantKey(key, clientContext)) return true;
   return false;
 }