Beispiel #1
0
 /** Wipes out all the items currently in the queue, as if all of them are cancelled at once. */
 public synchronized void clear() {
   for (WaitingItem i : waitingList) i.onCancelled();
   waitingList.clear();
   blockedProjects.cancelAll();
   buildables.cancelAll();
   scheduleMaintenance();
 }
Beispiel #2
0
  /**
   * Called by the executor to fetch something to build next.
   *
   * <p>This method blocks until a next project becomes buildable.
   */
  public Queue.Item pop() throws InterruptedException {
    final Executor exec = Executor.currentExecutor();

    try {
      while (true) {
        final JobOffer offer = new JobOffer(exec);
        long sleep = -1;

        synchronized (this) {
          // consider myself parked
          assert !parked.containsKey(exec);
          parked.put(exec, offer);

          // reuse executor thread to do a queue maintenance.
          // at the end of this we get all the buildable jobs
          // in the buildables field.
          maintain();

          // allocate buildable jobs to executors
          Iterator<BuildableItem> itr = buildables.iterator();
          while (itr.hasNext()) {
            BuildableItem p = itr.next();

            // one last check to make sure this build is not blocked.
            if (isBuildBlocked(p.task)) {
              itr.remove();
              blockedProjects.put(p.task, new BlockedItem(p));
              continue;
            }

            JobOffer runner = loadBalancer.choose(p.task, new ApplicableJobOfferList(p.task));
            if (runner == null)
              // if we couldn't find the executor that fits,
              // just leave it in the buildables list and
              // check if we can execute other projects
              continue;

            assert runner.canTake(p.task);

            // found a matching executor. use it.
            runner.set(p);
            itr.remove();
          }

          // we went over all the buildable projects and awaken
          // all the executors that got work to do. now, go to sleep
          // until this thread is awakened. If this executor assigned a job to
          // itself above, the block method will return immediately.

          if (!waitingList.isEmpty()) {
            // wait until the first item in the queue is due
            sleep = peek().timestamp.getTimeInMillis() - new GregorianCalendar().getTimeInMillis();
            if (sleep < 100) sleep = 100; // avoid wait(0)
          }
        }

        // this needs to be done outside synchronized block,
        // so that executors can maintain a queue while others are sleeping
        if (sleep == -1) offer.event.block();
        else offer.event.block(sleep);

        synchronized (this) {
          // retract the offer object
          assert parked.get(exec) == offer;
          parked.remove(exec);

          // am I woken up because I have a project to build?
          if (offer.item != null) {
            // if so, just build it
            LOGGER.fine("Pop returning " + offer.item + " for " + exec.getName());
            offer.item.future.startExecuting(exec);
            return offer.item;
          }
          // otherwise run a queue maintenance
        }
      }
    } finally {
      synchronized (this) {
        // remove myself from the parked list
        JobOffer offer = parked.remove(exec);
        if (offer != null && offer.item != null) {
          // we are already assigned a project,
          // ask for someone else to build it.
          // note that while this thread is waiting for CPU
          // someone else can schedule this build again,
          // so check the contains method first.
          if (!contains(offer.item.task)) buildables.put(offer.item.task, offer.item);
        }

        // since this executor might have been chosen for
        // maintenance, schedule another one. Worst case
        // we'll just run a pointless maintenance, and that's
        // fine.
        scheduleMaintenance();
      }
    }
  }
Beispiel #3
0
  /**
   * Schedules an execution of a task.
   *
   * @since 1.311
   * @return null if this task is already in the queue and therefore the add operation was no-op.
   *     Otherwise indicates the {@link WaitingItem} object added, although the nature of the queue
   *     is that such {@link Item} only captures the state of the item at a particular moment, and
   *     by the time you inspect the object, some of its information can be already stale.
   *     <p>That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#id},
   *     etc.
   */
  private synchronized WaitingItem scheduleInternal(Task p, int quietPeriod, List<Action> actions) {
    WaitingItem added = null;
    List<Item> items = getItems(p);
    Calendar due = new GregorianCalendar();
    due.add(Calendar.SECOND, quietPeriod);

    List<Item> duplicatesInQueue = new ArrayList<Item>();
    for (Item item : items) {
      boolean shouldScheduleItem = false;
      for (Action action : item.getActions()) {
        if (action instanceof QueueAction)
          shouldScheduleItem |= ((QueueAction) action).shouldSchedule(actions);
      }
      for (Action action : actions) {
        if (action instanceof QueueAction) {
          shouldScheduleItem |= ((QueueAction) action).shouldSchedule(item.getActions());
        }
      }
      if (!shouldScheduleItem) {
        duplicatesInQueue.add(item);
      }
    }
    if (duplicatesInQueue.size() == 0) {
      LOGGER.fine(p.getFullDisplayName() + " added to queue");

      // put the item in the queue
      waitingList.add(added = new WaitingItem(due, p, actions));
    } else {
      // the requested build is already queued, so will not be added
      List<WaitingItem> waitingDuplicates = new ArrayList<WaitingItem>();
      for (Item item : duplicatesInQueue) {
        for (Action a : actions) {
          if (a instanceof FoldableAction) {
            ((FoldableAction) a).foldIntoExisting(item.task, item.getActions());
          }
        }
        if ((item instanceof WaitingItem)) waitingDuplicates.add((WaitingItem) item);
      }
      if (duplicatesInQueue.size() == 0) {
        // all duplicates in the queue are already in the blocked or
        // buildable stage no need to requeue
        return null;
      }
      // TODO: avoid calling scheduleMaintenance() if none of the waiting items
      // actually change
      for (WaitingItem wi : waitingDuplicates) {
        if (quietPeriod <= 0) {
          // the user really wants to build now, and they mean NOW.
          // so let's pull in the timestamp if we can.
          if (wi.timestamp.before(due)) continue;
        } else {
          // otherwise we do the normal quiet period implementation
          if (wi.timestamp.after(due)) continue;
          // quiet period timer reset. start the period over again
        }

        // waitingList is sorted, so when we change a timestamp we need to maintain order
        waitingList.remove(wi);
        wi.timestamp = due;
        waitingList.add(wi);
      }
    }
    scheduleMaintenance(); // let an executor know that a new item is in the queue.
    return added;
  }