private FinishedTriggersBitSet readFinishedBits(ValueState<BitSet> state) {
    if (!isFinishedSetNeeded()) {
      // If no trigger in the tree will ever have finished bits, then we don't need to read them.
      // So that the code can be agnostic to that fact, we create a BitSet that is all 0 (not
      // finished) for each trigger in the tree.
      return FinishedTriggersBitSet.emptyWithCapacity(rootTrigger.getFirstIndexAfterSubtree());
    }

    BitSet bitSet = state.read();
    return bitSet == null
        ? FinishedTriggersBitSet.emptyWithCapacity(rootTrigger.getFirstIndexAfterSubtree())
        : FinishedTriggersBitSet.fromBitSet(bitSet);
  }
 public TriggerStateMachineRunner(
     ExecutableTriggerStateMachine rootTrigger,
     TriggerStateMachineContextFactory<W> contextFactory) {
   checkState(rootTrigger.getTriggerIndex() == 0);
   this.rootTrigger = rootTrigger;
   this.contextFactory = contextFactory;
 }
 /** Run the trigger logic to deal with a new value. */
 public void processValue(W window, Instant timestamp, Timers timers, StateAccessor<?> state)
     throws Exception {
   // Clone so that we can detect changes and so that changes here don't pollute merging.
   FinishedTriggersBitSet finishedSet = readFinishedBits(state.access(FINISHED_BITS_TAG)).copy();
   TriggerStateMachine.OnElementContext triggerContext =
       contextFactory.createOnElementContext(window, timers, timestamp, rootTrigger, finishedSet);
   rootTrigger.invokeOnElement(triggerContext);
   persistFinishedSet(state, finishedSet);
 }
 public void onFire(W window, Timers timers, StateAccessor<?> state) throws Exception {
   // shouldFire should be false.
   // However it is too expensive to assert.
   FinishedTriggersBitSet finishedSet = readFinishedBits(state.access(FINISHED_BITS_TAG)).copy();
   TriggerStateMachine.TriggerContext context =
       contextFactory.base(window, timers, rootTrigger, finishedSet);
   rootTrigger.invokeOnFire(context);
   persistFinishedSet(state, finishedSet);
 }
 public void prefetchForMerge(
     W window, Collection<W> mergingWindows, MergingStateAccessor<?, W> state) {
   if (isFinishedSetNeeded()) {
     for (ValueState<?> value : state.accessInEachMergingWindow(FINISHED_BITS_TAG).values()) {
       value.readLater();
     }
   }
   rootTrigger
       .getSpec()
       .prefetchOnMerge(
           contextFactory.createMergingStateAccessor(window, mergingWindows, rootTrigger));
 }
  /** Run the trigger merging logic as part of executing the specified merge. */
  public void onMerge(W window, Timers timers, MergingStateAccessor<?, W> state) throws Exception {
    // Clone so that we can detect changes and so that changes here don't pollute merging.
    FinishedTriggersBitSet finishedSet = readFinishedBits(state.access(FINISHED_BITS_TAG)).copy();

    // And read the finished bits in each merging window.
    ImmutableMap.Builder<W, FinishedTriggers> builder = ImmutableMap.builder();
    for (Map.Entry<W, ValueState<BitSet>> entry :
        state.accessInEachMergingWindow(FINISHED_BITS_TAG).entrySet()) {
      // Don't need to clone these, since the trigger context doesn't allow modification
      builder.put(entry.getKey(), readFinishedBits(entry.getValue()));
      // Clear the underlying finished bits.
      clearFinishedBits(entry.getValue());
    }
    ImmutableMap<W, FinishedTriggers> mergingFinishedSets = builder.build();

    TriggerStateMachine.OnMergeContext mergeContext =
        contextFactory.createOnMergeContext(
            window, timers, rootTrigger, finishedSet, mergingFinishedSets);

    // Run the merge from the trigger
    rootTrigger.invokeOnMerge(mergeContext);

    persistFinishedSet(state, finishedSet);
  }
 private boolean isFinishedSetNeeded() {
   // TODO: If we know that no trigger in the tree will ever finish, we don't need to do the
   // lookup. Right now, we special case this for the DefaultTrigger.
   return !(rootTrigger.getSpec() instanceof DefaultTriggerStateMachine);
 }
 /**
  * Clear the state used for executing triggers, but leave the finished set to indicate the window
  * is closed.
  */
 public void clearState(W window, Timers timers, StateAccessor<?> state) throws Exception {
   // Don't need to clone, because we'll be clearing the finished bits anyways.
   FinishedTriggers finishedSet = readFinishedBits(state.access(FINISHED_BITS_TAG));
   rootTrigger.invokeClear(contextFactory.base(window, timers, rootTrigger, finishedSet));
 }
 public boolean shouldFire(W window, Timers timers, StateAccessor<?> state) throws Exception {
   FinishedTriggers finishedSet = readFinishedBits(state.access(FINISHED_BITS_TAG)).copy();
   TriggerStateMachine.TriggerContext context =
       contextFactory.base(window, timers, rootTrigger, finishedSet);
   return rootTrigger.invokeShouldFire(context);
 }
 public void prefetchShouldFire(W window, StateAccessor<?> state) {
   prefetchIsClosed(state);
   rootTrigger
       .getSpec()
       .prefetchShouldFire(contextFactory.createStateAccessor(window, rootTrigger));
 }
 public void prefetchForValue(W window, StateAccessor<?> state) {
   prefetchIsClosed(state);
   rootTrigger
       .getSpec()
       .prefetchOnElement(contextFactory.createStateAccessor(window, rootTrigger));
 }