Repository: incubator-ignite Updated Branches: refs/heads/ignite-49 [created] 996cc086a
IGNITE-49 Implemented CacheStatisticsMXBean#getCacheEvictions() Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/c04013d9 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/c04013d9 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/c04013d9 Branch: refs/heads/ignite-49 Commit: c04013d9b89e94fba80bdcae3723cc337cdf09ea Parents: 70d98c2 Author: nikolay_tikhonov <ntikho...@gridgain.com> Authored: Fri Dec 26 12:58:51 2014 +0300 Committer: nikolay_tikhonov <ntikho...@gridgain.com> Committed: Fri Jan 16 14:13:33 2015 +0300 ---------------------------------------------------------------------- .../cache/GridCacheEvictionManager.java | 2 + .../cache/GridCacheMetricsAdapter.java | 51 +-- .../processors/cache/GridCacheTtlManager.java | 2 + .../cache/GridCacheAbstractMetricsSelfTest.java | 309 ++++++++++++++++++- 4 files changed, 344 insertions(+), 20 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/c04013d9/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheEvictionManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheEvictionManager.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheEvictionManager.java index d05a347..6894ed0 100644 --- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheEvictionManager.java +++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheEvictionManager.java @@ -668,6 +668,8 @@ public class GridCacheEvictionManager<K, V> extends GridCacheManagerAdapter<K, V cache.removeEntry(entry); + cache.metrics0().onEvict(); + if (recordable) cctx.events().addEvent(entry.partition(), entry.key(), cctx.nodeId(), (IgniteUuid)null, null, EVT_CACHE_ENTRY_EVICTED, null, false, oldVal, hasVal, null, null, null); http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/c04013d9/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheMetricsAdapter.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheMetricsAdapter.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheMetricsAdapter.java index 63899f8..4849fa5 100644 --- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheMetricsAdapter.java +++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheMetricsAdapter.java @@ -64,8 +64,10 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable /** Number of transaction rollbacks. */ private volatile int txRollbacks; - private volatile long getCnt; - private volatile long putCnt; + /** Number of evictions. */ + private volatile long evictCnt; + + /** Number of removed entries. */ private volatile long rmCnt; /** Cache metrics. */ @@ -95,6 +97,7 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable txCommits = m.txCommits(); txRollbacks = m.txRollbacks(); rmCnt = m.getCacheRemovals(); + evictCnt = m.getCacheEvictions(); } /** @@ -161,7 +164,6 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable /** {@inheritDoc} */ @Override public void clear() { - //TODO: rewrite createTime = U.currentTimeMillis(); readTime = createTime; writeTime = createTime; @@ -207,39 +209,36 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable /** {@inheritDoc} */ @Override public long getCacheGets() { - //TODO: split read - return 0; + return reads; } /** {@inheritDoc} */ @Override public long getCachePuts() { - //TODO: split write - return 0; + return writes; } - @Override - public long getCacheRemovals() { + /** {@inheritDoc} */ + @Override public long getCacheRemovals() { return rmCnt; } - @Override - public long getCacheEvictions() { - //TODO: discuss with Semen - return 0; + /** {@inheritDoc} */ + @Override public long getCacheEvictions() { + return evictCnt; } - @Override - public float getAverageGetTime() { + /** {@inheritDoc} */ + @Override public float getAverageGetTime() { return 0; } - @Override - public float getAveragePutTime() { + /** {@inheritDoc} */ + @Override public float getAveragePutTime() { return 0; } - @Override - public float getAverageRemoveTime() { + /** {@inheritDoc} */ + @Override public float getAverageRemoveTime() { return 0; } @@ -286,6 +285,16 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable } /** + * Cache remove callback. + */ + public void onEvict() { + evictCnt++; + + if (delegate != null) + delegate.onEvict(); + } + + /** * Transaction commit callback. */ public void onTxCommit() { @@ -336,6 +345,8 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable out.writeInt(misses); out.writeInt(txCommits); out.writeInt(txRollbacks); + out.writeLong(rmCnt); + out.writeLong(evictCnt); } /** {@inheritDoc} */ @@ -352,6 +363,8 @@ public class GridCacheMetricsAdapter implements GridCacheMetrics, Externalizable misses = in.readInt(); txCommits = in.readInt(); txRollbacks = in.readInt(); + rmCnt = in.readLong(); + evictCnt = in.readLong(); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/c04013d9/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheTtlManager.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheTtlManager.java b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheTtlManager.java index 20791e2..33ead3a 100644 --- a/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheTtlManager.java +++ b/modules/core/src/main/java/org/gridgain/grid/kernal/processors/cache/GridCacheTtlManager.java @@ -127,6 +127,8 @@ public class GridCacheTtlManager<K, V> extends GridCacheManagerAdapter<K, V> { if (wrapper.entry.onTtlExpired(obsoleteVer)) wrapper.entry.context().cache().removeEntry(wrapper.entry); + wrapper.entry.context().cache().metrics0().onEvict(); + it.remove(); } else http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/c04013d9/modules/core/src/test/java/org/gridgain/grid/kernal/processors/cache/GridCacheAbstractMetricsSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/gridgain/grid/kernal/processors/cache/GridCacheAbstractMetricsSelfTest.java b/modules/core/src/test/java/org/gridgain/grid/kernal/processors/cache/GridCacheAbstractMetricsSelfTest.java index 33fa252..5173837 100644 --- a/modules/core/src/test/java/org/gridgain/grid/kernal/processors/cache/GridCacheAbstractMetricsSelfTest.java +++ b/modules/core/src/test/java/org/gridgain/grid/kernal/processors/cache/GridCacheAbstractMetricsSelfTest.java @@ -18,7 +18,16 @@ package org.gridgain.grid.kernal.processors.cache; import org.apache.ignite.*; +import org.apache.ignite.transactions.*; import org.gridgain.grid.cache.*; +import org.gridgain.grid.util.lang.*; +import org.gridgain.grid.util.typedef.internal.*; +import org.gridgain.testframework.*; + +import javax.cache.expiry.*; +import java.util.*; + +import static java.util.concurrent.TimeUnit.*; /** * Cache metrics test. @@ -134,6 +143,41 @@ public abstract class GridCacheAbstractMetricsSelfTest extends GridCacheAbstract assertEquals(expMisses, misses); } + + /** + * @throws Exception If failed. + */ + public void testMissHitPercentage() throws Exception { + GridCache<Integer, Integer> cache0 = grid(0).cache(null); + + int keyCnt = keyCount(); + + // Put and get a few keys. + for (int i = 0; i < keyCnt; i++) { + cache0.put(i, i); // +1 read + + info("Writes: " + cache0.metrics().writes()); + + for (int j = 0; j < gridCount(); j++) { + GridCache<Integer, Integer> cache = grid(j).cache(null); + + int cacheWrites = cache.metrics().writes(); + + assertEquals("Wrong cache metrics [i=" + i + ", grid=" + j + ']', i + 1, cacheWrites); + } + + assertEquals("Wrong value for key: " + i, Integer.valueOf(i), cache0.get(i)); // +1 read + } + + // Check metrics for the whole cache. + for (int i = 0; i < gridCount(); i++) { + GridCacheMetrics m = grid(i).cache(null).metrics(); + + assertEquals(m.getCacheHits() * 100f / m.getCacheGets(), m.getCacheHitPercentage(), 0.1f); + assertEquals(m.getCacheMisses() * 100f / m.getCacheGets(), m.getCacheMissPercentage(), 0.1f); + } + } + /** * @throws Exception If failed. */ @@ -216,6 +260,9 @@ public abstract class GridCacheAbstractMetricsSelfTest extends GridCacheAbstract assertEquals("Expected 1 hit", 1, cache.metrics().hits()); } + /** + * @throws Exception If failed. + */ public void testRemoves() throws Exception { GridCache<Integer, Integer> cache = grid(0).cache(null); @@ -224,6 +271,266 @@ public abstract class GridCacheAbstractMetricsSelfTest extends GridCacheAbstract // +1 remove cache.remove(1); - assert cache.metrics().getCacheRemovals() == 1; + assertEquals(1L, cache.metrics().getCacheRemovals()); + } + + /** + * @throws Exception If failed. + */ + public void testManualEvictions() throws Exception { + GridCache<Integer, Integer> cache = grid(0).cache(null); + + if (cache.configuration().getCacheMode() == GridCacheMode.PARTITIONED) + return; + + cache.put(1, 1); + + cache.evict(1); + + assertEquals(0L, cache.metrics().getCacheRemovals()); + assertEquals(1L, cache.metrics().getCacheEvictions()); + } + + /** + * @throws Exception If failed. + */ + public void testTxEvictions() throws Exception { + if (grid(0).cache(null).configuration().getAtomicityMode() != GridCacheAtomicityMode.ATOMIC) + checkTtl(true); + } + + /** + * @throws Exception If failed. + */ + public void testNonTxEvictions() throws Exception { + if (grid(0).cache(null).configuration().getAtomicityMode() == GridCacheAtomicityMode.ATOMIC) + checkTtl(false); + } + + /** + * @param inTx + * @throws Exception If failed. + */ + private void checkTtl(boolean inTx) throws Exception { + int ttl = 1000; + + final ExpiryPolicy expiry = new TouchedExpiryPolicy(new Duration(MILLISECONDS, ttl)); + + final GridCache<Integer, Integer> c = grid(0).cache(null); + + final Integer key = primaryKeysForCache(c, 1, 0).get(0); + + c.put(key, 1); + + GridCacheEntry<Integer, Integer> entry = c.entry(key); + + assert entry != null; + + assertEquals(0, entry.timeToLive()); + assertEquals(0, entry.expirationTime()); + assertEquals(0, grid(0).cache(null).metrics().getCacheEvictions()); + + long startTime = System.currentTimeMillis(); + + if (inTx) { + // Rollback transaction for the first time. + IgniteTx tx = grid(0).transactions().txStart(); + + try { + grid(0).jcache(null).withExpiryPolicy(expiry).put(key, 1); + } + finally { + tx.rollback(); + } + + assertEquals(0, entry.timeToLive()); + assertEquals(0, entry.expirationTime()); + } + + // Now commit transaction and check that ttl and expire time have been saved. + IgniteTx tx = inTx ? c.txStart() : null; + + try { + grid(0).jcache(null).withExpiryPolicy(expiry).put(key, 1); + } + finally { + if (tx != null) + tx.commit(); + } + + long[] expireTimes = new long[gridCount()]; + + for (int i = 0; i < gridCount(); i++) { + GridCacheEntry<Object, Object> curEntry = grid(i).cache(null).entry(key); + + if (curEntry.primary() || curEntry.backup()) { + assertEquals(ttl, curEntry.timeToLive()); + + assert curEntry.expirationTime() > startTime; + + expireTimes[i] = curEntry.expirationTime(); + } + } + + // One more update from the same cache entry to ensure that expire time is shifted forward. + U.sleep(100); + + tx = inTx ? c.txStart() : null; + + try { + grid(0).jcache(null).withExpiryPolicy(expiry).put(key, 2); + } + finally { + if (tx != null) + tx.commit(); + } + + for (int i = 0; i < gridCount(); i++) { + GridCacheEntry<Object, Object> curEntry = grid(i).cache(null).entry(key); + + if (curEntry.primary() || curEntry.backup()) { + assertEquals(ttl, curEntry.timeToLive()); + + assert curEntry.expirationTime() > expireTimes[i]; + + expireTimes[i] = curEntry.expirationTime(); + } + } + + // And one more direct update to ensure that expire time is shifted forward. + U.sleep(100); + + assertEquals(0, grid(0).cache(null).metrics().getCacheEvictions()); + + tx = inTx ? c.txStart() : null; + + try { + grid(0).jcache(null).withExpiryPolicy(expiry).put(key, 3); + } + finally { + if (tx != null) + tx.commit(); + } + + for (int i = 0; i < gridCount(); i++) { + GridCacheEntry<Object, Object> curEntry = grid(i).cache(null).entry(key); + + if (curEntry.primary() || curEntry.backup()) { + assertEquals(ttl, curEntry.timeToLive()); + + assert curEntry.expirationTime() > expireTimes[i]; + + expireTimes[i] = curEntry.expirationTime(); + } + } + + // And one more update to ensure that ttl is not changed and expire time is not shifted forward. + U.sleep(100); + + assertEquals(0, grid(0).cache(null).metrics().getCacheEvictions()); + + log.info("Put 4"); + + tx = inTx ? c.txStart() : null; + + try { + grid(0).jcache(null).put(key, 4); + } + finally { + if (tx != null) + tx.commit(); + } + + log.info("Put 4 done"); + + for (int i = 0; i < gridCount(); i++) { + GridCacheEntry<Object, Object> curEntry = grid(i).cache(null).entry(key); + + if (curEntry.primary() || curEntry.backup()) { + assertEquals(ttl, curEntry.timeToLive()); + assertEquals(expireTimes[i], curEntry.expirationTime()); + } + } + + assertEquals(0, grid(0).cache(null).metrics().getCacheEvictions()); + + // Avoid reloading from store. + map.remove(key); + + assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicateX() { + @SuppressWarnings("unchecked") + @Override + public boolean applyx() throws IgniteCheckedException { + try { + if (c.get(key) != null) + return false; + + // Get "cache" field from GridCacheProxyImpl. + GridCacheAdapter c0 = GridTestUtils.getFieldValue(c, "cache"); + + if (!c0.context().deferredDelete()) { + GridCacheEntryEx e0 = c0.peekEx(key); + + return e0 == null || (e0.rawGet() == null && e0.valueBytes() == null); + } else + return true; + } catch (GridCacheEntryRemovedException e) { + throw new RuntimeException(e); + } + } + }, Math.min(ttl * 10, getTestTimeout()))); + + // Ensure that old TTL and expire time are not longer "visible". + entry = c.entry(key); + + assertEquals(0, entry.timeToLive()); + assertEquals(0, entry.expirationTime()); + + // Ensure that next update will not pick old expire time. + + tx = inTx ? c.txStart() : null; + + try { + entry.set(10); + } + finally { + if (tx != null) + tx.commit(); + } + + U.sleep(2000); + + entry = c.entry(key); + + assertEquals((Integer)10, entry.get()); + + assertEquals(0, entry.timeToLive()); + assertEquals(0, entry.expirationTime()); + + if (c.configuration().getCacheMode() != GridCacheMode.PARTITIONED && inTx) + assertEquals(1, grid(0).cache(null).metrics().getCacheEvictions()); + } + + /** + * @param cache Cache. + * @param cnt Keys count. + * @param startFrom Start value for keys search. + * @return Collection of keys for which given cache is primary. + * @throws IgniteCheckedException If failed. + */ + protected List<Integer> primaryKeysForCache(GridCacheProjection<Integer, Integer> cache, int cnt, int startFrom) + throws IgniteCheckedException { + List<Integer> found = new ArrayList<>(cnt); + + for (int i = startFrom; i < startFrom + 100_000; i++) { + if (cache.entry(i).primary()) { + found.add(i); + + if (found.size() == cnt) + return found; + } + } + + throw new IgniteCheckedException("Unable to find " + cnt + " keys as primary for cache."); } }