/**
   * Test logging on {@code DataStreamer.addData()} method when cache have no data nodes
   *
   * @throws Exception If fail.
   */
  public void testNoDataNodesOnFlush() throws Exception {
    boolean failed = false;

    cnt = 0;

    noNodesFilter = true;

    try {
      Ignite ignite = startGrid(1);

      IgniteFuture fut = null;

      try (IgniteDataStreamer<Integer, String> streamer = ignite.dataStreamer(null)) {
        fut = streamer.addData(1, "1");

        streamer.flush();
      } catch (IllegalStateException ex) {
        try {
          fut.get();

          fail("DataStreamer ignores failed streaming.");
        } catch (CacheServerNotFoundException ignored) {
          // No-op.
        }

        failed = true;
      }
    } finally {
      noNodesFilter = false;

      assertTrue(failed);
    }
  }
  private <T> void executeWithTimeout(
      Consumer<IgniteCache<K, V>> cacheOp, Handler<AsyncResult<T>> handler, long timeout) {
    try {
      IgniteCache<K, V> cache = this.cache.withAsync();
      cacheOp.accept(cache);
      IgniteFuture<T> future = cache.future();

      if (timeout >= 0) {
        vertx.executeBlocking(f -> future.get(timeout), handler);
      } else {
        future.listen(fut -> vertx.executeBlocking(f -> f.complete(future.get()), handler));
      }
    } catch (Exception e) {
      handler.handle(Future.failedFuture(e));
    }
  }
  /**
   * @param ignite Ignite instance.
   * @param clo Closure.
   * @return Result of closure execution.
   * @throws Exception If failed.
   */
  protected <T> T doInTransaction(Ignite ignite, Callable<T> clo) throws Exception {
    while (true) {
      try (Transaction tx = ignite.transactions().txStart(PESSIMISTIC, REPEATABLE_READ)) {
        T res = clo.call();

        tx.commit();

        return res;
      } catch (CacheException e) {
        if (e.getCause() instanceof ClusterTopologyException) {
          ClusterTopologyException topEx = (ClusterTopologyException) e.getCause();

          topEx.retryReadyFuture().get();
        } else throw e;
      } catch (ClusterTopologyException e) {
        IgniteFuture<?> fut = e.retryReadyFuture();

        fut.get();
      } catch (TransactionRollbackException ignore) {
        // Safe to retry right away.
      }
    }
  }
  /** @throws Exception If failed. */
  private void checkReentrantLock(final boolean fair) throws Exception {
    // Test API.
    checkLock(fair);

    checkFailoverSafe(fair);

    // Test main functionality.
    IgniteLock lock1 = grid(0).reentrantLock("lock", true, fair, true);

    assertFalse(lock1.isLocked());

    lock1.lock();

    IgniteCompute comp = grid(0).compute().withAsync();

    comp.call(
        new IgniteCallable<Object>() {
          @IgniteInstanceResource private Ignite ignite;

          @LoggerResource private IgniteLogger log;

          @Nullable
          @Override
          public Object call() throws Exception {
            // Test reentrant lock in multiple threads on each node.
            IgniteInternalFuture<?> fut =
                GridTestUtils.runMultiThreadedAsync(
                    new Callable<Object>() {
                      @Nullable
                      @Override
                      public Object call() throws Exception {
                        IgniteLock lock = ignite.reentrantLock("lock", true, fair, true);

                        assert lock != null;

                        log.info(
                            "Thread is going to wait on reentrant lock: "
                                + Thread.currentThread().getName());

                        assert lock.tryLock(1, MINUTES);

                        log.info("Thread is again runnable: " + Thread.currentThread().getName());

                        lock.unlock();

                        return null;
                      }
                    },
                    5,
                    "test-thread");

            fut.get();

            return null;
          }
        });

    IgniteFuture<Object> fut = comp.future();

    Thread.sleep(3000);

    assert lock1.isHeldByCurrentThread();

    assert lock1.getHoldCount() == 1;

    lock1.lock();

    assert lock1.isHeldByCurrentThread();

    assert lock1.getHoldCount() == 2;

    lock1.unlock();

    lock1.unlock();

    // Ensure there are no hangs.
    fut.get();

    // Test operations on removed lock.
    lock1.close();

    checkRemovedReentrantLock(lock1);
  }
  /** @throws Exception If test fails. */
  public void testBasicOpsAsync() throws Exception {
    CountDownLatch latch = new CountDownLatch(3);

    CacheEventListener lsnr = new CacheEventListener(latch);

    try {
      IgniteCache<String, String> cache1 = ignite1.cache(null);
      IgniteCache<String, String> cache1Async = cache1.withAsync();
      IgniteCache<String, String> cache2 = ignite2.cache(null);
      IgniteCache<String, String> cache2Async = cache2.withAsync();
      IgniteCache<String, String> cache3 = ignite3.cache(null);
      IgniteCache<String, String> cache3Async = cache3.withAsync();

      ignite1.events().localListen(lsnr, EVT_CACHE_OBJECT_PUT, EVT_CACHE_OBJECT_REMOVED);
      ignite2.events().localListen(lsnr, EVT_CACHE_OBJECT_PUT, EVT_CACHE_OBJECT_REMOVED);
      ignite3.events().localListen(lsnr, EVT_CACHE_OBJECT_PUT, EVT_CACHE_OBJECT_REMOVED);

      cache1Async.get("async1");

      IgniteFuture<String> f1 = cache1Async.future();

      assert f1.get() == null;

      cache1Async.put("async1", "asyncval1");

      cache1Async.future().get();

      cache1Async.get("async1");

      f1 = cache1Async.future();

      String v1 = f1.get();

      assert v1 != null;
      assert "asyncval1".equals(v1);

      assert latch.await(5, SECONDS);

      cache2Async.get("async1");

      IgniteFuture<String> f2 = cache2Async.future();

      cache3Async.get("async1");

      IgniteFuture<String> f3 = cache3Async.future();

      String v2 = f2.get();
      String v3 = f3.get();

      assert v2 != null;
      assert v3 != null;

      assert "asyncval1".equals(v2);
      assert "asyncval1".equals(v3);

      lsnr.setLatch(latch = new CountDownLatch(3));

      cache2Async.getAndRemove("async1");

      f2 = cache2Async.future();

      assert "asyncval1".equals(f2.get());

      assert latch.await(5, SECONDS);

      cache1Async.get("async1");

      f1 = cache1Async.future();

      cache2Async.get("async1");

      f2 = cache2Async.future();

      cache3Async.get("async1");

      f3 = cache3Async.future();

      v1 = f1.get();
      v2 = f2.get();
      v3 = f3.get();

      info("Removed v1: " + v1);
      info("Removed v2: " + v2);
      info("Removed v3: " + v3);

      assert v1 == null;
      assert v2 == null;
      assert v3 == null;
    } finally {
      ignite1.events().stopLocalListen(lsnr);
      ignite2.events().stopLocalListen(lsnr);
      ignite3.events().stopLocalListen(lsnr);
    }
  }