/** @throws Exception if failed. */
  public void testDynamicCache() throws Exception {
    IgniteEx ignite = startGrid(0);

    String cacheName = "dynamic";

    CacheConfiguration<Object, Object> ccfg = new CacheConfiguration<>(cacheName);

    ccfg.setCacheMode(CacheMode.REPLICATED);
    ccfg.setRebalanceMode(CacheRebalanceMode.SYNC);

    IgniteCache<Object, Object> cache = ignite.createCache(ccfg);

    try (IgniteDataStreamer<Object, Object> streamer = ignite.dataStreamer(cacheName)) {
      streamer.allowOverwrite(true);

      for (int i = 0; i < 100_000; i++) streamer.addData(i, i);
    }

    assertEquals(CNT, cache.localSize());

    Ignite ignite2 = startGrid(1);

    assertEquals(
        CNT, ignite2.cache(cacheName).localSize(CachePeekMode.PRIMARY, CachePeekMode.BACKUP));

    for (int i = 0; i < CNT; i++) assertEquals(i, ignite2.cache(cacheName).localPeek(i));
  }
  /** {@inheritDoc} */
  @SuppressWarnings("unchecked")
  @Override
  public void onEntryAccessed(boolean rmv, EvictableEntry<K, V> entry) {
    if (!entry.isCached()) return;

    IgniteCache<K, V> cache = entry.unwrap(IgniteCache.class);

    int size = cache.localSize(CachePeekMode.ONHEAP);

    for (int i = max; i < size; i++) {
      Cache.Entry<K, V> e = cache.randomEntry();

      if (e != null) e.unwrap(EvictableEntry.class).evict();
    }
  }
  /** {@inheritDoc} */
  @Override
  public void testEvictExpired() throws Exception {
    if (isMultiJvm()) fail("https://issues.apache.org/jira/browse/IGNITE-1113");

    IgniteCache<String, Integer> cache = jcache();

    String key = primaryKeysForCache(cache, 1).get(0);

    cache.put(key, 1);

    assertEquals((Integer) 1, cache.get(key));

    long ttl = 500;

    grid(0)
        .cache(null)
        .withExpiryPolicy(new TouchedExpiryPolicy(new Duration(MILLISECONDS, ttl)))
        .put(key, 1);

    Thread.sleep(ttl + 100);

    // Expired entry should not be swapped.
    cache.localEvict(Collections.singleton(key));

    assertNull(cache.localPeek(key, CachePeekMode.ONHEAP));

    cache.localPromote(Collections.singleton(key));

    assertNull(cache.localPeek(key, CachePeekMode.ONHEAP));

    assertTrue(cache.localSize() == 0);

    load(cache, key, true);

    Affinity<String> aff = ignite(0).affinity(null);

    for (int i = 0; i < gridCount(); i++) {
      if (aff.isPrimaryOrBackup(grid(i).cluster().localNode(), key))
        assertEquals((Integer) 1, peek(jcache(i), key));
    }
  }
  /** @throws Exception if failed. */
  public void testStaticCache() throws Exception {
    IgniteEx ignite = startGrid(0);

    IgniteCache<Object, Object> cache = ignite.cache(STATIC_CACHE_NAME);

    try (IgniteDataStreamer<Object, Object> streamer = ignite.dataStreamer(STATIC_CACHE_NAME)) {
      streamer.allowOverwrite(true);

      for (int i = 0; i < 100_000; i++) streamer.addData(i, i);
    }

    assertEquals(CNT, cache.localSize());

    Ignite ignite2 = startGrid(1);

    assertEquals(
        CNT,
        ignite2.cache(STATIC_CACHE_NAME).localSize(CachePeekMode.PRIMARY, CachePeekMode.BACKUP));

    for (int i = 0; i < CNT; i++) assertEquals(i, ignite2.cache(STATIC_CACHE_NAME).localPeek(i));
  }
  /**
   * JUnit.
   *
   * @throws Exception If failed.
   */
  @SuppressWarnings({"TooBroadScope"})
  public void testRestarts() throws Exception {
    int duration = 60 * 1000;
    int qryThreadNum = 10;
    final long nodeLifeTime = 2 * 1000;
    final int logFreq = 20;

    final IgniteCache<Integer, Integer> cache = grid(0).cache(null);

    assert cache != null;

    for (int i = 0; i < KEY_CNT; i++) cache.put(i, i);

    assertEquals(KEY_CNT, cache.localSize());

    final AtomicInteger qryCnt = new AtomicInteger();

    final AtomicBoolean done = new AtomicBoolean();

    IgniteInternalFuture<?> fut1 =
        multithreadedAsync(
            new CAX() {
              @Override
              public void applyx() throws IgniteCheckedException {
                while (!done.get()) {
                  Collection<Cache.Entry<Integer, Integer>> res =
                      cache.query(new SqlQuery(Integer.class, "_val >= 0")).getAll();

                  assertFalse(res.isEmpty());

                  int c = qryCnt.incrementAndGet();

                  if (c % logFreq == 0) info("Executed queries: " + c);
                }
              }
            },
            qryThreadNum);

    final AtomicInteger restartCnt = new AtomicInteger();

    CollectingEventListener lsnr = new CollectingEventListener();

    for (int i = 0; i < GRID_CNT; i++)
      grid(i).events().localListen(lsnr, EventType.EVT_CACHE_REBALANCE_STOPPED);

    IgniteInternalFuture<?> fut2 =
        multithreadedAsync(
            new Callable<Object>() {
              @SuppressWarnings({"BusyWait"})
              @Override
              public Object call() throws Exception {
                while (!done.get()) {
                  int idx = GRID_CNT;

                  startGrid(idx);

                  Thread.sleep(nodeLifeTime);

                  stopGrid(idx);

                  int c = restartCnt.incrementAndGet();

                  if (c % logFreq == 0) info("Node restarts: " + c);
                }

                return true;
              }
            },
            1);

    Thread.sleep(duration);

    done.set(true);

    fut1.get();
    fut2.get();

    info("Awaiting rebalance events [restartCnt=" + restartCnt.get() + ']');

    boolean success = lsnr.awaitEvents(GRID_CNT * 2 * restartCnt.get(), 15000);

    for (int i = 0; i < GRID_CNT; i++)
      grid(i).events().stopLocalListen(lsnr, EventType.EVT_CACHE_REBALANCE_STOPPED);

    assert success;
  }