Example #1
0
    /**
     * May be called from within timeReached(), but schedule() is better there.
     *
     * @param timeoutMs
     * @param useEarliestTime if its already scheduled, use the earlier of the two timeouts, else
     *     use the later
     */
    public synchronized void reschedule(long timeoutMs, boolean useEarliestTime) {
      final long now = System.currentTimeMillis();
      long oldTimeout;
      boolean scheduled = _state == TimedEventState.SCHEDULED;
      if (scheduled) oldTimeout = _nextRun - now;
      else oldTimeout = timeoutMs;

      // don't bother rescheduling if within _fuzz ms
      if ((oldTimeout - _fuzz > timeoutMs && useEarliestTime)
          || (oldTimeout + _fuzz < timeoutMs && !useEarliestTime)
          || (!scheduled)) {
        if (scheduled && (now + timeoutMs) < _nextRun) {
          if (_log.shouldLog(Log.INFO))
            _log.info(
                "Re-scheduling: "
                    + this
                    + " timeout = "
                    + timeoutMs
                    + " old timeout was "
                    + oldTimeout
                    + " state: "
                    + _state);
          cancel();
        }
        schedule(timeoutMs);
      }
    }
Example #2
0
    /** Slightly more efficient than reschedule(). Does nothing if already scheduled. */
    public synchronized void schedule(long timeoutMs) {
      if (_log.shouldLog(Log.DEBUG))
        _log.debug("Scheduling: " + this + " timeout = " + timeoutMs + " state: " + _state);
      if (timeoutMs <= 0 && _log.shouldLog(Log.WARN))
        timeoutMs = 1; // otherwise we may execute before _future is updated, which is fine
      // except it triggers 'early execution' warning logging

      // always set absolute time of execution
      _nextRun = timeoutMs + System.currentTimeMillis();

      switch (_state) {
        case RUNNING:
          _rescheduleAfterRun = true; // signal that we need rescheduling.
          break;
        case IDLE: // fall through
        case CANCELLED:
          _future = _pool.schedule(this, timeoutMs);
          _state = TimedEventState.SCHEDULED;
          break;
        case SCHEDULED: // nothing
      }
    }
Example #3
0
    public void run() {
      if (_log.shouldLog(Log.DEBUG)) _log.debug("Running: " + this);
      long before = System.currentTimeMillis();
      long delay = 0;
      synchronized (this) {
        if (_rescheduleAfterRun)
          throw new IllegalStateException("rescheduleAfterRun cannot be true here");

        switch (_state) {
          case CANCELLED:
            return; // goodbye
          case IDLE: // fall through
          case RUNNING:
            throw new IllegalStateException("not possible to be in " + _state);
          case SCHEDULED: // proceed, switch to IDLE in case I need to reschedule
            _state = TimedEventState.IDLE;
        }

        // if I was rescheduled by the user, re-submit myself to the executor.
        int difference = (int) (_nextRun - before); // careful with long uptimes
        if (difference > _fuzz) {
          schedule(difference);
          return;
        }

        // else proceed to run
        _state = TimedEventState.RUNNING;
      }
      // cancel()-ing after this point only works if the event supports it explicitly
      // none of these _future checks should be necessary anymore
      if (_future != null) delay = _future.getDelay(TimeUnit.MILLISECONDS);
      else if (_log.shouldLog(Log.WARN)) _log.warn(_pool + " wtf, no _future " + this);
      // This can be an incorrect warning especially after a schedule(0)
      if (_log.shouldLog(Log.WARN) && delay > 100)
        _log.warn(_pool + " wtf, early execution " + delay + ": " + this);
      else if (_log.shouldLog(Log.WARN) && delay < -1000)
        _log.warn(" wtf, late execution " + (0 - delay) + ": " + this + _pool.debug());
      try {
        timeReached();
      } catch (Throwable t) {
        _log.log(
            Log.CRIT, _pool + ": Timed task " + this + " exited unexpectedly, please report", t);
      } finally { // must be in finally
        synchronized (this) {
          switch (_state) {
            case SCHEDULED: // fall through
            case IDLE:
              throw new IllegalStateException("can't be " + _state);
            case CANCELLED:
              break; // nothing
            case RUNNING:
              _state = TimedEventState.IDLE;
              // do we need to reschedule?
              if (_rescheduleAfterRun) {
                _rescheduleAfterRun = false;
                schedule(_nextRun - System.currentTimeMillis());
              }
          }
        }
      }
      long time = System.currentTimeMillis() - before;
      if (time > 500 && _log.shouldLog(Log.WARN))
        _log.warn(_pool + " wtf, event execution took " + time + ": " + this);
      if (_log.shouldLog(Log.INFO)) {
        // this call is slow - iterates through a HashMap -
        // would be better to have a local AtomicLong if we care
        long completed = _pool.getCompletedTaskCount();
        if (completed % 250 == 0) _log.info(_pool.debug());
      }
    }
Example #4
0
  /**
   * @param event
   * @param timeoutMs
   * @param useEarliestTime if its already scheduled, use the earlier of the two timeouts, else use
   *     the later
   */
  public void addEvent(TimedEvent event, long timeoutMs, boolean useEarliestTime) {
    int totalEvents = 0;
    long now = System.currentTimeMillis();
    long eventTime = now + timeoutMs;
    Long time = Long.valueOf(eventTime);
    synchronized (_events) {
      // remove the old scheduled position, then reinsert it
      Long oldTime = _eventTimes.get(event);
      if (oldTime != null) {
        if (useEarliestTime) {
          if (oldTime.longValue() < eventTime) {
            _events.notifyAll();
            return; // already scheduled for sooner than requested
          } else {
            _events.remove(oldTime);
          }
        } else {
          if (oldTime.longValue() > eventTime) {
            _events.notifyAll();
            return; // already scheduled for later than the given period
          } else {
            _events.remove(oldTime);
          }
        }
      }
      // FIXME if you plan to use this class again
      while (_events.containsKey(time)) time = Long.valueOf(time.longValue() + 1);
      _events.put(time, event);
      _eventTimes.put(event, time);

      if ((_events.size() != _eventTimes.size())) {
        _log.error("Skewed events: " + _events.size() + " for " + _eventTimes.size());
        for (TimedEvent evt : _eventTimes.keySet()) {
          Long when = _eventTimes.get(evt);
          TimedEvent cur = _events.get(when);
          if (cur != evt) {
            _log.error("event " + evt + " @ " + when + ": " + cur);
          }
        }
      }

      totalEvents = _events.size();
      _events.notifyAll();
    }
    if (time.longValue() > eventTime + 100) {
      if (_log.shouldLog(Log.WARN))
        _log.warn(
            "Lots of timer congestion, had to push "
                + event
                + " back "
                + (time.longValue() - eventTime)
                + "ms (# events: "
                + totalEvents
                + ")");
    }
    long timeToAdd = System.currentTimeMillis() - now;
    if (timeToAdd > 50) {
      if (_log.shouldLog(Log.WARN))
        _log.warn(
            "timer contention: took "
                + timeToAdd
                + "ms to add a job with "
                + totalEvents
                + " queued");
    }
  }