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 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 start() {
   chkRequestStarterRT.start();
   chkInsertStarterRT.start();
   sskRequestStarterRT.start();
   sskInsertStarterRT.start();
   chkRequestStarterBulk.start();
   chkInsertStarterBulk.start();
   sskRequestStarterBulk.start();
   sskInsertStarterBulk.start();
 }
  private void fillRequestStarterQueue(ObjectContainer container, ClientContext context) {
    synchronized (this) {
      if (fillingRequestStarterQueue) return;
      fillingRequestStarterQueue = true;
    }
    long now = System.currentTimeMillis();
    try {
      if (logMINOR)
        Logger.minor(
            this,
            "Filling request queue... (SSK=" + isSSKScheduler + " insert=" + isInsertScheduler);
      long noLaterThan = Long.MAX_VALUE;
      boolean checkCooldownQueue = now > nextQueueFillRequestStarterQueue;
      if ((!isInsertScheduler) && checkCooldownQueue) {
        if (persistentCooldownQueue != null)
          noLaterThan = moveKeysFromCooldownQueue(persistentCooldownQueue, true, container);
        noLaterThan =
            Math.min(
                noLaterThan, moveKeysFromCooldownQueue(transientCooldownQueue, false, container));
      }
      // If anything has been re-added, the request starter will have been woken up.
      short fuzz = -1;
      if (PRIORITY_SOFT.equals(choosenPriorityScheduler)) fuzz = -1;
      else if (PRIORITY_HARD.equals(choosenPriorityScheduler)) fuzz = 0;
      boolean added = false;
      synchronized (starterQueue) {
        if (logMINOR && (!isSSKScheduler) && (!isInsertScheduler)) {
          Logger.minor(this, "Scheduling CHK fetches...");
          for (SendableRequest req : runningPersistentRequests) {
            boolean wasActive = container.ext().isActive(req);
            if (!wasActive) container.activate(req, 1);
            Logger.minor(this, "Running persistent request: " + req);
            if (!wasActive) container.deactivate(req, 1);
          }
        }
        // Recompute starterQueueLength
        int length = 0;
        PersistentChosenRequest old = null;
        for (PersistentChosenRequest req : starterQueue) {
          if (old == req) Logger.error(this, "DUPLICATE CHOSEN REQUESTS ON QUEUE: " + req);
          if (old != null && old.request == req.request)
            Logger.error(
                this, "DUPLICATE REQUEST ON QUEUE: " + old + " vs " + req + " both " + req.request);
          boolean ignoreActive = false;
          if (!ignoreActive) {
            if (container.ext().isActive(req.request))
              Logger.warning(
                  this,
                  "REQUEST ALREADY ACTIVATED: "
                      + req.request
                      + " for "
                      + req
                      + " while checking request queue in filling request queue");
            else if (logMINOR)
              Logger.minor(
                  this,
                  "Not already activated for "
                      + req
                      + " in while checking request queue in filling request queue");
          } else if (logMINOR)
            Logger.minor(this, "Ignoring active because just registered: " + req.request);
          req.pruneDuplicates(ClientRequestScheduler.this);
          old = req;
          length += req.sizeNotStarted();
        }
        if (logMINOR)
          Logger.minor(
              this,
              "Queue size: " + length + " SSK=" + isSSKScheduler + " insert=" + isInsertScheduler);
        if (length > MAX_STARTER_QUEUE_SIZE * 3 / 4) {
          if (length >= WARNING_STARTER_QUEUE_SIZE)
            Logger.error(this, "Queue already full: " + length);
          return;
        }
      }

      if ((!isSSKScheduler) && (!isInsertScheduler)) {
        Logger.minor(this, "Scheduling CHK fetches...");
      }
      boolean addedMore = false;
      while (true) {
        SelectorReturn r;
        // Must synchronize on scheduler to avoid problems with cooldown queue. See notes on
        // CooldownTracker.clearCachedWakeup, which also applies to other cooldown operations.
        synchronized (this) {
          r =
              selector.removeFirstInner(
                  fuzz,
                  random,
                  offeredKeys,
                  starter,
                  schedCore,
                  schedTransient,
                  false,
                  true,
                  Short.MAX_VALUE,
                  isRTScheduler,
                  context,
                  container,
                  now);
        }
        SendableRequest request = null;
        if (r != null && r.req != null) request = r.req;
        else {
          if (r != null && r.wakeupTime > 0 && noLaterThan > r.wakeupTime) {
            noLaterThan = r.wakeupTime;
            if (logMINOR)
              Logger.minor(
                  this,
                  "Waking up in " + TimeUtil.formatTime(noLaterThan - now) + " for cooldowns");
          }
        }
        if (request == null) {
          synchronized (ClientRequestScheduler.this) {
            // Don't wake up for a while, but no later than the time we expect the next item to come
            // off the cooldown queue
            if (checkCooldownQueue && !added) {
              nextQueueFillRequestStarterQueue =
                  System.currentTimeMillis() + WAIT_AFTER_NOTHING_TO_START;
              if (nextQueueFillRequestStarterQueue > noLaterThan)
                nextQueueFillRequestStarterQueue = noLaterThan + 1;
            }
          }
          if (addedMore) starter.wakeUp();
          return;
        }
        boolean full = addToStarterQueue(request, container);
        container.deactivate(request, 1);
        if (!added) starter.wakeUp();
        else addedMore = true;
        added = true;
        if (full) {
          if (addedMore) starter.wakeUp();
          return;
        }
      }
    } finally {
      synchronized (this) {
        fillingRequestStarterQueue = false;
      }
    }
  }
  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();
    }
  }
 @Override
 public void wakeStarter() {
   starter.wakeUp();
 }
 /** Queue the offered key */
 public void queueOfferedKey(final Key key, boolean realTime) {
   if (logMINOR) Logger.minor(this, "queueOfferedKey(" + key);
   offeredKeys.queueKey(key);
   starter.wakeUp();
 }
  RequestStarterGroup(
      Node node,
      NodeClientCore core,
      int portNumber,
      RandomSource random,
      Config config,
      SimpleFieldSet fs,
      ClientContext ctx,
      long dbHandle)
      throws InvalidConfigValueException {
    SubConfig schedulerConfig = config.createSubConfig("node.scheduler");
    this.stats = core.nodeStats;

    throttleWindowBulk =
        new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindow"), node);
    throttleWindowRT =
        new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowRT"), node);

    throttleWindowCHK =
        new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowCHK"), node);
    throttleWindowSSK =
        new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowSSK"), node);
    throttleWindowInsert =
        new ThrottleWindowManager(2.0, fs == null ? null : fs.subset("ThrottleWindowInsert"), node);
    throttleWindowRequest =
        new ThrottleWindowManager(
            2.0, fs == null ? null : fs.subset("ThrottleWindowRequest"), node);
    chkRequestThrottleBulk =
        new MyRequestThrottle(
            5000, "CHK Request", fs == null ? null : fs.subset("CHKRequestThrottle"), 32768, false);
    chkRequestThrottleRT =
        new MyRequestThrottle(
            5000,
            "CHK Request (RT)",
            fs == null ? null : fs.subset("CHKRequestThrottleRT"),
            32768,
            true);
    chkRequestStarterBulk =
        new RequestStarter(
            core,
            chkRequestThrottleBulk,
            "CHK Request starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localChkFetchBytesSentAverage,
            stats.localChkFetchBytesReceivedAverage,
            false,
            false,
            false);
    chkRequestStarterRT =
        new RequestStarter(
            core,
            chkRequestThrottleRT,
            "CHK Request starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localChkFetchBytesSentAverage,
            stats.localChkFetchBytesReceivedAverage,
            false,
            false,
            true);
    chkFetchSchedulerBulk =
        new ClientRequestScheduler(
            false, false, false, random, chkRequestStarterBulk, node, core, "CHKrequester", ctx);
    chkFetchSchedulerRT =
        new ClientRequestScheduler(
            false, false, true, random, chkRequestStarterRT, node, core, "CHKrequester", ctx);
    chkRequestStarterBulk.setScheduler(chkFetchSchedulerBulk);
    chkRequestStarterRT.setScheduler(chkFetchSchedulerRT);

    registerSchedulerConfig(
        schedulerConfig, "CHKrequester", chkFetchSchedulerBulk, chkFetchSchedulerRT, false, false);

    // insertThrottle = new ChainedRequestThrottle(10000, 2.0F, requestThrottle);
    // FIXME reenable the above
    chkInsertThrottleBulk =
        new MyRequestThrottle(
            20000, "CHK Insert", fs == null ? null : fs.subset("CHKInsertThrottle"), 32768, false);
    chkInsertThrottleRT =
        new MyRequestThrottle(
            20000,
            "CHK Insert (RT)",
            fs == null ? null : fs.subset("CHKInsertThrottleRT"),
            32768,
            true);
    chkInsertStarterBulk =
        new RequestStarter(
            core,
            chkInsertThrottleBulk,
            "CHK Insert starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localChkInsertBytesSentAverage,
            stats.localChkInsertBytesReceivedAverage,
            true,
            false,
            false);
    chkInsertStarterRT =
        new RequestStarter(
            core,
            chkInsertThrottleRT,
            "CHK Insert starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localChkInsertBytesSentAverage,
            stats.localChkInsertBytesReceivedAverage,
            true,
            false,
            true);
    chkPutSchedulerBulk =
        new ClientRequestScheduler(
            true, false, false, random, chkInsertStarterBulk, node, core, "CHKinserter", ctx);
    chkPutSchedulerRT =
        new ClientRequestScheduler(
            true, false, true, random, chkInsertStarterRT, node, core, "CHKinserter", ctx);
    chkInsertStarterBulk.setScheduler(chkPutSchedulerBulk);
    chkInsertStarterRT.setScheduler(chkPutSchedulerRT);

    registerSchedulerConfig(
        schedulerConfig, "CHKinserter", chkPutSchedulerBulk, chkPutSchedulerRT, false, true);

    sskRequestThrottleBulk =
        new MyRequestThrottle(
            5000, "SSK Request", fs == null ? null : fs.subset("SSKRequestThrottle"), 1024, false);
    sskRequestThrottleRT =
        new MyRequestThrottle(
            5000,
            "SSK Request (RT)",
            fs == null ? null : fs.subset("SSKRequestThrottleRT"),
            1024,
            true);
    sskRequestStarterBulk =
        new RequestStarter(
            core,
            sskRequestThrottleBulk,
            "SSK Request starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localSskFetchBytesSentAverage,
            stats.localSskFetchBytesReceivedAverage,
            false,
            true,
            false);
    sskRequestStarterRT =
        new RequestStarter(
            core,
            sskRequestThrottleRT,
            "SSK Request starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localSskFetchBytesSentAverage,
            stats.localSskFetchBytesReceivedAverage,
            false,
            true,
            true);
    sskFetchSchedulerBulk =
        new ClientRequestScheduler(
            false, true, false, random, sskRequestStarterBulk, node, core, "SSKrequester", ctx);
    sskFetchSchedulerRT =
        new ClientRequestScheduler(
            false, true, true, random, sskRequestStarterRT, node, core, "SSKrequester", ctx);
    sskRequestStarterBulk.setScheduler(sskFetchSchedulerBulk);
    sskRequestStarterRT.setScheduler(sskFetchSchedulerRT);

    registerSchedulerConfig(
        schedulerConfig, "SSKrequester", sskFetchSchedulerBulk, sskFetchSchedulerRT, true, false);

    // insertThrottle = new ChainedRequestThrottle(10000, 2.0F, requestThrottle);
    // FIXME reenable the above
    sskInsertThrottleBulk =
        new MyRequestThrottle(
            20000, "SSK Insert", fs == null ? null : fs.subset("SSKInsertThrottle"), 1024, false);
    sskInsertThrottleRT =
        new MyRequestThrottle(
            20000, "SSK Insert", fs == null ? null : fs.subset("SSKInsertThrottleRT"), 1024, true);
    sskInsertStarterBulk =
        new RequestStarter(
            core,
            sskInsertThrottleBulk,
            "SSK Insert starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localSskInsertBytesSentAverage,
            stats.localSskFetchBytesReceivedAverage,
            true,
            true,
            false);
    sskInsertStarterRT =
        new RequestStarter(
            core,
            sskInsertThrottleRT,
            "SSK Insert starter (" + portNumber + ')',
            stats.requestOutputThrottle,
            stats.requestInputThrottle,
            stats.localSskInsertBytesSentAverage,
            stats.localSskFetchBytesReceivedAverage,
            true,
            true,
            true);
    sskPutSchedulerBulk =
        new ClientRequestScheduler(
            true, true, false, random, sskInsertStarterBulk, node, core, "SSKinserter", ctx);
    sskPutSchedulerRT =
        new ClientRequestScheduler(
            true, true, true, random, sskInsertStarterRT, node, core, "SSKinserter", ctx);
    sskInsertStarterBulk.setScheduler(sskPutSchedulerBulk);
    sskInsertStarterRT.setScheduler(sskPutSchedulerRT);

    registerSchedulerConfig(
        schedulerConfig, "SSKinserter", sskPutSchedulerBulk, sskPutSchedulerRT, true, true);

    schedulerConfig.finishedInitialization();
  }