/** {@inheritDoc} */
  @Override
  public void onUpdate(int cnt) {
    assert cnt >= 0;

    this.cnt = cnt;

    while (internalLatch != null && internalLatch.getCount() > cnt) internalLatch.countDown();
  }
  /** @throws GridException If operation failed. */
  private void initializeLatch() throws GridException {
    if (initGuard.compareAndSet(false, true)) {
      try {
        internalLatch =
            CU.outTx(
                new Callable<CountDownLatch>() {
                  @Override
                  public CountDownLatch call() throws Exception {
                    GridCacheTx tx =
                        CU.txStartInternal(ctx, latchView, PESSIMISTIC, REPEATABLE_READ);

                    try {
                      GridCacheCountDownLatchValue val = latchView.get(key);

                      if (val == null) {
                        if (log.isDebugEnabled())
                          log.debug("Failed to find count down latch with given name: " + name);

                        assert cnt == 0;

                        return new CountDownLatch(cnt);
                      }

                      tx.commit();

                      return new CountDownLatch(val.get());
                    } finally {
                      tx.end();
                    }
                  }
                },
                ctx);

        if (log.isDebugEnabled()) log.debug("Initialized internal latch: " + internalLatch);
      } finally {
        initLatch.countDown();
      }
    } else {
      try {
        initLatch.await();
      } catch (InterruptedException ignored) {
        throw new GridException("Thread has been interrupted.");
      }

      if (internalLatch == null)
        throw new GridException("Internal latch has not been properly initialized.");
    }
  }
  /** {@inheritDoc} */
  @Override
  public boolean await(long timeout, TimeUnit unit) throws GridException {
    initializeLatch();

    try {
      return internalLatch.await(timeout, unit);
    } catch (InterruptedException e) {
      throw new GridInterruptedException(e);
    }
  }
  /** {@inheritDoc} */
  @Override
  public void await() throws GridException {
    initializeLatch();

    try {
      internalLatch.await();
    } catch (InterruptedException e) {
      throw new GridInterruptedException(e);
    }
  }