/**
   * Triggers pulling of updates up until at least {@code toTxId} if no pulling is currently
   * happening and returns immediately.
   *
   * @return {@link Future} which will block on {@link Future#get()} until {@code toTxId} has been
   *     applied.
   */
  @Override
  public void fulfill(final long toTxId) throws InterruptedException {
    if (!updatePuller.isActive()) {
      throw new IllegalStateException("Update puller not active " + updatePuller);
    }

    updatePuller.await(
        new Condition() {
          @Override
          public boolean evaluate(int currentTicket, int targetTicket) {
            /**
             * We need to await last *closed* transaction id, not last *committed* transaction id
             * since right after leaving this method we might read records off of disk, and they had
             * better be up to date, otherwise we read stale data.
             */
            return transactionIdStore.getLastClosedTransactionId() >= toTxId;
          }
        });
  }