Return-Path: X-Original-To: apmail-ignite-commits-archive@minotaur.apache.org Delivered-To: apmail-ignite-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 0BD5017442 for ; Wed, 8 Apr 2015 02:04:02 +0000 (UTC) Received: (qmail 17029 invoked by uid 500); 8 Apr 2015 02:03:46 -0000 Delivered-To: apmail-ignite-commits-archive@ignite.apache.org Received: (qmail 17003 invoked by uid 500); 8 Apr 2015 02:03:46 -0000 Mailing-List: contact commits-help@ignite.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@ignite.incubator.apache.org Delivered-To: mailing list commits@ignite.incubator.apache.org Received: (qmail 16994 invoked by uid 99); 8 Apr 2015 02:03:46 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Apr 2015 02:03:46 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_RP_MATCHES_RCVD X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 08 Apr 2015 02:03:20 +0000 Received: (qmail 14854 invoked by uid 99); 8 Apr 2015 02:03:16 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 08 Apr 2015 02:03:16 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 50612E2F1D; Wed, 8 Apr 2015 02:03:16 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: agoncharuk@apache.org To: commits@ignite.incubator.apache.org Date: Wed, 08 Apr 2015 02:03:20 -0000 Message-Id: <80fcdccbaff04200bff32242904dbaff@git.apache.org> In-Reply-To: <7280ee34b8a64d0e89f2d97e4d9ec583@git.apache.org> References: <7280ee34b8a64d0e89f2d97e4d9ec583@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [05/50] [abbrv] incubator-ignite git commit: ignite-396 Batch eviction support added to CacheFifoEvictionPolicy X-Virus-Checked: Checked by ClamAV on apache.org ignite-396 Batch eviction support added to CacheFifoEvictionPolicy Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/8242c151 Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/8242c151 Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/8242c151 Branch: refs/heads/ignite-674 Commit: 8242c1512657dbbb0efe9a3e0238c88d2aac447a Parents: e6a6b64 Author: Andrey Gura Authored: Mon Apr 6 15:18:54 2015 +0300 Committer: Andrey Gura Committed: Mon Apr 6 21:17:21 2015 +0300 ---------------------------------------------------------------------- .../cache/eviction/fifo/FifoEvictionPolicy.java | 58 ++- .../eviction/fifo/FifoEvictionPolicyMBean.java | 16 + .../eviction/GridCacheEvictionAbstractTest.java | 5 +- ...ridCacheFifoBatchEvictionPolicySelfTest.java | 385 +++++++++++++++++++ 4 files changed, 454 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8242c151/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicy.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicy.java b/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicy.java index d32c746..ca3cc1b 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicy.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicy.java @@ -27,8 +27,12 @@ import java.io.*; import java.util.*; /** - * Eviction policy based on {@code First In First Out (FIFO)} algorithm. This - * implementation is very efficient since it does not create any additional + * Eviction policy based on {@code First In First Out (FIFO)} algorithm and supports batch eviction. + *

+ * The eviction starts when the cache size becomes {@code batchSize} elements greater than the maximum size. + * {@code batchSize} elements will be evicted in this case. The default {@code batchSize} value is {@code 1}. + *

+ * This implementation is very efficient since it does not create any additional * table-like data structures. The {@code FIFO} ordering information is * maintained by attaching ordering metadata to cache entries. */ @@ -39,6 +43,9 @@ public class FifoEvictionPolicy implements EvictionPolicy, FifoEvict /** Maximum size. */ private volatile int max = CacheConfiguration.DFLT_CACHE_SIZE; + /** Batch size. */ + private volatile int batchSize = 1; + /** FIFO queue. */ private final ConcurrentLinkedDeque8> queue = new ConcurrentLinkedDeque8<>(); @@ -62,6 +69,20 @@ public class FifoEvictionPolicy implements EvictionPolicy, FifoEvict } /** + * Constructs FIFO eviction policy with maximum size and given batch size. Empty entries are allowed. + * + * @param max Maximum allowed size of cache before entry will start getting evicted. + * @param batchSize Maximum size of batch. + */ + public FifoEvictionPolicy(int max, int batchSize) { + A.ensure(max > 0, "max > 0"); + A.ensure(batchSize > 0, "batchSize > 0"); + + this.max = max; + this.batchSize = batchSize; + } + + /** * Gets maximum allowed size of cache before entry will start getting evicted. * * @return Maximum allowed size of cache before entry will start getting evicted. @@ -82,6 +103,18 @@ public class FifoEvictionPolicy implements EvictionPolicy, FifoEvict } /** {@inheritDoc} */ + @Override public int getBatchSize() { + return batchSize; + } + + /** {@inheritDoc} */ + @Override public void setBatchSize(int batchSize) { + A.ensure(batchSize > 0, "batchSize > 0"); + + this.batchSize = batchSize; + } + + /** {@inheritDoc} */ @Override public int getCurrentSize() { return queue.size(); } @@ -158,18 +191,23 @@ public class FifoEvictionPolicy implements EvictionPolicy, FifoEvict private void shrink() { int max = this.max; + int batchSize = this.batchSize; + int startSize = queue.sizex(); - for (int i = 0; i < startSize && queue.sizex() > max; i++) { - EvictableEntry entry = queue.poll(); + // Shrink only if queue is full. + if (startSize >= max + batchSize) { + for (int i = max; i < startSize && queue.sizex() > max; i++) { + EvictableEntry entry = queue.poll(); - if (entry == null) - break; + if (entry == null) + break; - if (!entry.evict()) { - entry.removeMeta(); + if (!entry.evict()) { + entry.removeMeta(); - touch(entry); + touch(entry); + } } } } @@ -177,11 +215,13 @@ public class FifoEvictionPolicy implements EvictionPolicy, FifoEvict /** {@inheritDoc} */ @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(max); + out.writeInt(batchSize); } /** {@inheritDoc} */ @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { max = in.readInt(); + batchSize = in.readInt(); } /** {@inheritDoc} */ http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8242c151/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicyMBean.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicyMBean.java b/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicyMBean.java index 4827e95..63a413e 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicyMBean.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/eviction/fifo/FifoEvictionPolicyMBean.java @@ -41,6 +41,22 @@ public interface FifoEvictionPolicyMBean { public void setMaxSize(int max); /** + * Gets batch size. + * + * @return batch size. + */ + @MXBeanDescription("Batch size.") + public int getBatchSize(); + + /** + * Sets batch size. + * + * @param batchSize Batch size. + */ + @MXBeanDescription("Set batch size.") + public void setBatchSize(int batchSize); + + /** * Gets current queue size. * * @return Current queue size. http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/8242c151/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionAbstractTest.java ---------------------------------------------------------------------- diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionAbstractTest.java index 2081bfd..e0dab7d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/GridCacheEvictionAbstractTest.java @@ -63,6 +63,9 @@ public abstract class GridCacheEvictionAbstractTest> { + /** + * @throws Exception If failed. + */ + public void testPolicy() throws Exception { + try { + startGrid(); + + MockEntry e1 = new MockEntry("1", "1"); + MockEntry e2 = new MockEntry("2", "2"); + MockEntry e3 = new MockEntry("3", "3"); + MockEntry e4 = new MockEntry("4", "4"); + MockEntry e5 = new MockEntry("5", "5"); + + FifoEvictionPolicy p = policy(); + + p.setMaxSize(3); + + p.setBatchSize(2); + + p.onEntryAccessed(false, e1); + + check(p.queue(), e1); + + p.onEntryAccessed(false, e2); + + check(p.queue(), e1, e2); + + p.onEntryAccessed(false, e3); + + check(p.queue(), e1, e2, e3); + + p.onEntryAccessed(false, e4); + + check(p.queue(), e1, e2, e3, e4); + + assertFalse(e1.isEvicted()); + assertFalse(e2.isEvicted()); + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + + assertEquals(4, p.getCurrentSize()); + + p.onEntryAccessed(false, e5); + + // Batch evicted. + check(p.queue(), e3, e4, e5); + + assertEquals(3, p.getCurrentSize()); + + assertTrue(e1.isEvicted()); + assertTrue(e2.isEvicted()); + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + assertFalse(e5.isEvicted()); + + p.onEntryAccessed(false, e1 = new MockEntry("1", "1")); + + check(p.queue(), e3, e4, e5, e1); + + assertEquals(4, p.getCurrentSize()); + + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + assertFalse(e5.isEvicted()); + assertFalse(e1.isEvicted()); + + p.onEntryAccessed(false, e5); + + check(p.queue(), e3, e4, e5, e1); + + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + assertFalse(e5.isEvicted()); + assertFalse(e1.isEvicted()); + + p.onEntryAccessed(false, e1); + + assertEquals(4, p.getCurrentSize()); + + check(p.queue(), e3, e4, e5, e1); + + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + assertFalse(e5.isEvicted()); + assertFalse(e1.isEvicted()); + + p.onEntryAccessed(true, e1); + + assertEquals(3, p.getCurrentSize()); + + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + assertFalse(e5.isEvicted()); + + p.onEntryAccessed(true, e4); + + assertEquals(2, p.getCurrentSize()); + + assertFalse(e3.isEvicted()); + assertFalse(e5.isEvicted()); + + p.onEntryAccessed(true, e5); + + assertEquals(1, p.getCurrentSize()); + + assertFalse(e3.isEvicted()); + + p.onEntryAccessed(true, e3); + + assertEquals(0, p.getCurrentSize()); + + assertFalse(e3.isEvicted()); + + info(p); + } + finally { + stopAllGrids(); + } + } + + /** + * @throws Exception If failed. + */ + public void testMemory() throws Exception { + try { + startGrid(); + + FifoEvictionPolicy p = policy(); + + int max = 10; + + int batchSize = 2; + + p.setMaxSize(max); + p.setBatchSize(batchSize); + + int cnt = max + batchSize; + + for (int i = 0; i < cnt; i++) + p.onEntryAccessed(false, new MockEntry(Integer.toString(i), Integer.toString(i))); + + info(p); + + assertEquals(cnt - batchSize, p.getCurrentSize()); + } + finally { + stopAllGrids(); + } + } + + /** + * @throws Exception If failed. + */ + public void testRandom() throws Exception { + try { + startGrid(); + + FifoEvictionPolicy p = policy(); + + int max = 10; + + int batchSize = 2; + + p.setMaxSize(max); + + p.setBatchSize(batchSize); + + Random rand = new Random(); + + int keys = 31; + + MockEntry[] fifos = new MockEntry[keys]; + + for (int i = 0; i < fifos.length; i++) + fifos[i] = new MockEntry(Integer.toString(i)); + + int runs = 5000000; + + for (int i = 0; i < runs; i++) { + boolean rmv = rand.nextBoolean(); + + int j = rand.nextInt(fifos.length); + + MockEntry e = entry(fifos, j); + + if (rmv) + fifos[j] = new MockEntry(Integer.toString(j)); + + p.onEntryAccessed(rmv, e); + } + + info(p); + + int curSize = p.getCurrentSize(); + + assert curSize < max + batchSize : + "curSize < max + batchSize [curSize=" + curSize + ", max=" + max + ", batchSize=" + batchSize + ']'; + } + finally { + stopAllGrids(); + } + } + + /** + * @throws Exception If failed. + */ + public void testAllowEmptyEntries() throws Exception { + try { + startGrid(); + + MockEntry e1 = new MockEntry("1"); + + MockEntry e2 = new MockEntry("2"); + + MockEntry e3 = new MockEntry("3"); + + MockEntry e4 = new MockEntry("4"); + + MockEntry e5 = new MockEntry("5"); + + FifoEvictionPolicy p = policy(); + + p.setBatchSize(2); + + p.onEntryAccessed(false, e1); + + assertFalse(e1.isEvicted()); + + p.onEntryAccessed(false, e2); + + assertFalse(e1.isEvicted()); + assertFalse(e2.isEvicted()); + + p.onEntryAccessed(false, e3); + + assertFalse(e1.isEvicted()); + assertFalse(e3.isEvicted()); + + p.onEntryAccessed(false, e4); + + assertFalse(e1.isEvicted()); + assertFalse(e3.isEvicted()); + assertFalse(e4.isEvicted()); + + p.onEntryAccessed(false, e5); + + assertFalse(e1.isEvicted()); + assertFalse(e3.isEvicted()); + assertFalse(e5.isEvicted()); + } + finally { + stopAllGrids(); + } + } + + /** + * @throws Exception If failed. + */ + public void testPut() throws Exception { + mode = LOCAL; + syncCommit = true; + plcMax = 10; + + Ignite ignite = startGrid(); + + try { + IgniteCache cache = ignite.cache(null); + + int cnt = 500; + + int min = Integer.MAX_VALUE; + + int minIdx = 0; + + for (int i = 0; i < cnt; i++) { + cache.put(i, i); + + int cacheSize = cache.size(); + + if (i > plcMax && cacheSize < min) { + min = cacheSize; + minIdx = i; + } + } + + // Batch evicted. + assert min >= plcMax : "Min cache size is too small: " + min; + + info("Min cache size [min=" + min + ", idx=" + minIdx + ']'); + info("Current cache size " + cache.size()); + info("Current cache key size " + cache.size()); + + min = Integer.MAX_VALUE; + + minIdx = 0; + + // Touch. + for (int i = cnt; --i > cnt - plcMax;) { + cache.get(i); + + int cacheSize = cache.size(); + + if (cacheSize < min) { + min = cacheSize; + minIdx = i; + } + } + + info("----"); + info("Min cache size [min=" + min + ", idx=" + minIdx + ']'); + info("Current cache size " + cache.size()); + info("Current cache key size " + cache.size()); + + // Batch evicted. + assert min >= plcMax : "Min cache size is too small: " + min; + } + finally { + stopAllGrids(); + } + } + + /** {@inheritDoc} */ + @Override public void testPartitionedNearDisabled() throws Exception { + plcBatchSize = 2; + + super.testPartitionedNearDisabled(); + } + + /** {@inheritDoc} */ + @Override protected FifoEvictionPolicy createPolicy(int plcMax) { + return new FifoEvictionPolicy<>(10, 2); + } + + /** {@inheritDoc} */ + @Override protected FifoEvictionPolicy createNearPolicy(int nearMax) { + return new FifoEvictionPolicy<>(nearMax, 2); + } + + /** {@inheritDoc} */ + @Override protected void checkNearPolicies(int endNearPlcSize) { + for (int i = 0; i < gridCnt; i++) + for (EvictableEntry e : nearPolicy(i).queue()) + assert !e.isCached() : "Invalid near policy size: " + nearPolicy(i).queue(); + } + + /** {@inheritDoc} */ + @Override protected void checkPolicies(int plcMax) { + for (int i = 0; i < gridCnt; i++) + assert policy(i).queue().size() <= plcMax + policy(i).getBatchSize(); + } + +}