/**
   * Checks that gets work for implicit txs.
   *
   * @param cache Cache to test.
   * @throws Exception If failed.
   */
  private void checkExplicitTx(Ignite ignite, IgniteCache<String, String> cache) throws Exception {
    IgniteCache<String, String> asyncCache = cache.withAsync();

    Transaction tx = ignite.transactions().txStart();

    try {
      assertNull(cache.get("key1"));

      tx.commit();
    } finally {
      tx.close();
    }

    tx = ignite.transactions().txStart();

    try {
      asyncCache.get("key2");

      assertNull(asyncCache.future().get());

      tx.commit();
    } finally {
      tx.close();
    }

    tx = ignite.transactions().txStart();

    try {
      assertTrue(cache.getAll(F.asSet("key3", "key4")).isEmpty());

      tx.commit();
    } finally {
      tx.close();
    }

    tx = ignite.transactions().txStart();

    try {
      asyncCache.getAll(F.asSet("key5", "key6"));

      assertTrue(((Map) asyncCache.future().get()).isEmpty());

      tx.commit();
    } finally {
      tx.close();
    }

    tx = ignite.transactions().txStart();

    try {
      cache.put("key7", "key7");

      cache.remove("key7");

      assertNull(cache.get("key7"));

      tx.commit();
    } finally {
      tx.close();
    }

    checkEmpty(cache);
  }
  /**
   * @param id Transaction ID.
   * @return Transaction state.
   */
  private int txClose(long id) {
    Transaction tx = tx(id);

    try {
      tx.close();

      return tx.state().ordinal();
    } finally {
      unregisterTx(id);
    }
  }
  /** {@inheritDoc} */
  @Override
  protected void afterTest() throws Exception {
    Transaction tx = jcache().unwrap(Ignite.class).transactions().tx();

    if (tx != null) {
      tx.close();

      fail("Cache transaction remained after test completion: " + tx);
    }

    for (int i = 0; i < gridCount(); i++) {
      info("Checking grid: " + i);

      while (true) {
        try {
          final int fi = i;

          assertTrue(
              "Cache is not empty: "
                  + " localSize = "
                  + jcache(fi).localSize(CachePeekMode.ALL)
                  + ", local entries "
                  + entrySet(jcache(fi).localEntries()),
              GridTestUtils.waitForCondition(
                  // Preloading may happen as nodes leave, so we need to wait.
                  new GridAbsPredicateX() {
                    @Override
                    public boolean applyx() throws IgniteCheckedException {
                      jcache(fi).removeAll();

                      if (jcache(fi).size(CachePeekMode.ALL) > 0) {
                        for (Cache.Entry<String, ?> k : jcache(fi).localEntries())
                          jcache(fi).remove(k.getKey());
                      }

                      return jcache(fi).localSize(CachePeekMode.ALL) == 0;
                    }
                  },
                  getTestTimeout()));

          int primaryKeySize = jcache(i).localSize(CachePeekMode.PRIMARY);
          int keySize = jcache(i).localSize();
          int size = jcache(i).localSize();
          int globalSize = jcache(i).size();
          int globalPrimarySize = jcache(i).size(CachePeekMode.PRIMARY);

          info(
              "Size after [idx="
                  + i
                  + ", size="
                  + size
                  + ", keySize="
                  + keySize
                  + ", primarySize="
                  + primaryKeySize
                  + ", globalSize="
                  + globalSize
                  + ", globalPrimarySize="
                  + globalPrimarySize
                  + ", entrySet="
                  + jcache(i).localEntries()
                  + ']');

          assertEquals(
              "Cache is not empty [idx=" + i + ", entrySet=" + jcache(i).localEntries() + ']',
              0,
              jcache(i).localSize(CachePeekMode.ALL));

          break;
        } catch (Exception e) {
          if (X.hasCause(e, ClusterTopologyCheckedException.class)) {
            info("Got topology exception while tear down (will retry in 1000ms).");

            U.sleep(1000);
          } else throw e;
        }
      }

      for (Cache.Entry<String, Integer> entry : jcache(i).localEntries(CachePeekMode.SWAP))
        jcache(i).remove(entry.getKey());
    }

    assert jcache().unwrap(Ignite.class).transactions().tx() == null;
    assertEquals("Cache is not empty", 0, jcache().localSize(CachePeekMode.ALL));

    resetStore();
  }