예제 #1
0
  private List<GridEvent> getNextSlice(long elapsed) {

    List<GridEvent> slice = new ArrayList<GridEvent>();
    if (elapsed <= 0) return slice;

    this.totalElapsed += elapsed;

    log.trace("getNextSlice, prevElapsed={}, totalElapsed={}", prevElapsed, totalElapsed);

    if (prevElapsed >= totalElapsed) {
      log.warn(
          "No slice possible with (prevElapsed={}, totalElapsed={})", prevElapsed, totalElapsed);
      return slice;
    }

    long start = prevElapsed;
    long end = totalElapsed;

    SortedMap<Long, List<Event>> eventSlice = timeline.getEvents(start, end);

    if (!eventSlice.isEmpty()) {
      // We only move the start of the window up when we find an event. This done because the
      // database might
      // have gaps if the incoming events cannot be processed in real-time. In that case, we don't
      // want to
      // miss any events if they come late.
      this.prevElapsed = totalElapsed;

      log.trace("Timeline has {} offset buckets", timeline.getNumOffsets());
      log.info(
          "Requested slice where {}<=t<{} and got " + eventSlice.size() + " buckets", start, end);
    }

    if (!eventSlice.isEmpty()) {
      for (Long offset : eventSlice.keySet()) {
        log.trace("Got offset bucket {}", offset);
        if (offset >= totalElapsed) {
          log.warn(
              "Timeline returned grid events outside the requested frame: {}>{}",
              offset,
              totalElapsed);
          break;
        }
        List<Event> events = eventSlice.get(offset);
        synchronized (events) {
          if (events.isEmpty()) {
            log.trace("Got empty offset bucket for offset {}", offset);
          }
          for (Event event : events) {
            if (event instanceof GridEvent) {
              GridEvent gridEvent = (GridEvent) event;
              log.trace("Got grid event {}", gridEvent);
              slice.add(gridEvent);
            } else if (event instanceof SnapshotEvent) {
              SnapshotEvent gridEvent = (SnapshotEvent) event;
              log.trace("Got snapshot event {}", gridEvent);
            } else {
              log.trace("Got unrecognized event {}", event);
            }
          }
        }
      }
    }

    return slice;
  }
예제 #2
0
  @Override
  public void run() {

    while (true) {

      switch (playState) {
        case BUFFERING:
          bufferToNextPosition();
          break;

        case PLAYING:
          Date currDate = new Date();
          long elapsed = (int) ((currDate.getTime() - lastSliceRequestDate.getTime()) * playSpeed);
          this.lastSliceRequestDate = currDate;

          // Check if we've been truncated, and move forward if necessary
          if (totalElapsed < timeline.getFirstOffset()) {
            log.info(
                "Elapsed time ({}) occurs before the current timeline ({})",
                totalElapsed,
                timeline.getFirstOffset());

            long position = elapsed;
            boolean noMatch = true;
            while (noMatch) {
              if (position != timeline.getFirstOffset()) {
                position = timeline.getFirstOffset();
                try {
                  Thread.sleep(500);
                } catch (InterruptedException e) {
                  // Ignore
                }
              } else {
                noMatch = false;
              }
            }
            log.info("Will buffer to new position: {}", position);
            bufferAtPosition(position);
            break;
          }

          // Update actors and build a usage map
          Map<String, Integer> slotsUsedByUser = new HashMap<String, Integer>();
          Iterator<? extends Actor> i = getJobActors().values().iterator();
          while (i.hasNext()) {
            Actor actor = i.next();
            if (actor instanceof JobActor) {
              JobActor jobActor = (JobActor) actor;
              if (jobActor.defunct) {
                removeJobActor(jobActor.name, jobActor);
              } else {
                int slots = 1;
                if (jobActor.queued) {
                  // If a job is queued then it is represented by a single sprite, so we need the
                  // actual number of slots
                  GridJob job = state.getJobByFullId(jobActor.name);
                  if (job != null) {
                    slots = job.getSlots();
                  }
                }

                if (jobActor.getName().contains(":")) {
                  // Parse a jobId like this: 1275988.2828-4000:1
                  try {
                    Pattern p = Pattern.compile("(\\d+)\\.(\\d+)-(\\d+):(\\d+)");
                    Matcher m = p.matcher(jobActor.getName());
                    if (m.matches()) {
                      int start = Integer.parseInt(m.group(2));
                      int end = Integer.parseInt(m.group(3));
                      int interval = Integer.parseInt(m.group(4));
                      slots = (end - start) / interval;
                    }
                  } catch (Exception e) {
                    log.error("Error parsing jobId: " + jobActor.getName(), e);
                  }
                } else if (jobActor.getName().contains(",")) {
                  // Parse a jobId like this: 2968157.205,211
                  try {
                    Pattern p = Pattern.compile("(\\d+)\\.(\\d+),(\\d+)");
                    Matcher m = p.matcher(jobActor.getName());
                    if (m.matches()) {
                      int first = Integer.parseInt(m.group(2));
                      int second = Integer.parseInt(m.group(3));
                      // There are two jobs listed here, so we require twice the number of slots
                      slots *= 2;
                    }
                  } catch (Exception e) {
                    log.error("Error parsing jobId: " + jobActor.getName(), e);
                  }
                }

                String user = jobActor.getUsername();
                if (!slotsUsedByUser.containsKey(user)) {
                  slotsUsedByUser.put(user, 0);
                }
                if (!jobActor.queued) {
                  slotsUsedByUser.put(user, slotsUsedByUser.get(user) + slots);
                }
              }
            }
          }

          legend.retain(slotsUsedByUser);

          updateState(elapsed);

          break;

        case READY:
          break;

        case PAUSED:
          break;

        case END:
          return;

        default:
          log.error("Invalid play state: " + playState);
          break;
      }

      try {
        Thread.sleep(50);
      } catch (InterruptedException e) {
        // Ignore
      }
    }
  }
예제 #3
0
  private void bufferToNextPosition() {

    log.info("Buffering to next position: {}", nextStartingPosition);

    int i = 0;
    Snapshot reqSnapshot = null;
    Snapshot prevSnapshot = null;
    for (Snapshot snapshot : timeline.getSnapshots()) {
      long offset = timeline.getOffset(snapshot.getSamplingTime());

      log.debug("Snapshot {} has offset {}", i, offset);

      if (offset >= nextStartingPosition) {
        if (prevSnapshot == null) {
          reqSnapshot = snapshot;
        } else {
          reqSnapshot = prevSnapshot;
        }
        break;
      }
      prevSnapshot = snapshot;
      i++;
    }

    if (reqSnapshot == null) {
      reqSnapshot = prevSnapshot;
      if (reqSnapshot == null) {
        log.error("Could not find snapshot for offset {}", nextStartingPosition);
        setPlayState(PlayState.PAUSED);
        return;
      }
    }

    // Initialize the state at the closest possible snapshot
    log.info(
        "Init with snapshot with offset {}", timeline.getOffset(reqSnapshot.getSamplingTime()));

    this.state = new GridState(reqSnapshot, "runState");
    initState();

    // Apply all events between the closet snapshot and the desired starting position
    this.totalElapsed = timeline.getOffset((reqSnapshot.getSamplingTime())) + 1;
    // This must be set before calling updateState for the first time after changing the position
    // (i.e. totalElapsed)
    this.prevElapsed = totalElapsed;
    long elapsed = nextStartingPosition - totalElapsed;
    if (elapsed < 0) {
      log.warn(
          "Negative time elapsed. Normalizing to nextStartingPosition={}", nextStartingPosition);
      totalElapsed = nextStartingPosition;
      elapsed = nextStartingPosition;
    }

    log.info("Buffering elapsed: {}", elapsed);
    this.tweenChanges = false;
    updateState(elapsed);
    this.tweenChanges = true;

    // Get ready to start playing
    this.lastSliceRequestDate = new Date();
    if (totalElapsed != nextStartingPosition) {
      totalElapsed = nextStartingPosition;
    }

    setPlayState(PlayState.READY);
    log.info("Buffered at totalElapsed={}", totalElapsed);
  }