Repository: incubator-ignite
Updated Branches:
  refs/heads/ignite-446 315e84411 -> 56196599d


ignite-485 Need to implement CacheSortedEvictionPolicy


Project: http://git-wip-us.apache.org/repos/asf/incubator-ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ignite/commit/fabe1a69
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ignite/tree/fabe1a69
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ignite/diff/fabe1a69

Branch: refs/heads/ignite-446
Commit: fabe1a69f318e97000a365419ff7098a272a14a0
Parents: 80b1e05
Author: agura <ag...@gridgain.com>
Authored: Wed Apr 15 20:46:21 2015 +0300
Committer: agura <ag...@gridgain.com>
Committed: Thu Apr 16 20:35:57 2015 +0300

----------------------------------------------------------------------
 .../eviction/sorted/SortedEvictionPolicy.java   | 399 +++++++++++++++++++
 .../sorted/SortedEvictionPolicyMBean.java       |  50 +++
 .../cache/eviction/sorted/package-info.java     |  21 +
 .../GridSortedEvictionPolicySelfTest.java       | 373 +++++++++++++++++
 .../IgniteCacheEvictionSelfTestSuite.java       |   2 +
 5 files changed, 845 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fabe1a69/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicy.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicy.java
 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicy.java
new file mode 100644
index 0000000..b3f3119
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicy.java
@@ -0,0 +1,399 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cache.eviction.sorted;
+
+import org.apache.ignite.cache.eviction.*;
+import org.apache.ignite.internal.util.*;
+import org.apache.ignite.internal.util.typedef.internal.*;
+
+import org.jetbrains.annotations.*;
+import org.jsr166.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.atomic.*;
+
+import static java.lang.Math.*;
+import static org.apache.ignite.configuration.CacheConfiguration.*;
+
+/**
+ * Cache eviction policy which will select the minimum cache entry for 
eviction if cache
+ * size exceeds the {@link #getMaxSize()} parameter. Entries comparison based 
on {@link Comparator} instance if provided.
+ * Default {@code Comparator} behaviour is use cache entries keys for 
comparison that imposes a requirement for keys
+ * to implement {@link Comparable} interface.
+ */
+public class SortedEvictionPolicy<K, V> implements EvictionPolicy<K, V>, 
SortedEvictionPolicyMBean, Serializable {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Maximum size. */
+    private volatile int max;
+
+    /** Order. */
+    private final AtomicLong orderCnt = new AtomicLong();
+
+    /** Backed sorted set. */
+    private final GridConcurrentSkipListSetEx<Holder<K, V>> set;
+
+    /**
+     * Constructs sorted eviction policy with all defaults.
+     */
+    public SortedEvictionPolicy() {
+        this(DFLT_CACHE_SIZE, null);
+    }
+
+    /**
+     * Constructs sorted eviction policy with maximum size.
+     *
+     * @param max Maximum allowed size of cache before entry will start 
getting evicted.
+     */
+    public SortedEvictionPolicy(int max) {
+        this(max, null);
+    }
+
+    /**
+     * Constructs sorted eviction policy with default maximum size and given 
entry comparator.
+     *
+     * @param comp Entries comparator.
+     */
+    public SortedEvictionPolicy(Comparator<EvictableEntry<K, V>> comp) {
+        this(DFLT_CACHE_SIZE, comp);
+    }
+
+    /**
+     * Constructs sorted eviction policy with given maximum size and entries 
comparator.
+     *
+     * @param max Maximum allowed size of cache before entry will start 
getting evicted.
+     * @param comp Entries comparator.
+     */
+    public SortedEvictionPolicy(int max, Comparator<EvictableEntry<K, V>> 
comp) {
+        A.ensure(max > 0, "max > 0");
+
+        this.max = max;
+        this.set = new GridConcurrentSkipListSetEx<>(
+            comp == null ? new DefaultHolderComparator<K, V>() : new 
HolderComparator<>(comp));
+    }
+
+    /**
+     * Gets maximum allowed size of cache before entry will start getting 
evicted.
+     *
+     * @return Maximum allowed size of cache before entry will start getting 
evicted.
+     */
+    @Override public int getMaxSize() {
+        return max;
+    }
+
+    /**
+     * Sets maximum allowed size of cache before entry will start getting 
evicted.
+     *
+     * @param max Maximum allowed size of cache before entry will start 
getting evicted.
+     */
+    @Override public void setMaxSize(int max) {
+        A.ensure(max > 0, "max > 0");
+
+        this.max = max;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getCurrentSize() {
+        return set.sizex();
+    }
+
+    /**
+     * Gets read-only view of backed set in proper order.
+     *
+     * @return Read-only view of backed set.
+     */
+    public Collection<EvictableEntry<K, V>> set() {
+        Set<EvictableEntry<K, V>> cp = new LinkedHashSet<>();
+
+        for (Holder<K, V> holder : set)
+            cp.add(holder.entry);
+
+        return Collections.unmodifiableCollection(cp);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onEntryAccessed(boolean rmv, EvictableEntry<K, V> 
entry) {
+        if (!rmv) {
+            if (!entry.isCached())
+                return;
+
+            if (touch(entry))
+                shrink();
+        }
+        else {
+            Holder<K, V> holder = entry.removeMeta();
+
+            if (holder != null)
+                removeHolder(holder);
+        }
+    }
+
+    /**
+     * @param entry Entry to touch.
+     * @return {@code True} if backed set has been changed by this call.
+     */
+    private boolean touch(EvictableEntry<K, V> entry) {
+        Holder<K, V> holder = entry.meta();
+
+        // Entry has not been add yet to backed set..
+        if (holder == null) {
+            while (true) {
+                holder = new Holder<>(entry, orderCnt.incrementAndGet());
+
+                set.add(holder);
+
+                if (entry.putMetaIfAbsent(holder) != null) {
+                    // Was concurrently added, need to remove it from set.
+                    removeHolder(holder);
+
+                    // Set has not been changed.
+                    return false;
+                }
+                else if (holder.order > 0) {
+                    if (!entry.isCached()) {
+                        // Was concurrently evicted, need to remove it from 
set.
+                        removeHolder(holder);
+
+                        return false;
+                    }
+
+                    return true;
+                }
+                // If holder was removed by concurrent shrink() call, we must 
repeat the whole cycle.
+                else if (!entry.removeMeta(holder))
+                    return false;
+            }
+        }
+
+        // Entry is already in queue.
+        return false;
+    }
+
+    /**
+     * Shrinks backed set to maximum allowed size.
+     */
+    private void shrink() {
+        int max = this.max;
+
+        int startSize = set.sizex();
+
+        if (startSize > max) {
+            for (int i = max; i < startSize && set.sizex() > max; i++) {
+                Holder<K, V> h = set.pollFirst();
+
+                if (h == null)
+                    break;
+
+                EvictableEntry<K, V> entry = h.entry;
+
+                if (h.order > 0 && !entry.evict()) {
+                    entry.removeMeta();
+
+                    touch(entry);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes holder from backed set and marks holder as removed.
+     *
+     * @param holder Holder.
+     */
+    private void removeHolder(Holder<K, V> holder) {
+        long order0 = holder.order;
+
+        if (order0 > 0)
+            holder.order = -order0;
+
+        set.remove(holder);
+    }
+
+    /**
+     * Evictable entry holder.
+     */
+    private static class Holder<K, V> {
+        /** Entry. */
+        private final EvictableEntry<K, V> entry;
+
+        /** Order needs for distinguishing keys that are equal. */
+        private volatile long order;
+
+        /**
+         * Constructs holder for given key.
+         *
+         * @param entry Entry.
+         * @param order Order.
+         */
+        public Holder(EvictableEntry<K, V> entry, long order) {
+            assert order > 0;
+
+            this.entry = entry;
+            this.order = order;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return entry.hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("unchecked")
+        @Override public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+
+            if (obj == null || this.getClass() != obj.getClass())
+                return false;
+
+            Holder<K, V> h = (Holder<K, V>) obj;
+
+            return Objects.equals(entry, h.entry) && abs(order) == 
abs(h.order);
+        }
+    }
+
+    /**
+     * Evictable entries holder comparator. Wrapper for client's comparator.
+     */
+    private static class HolderComparator<K, V> implements 
Comparator<Holder<K, V>>, Serializable {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Keys comparator. */
+        private final Comparator<EvictableEntry<K, V>> comp;
+
+        /**
+         * @param comp Comparator.
+         */
+        public HolderComparator(Comparator<EvictableEntry<K, V>> comp) {
+            A.notNull(comp, "comp");
+
+            this.comp = comp;
+        }
+
+        /** {@inheritDoc} */
+        @Override public int compare(Holder<K, V> h1, Holder<K, V> h2) {
+            if (h1 == h2)
+                return 0;
+
+            EvictableEntry<K, V> e1 = h1.entry;
+            EvictableEntry<K, V> e2 = h2.entry;
+
+            int cmp = comp.compare(e1, e2);
+
+            return cmp == 0 ? Long.compare(abs(h1.order), abs(h2.order)) : cmp;
+        }
+    }
+
+    /**
+     * Default comparator. Uses if comparator isn't provided by client.
+     * Compares only entry keys that should implements {@link Comparable} 
interface.
+     */
+    private static class DefaultHolderComparator<K, V> implements 
Comparator<Holder<K, V>>, Serializable {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** {@inheritDoc} */
+        @SuppressWarnings("unchecked")
+        @Override public int compare(Holder<K, V> h1, Holder<K, V> h2) {
+            if (h1 == h2)
+                return 0;
+
+            EvictableEntry<K, V> e1 = h1.entry;
+            EvictableEntry<K, V> e2 = h2.entry;
+
+            int cmp = ((Comparable<K>) e1.getKey()).compareTo(e2.getKey());
+
+            return cmp == 0 ? Long.compare(abs(h1.order), abs(h2.order)) : cmp;
+        }
+    }
+
+    /**
+     * Provides additional method {@code #sizex()}. NOTE: Only the following 
methods supports this addition:
+     * <ul>
+     *     <li>{@code #add()}</li>
+     *     <li>{@code #remove()}</li>
+     *     <li>{@code #pollFirst()}</li>
+     *     <li>{@code #clone()}</li>
+     * <ul/>
+     */
+    private static class GridConcurrentSkipListSetEx<E> extends 
GridConcurrentSkipListSet<E> {
+        /** */
+        private static final long serialVersionUID = 0L;
+
+        /** Size. */
+        private volatile LongAdder8 size = new LongAdder8();
+
+        /**
+         * @param comp Comparator.
+         */
+        public GridConcurrentSkipListSetEx(Comparator<? super E> comp) {
+            super(comp);
+        }
+
+        /**
+         * @return Size based on performed operations.
+         */
+        public int sizex() {
+            return size.intValue();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean add(E e) {
+            boolean res = super.add(e);
+
+            if (res)
+                size.increment();
+
+            return res;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean remove(Object o) {
+            boolean res = super.remove(o);
+
+            if (res)
+                size.decrement();
+
+            return res;
+        }
+
+        /** {@inheritDoc} */
+        @Nullable @Override public E pollFirst() {
+            E e = super.pollFirst();
+
+            if (e != null)
+                size.decrement();
+
+            return e;
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridConcurrentSkipListSetEx<E> clone() {
+            GridConcurrentSkipListSetEx<E> clone = 
(GridConcurrentSkipListSetEx<E>)super.clone();
+
+            clone.size = new LongAdder8();
+
+            clone.size.add(size.intValue());
+
+            return clone;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fabe1a69/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicyMBean.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicyMBean.java
 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicyMBean.java
new file mode 100644
index 0000000..f8b0d23
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/SortedEvictionPolicyMBean.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.cache.eviction.sorted;
+
+import org.apache.ignite.mxbean.*;
+
+/**
+ * MBean for sorted eviction policy.
+ */
+@MXBeanDescription("MBean for sorted cache eviction policy.")
+public interface SortedEvictionPolicyMBean {
+    /**
+     * Gets maximum allowed cache size.
+     *
+     * @return Maximum allowed cache size.
+     */
+    @MXBeanDescription("Maximum allowed cache size.")
+    public int getMaxSize();
+
+    /**
+     * Sets maximum allowed cache size.
+     *
+     * @param max Maximum allowed cache size.
+     */
+    @MXBeanDescription("Set maximum allowed cache size.")
+    public void setMaxSize(int max);
+
+    /**
+     * Gets current size.
+     *
+     * @return Current size.
+     */
+    @MXBeanDescription("Current sorted key set size.")
+    public int getCurrentSize();
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fabe1a69/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/package-info.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/package-info.java
 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/package-info.java
new file mode 100644
index 0000000..5d59333
--- /dev/null
+++ 
b/modules/core/src/main/java/org/apache/ignite/cache/eviction/sorted/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Contains cache sorted eviction policy implementation.
+ */
+package org.apache.ignite.cache.eviction.sorted;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fabe1a69/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/sorted/GridSortedEvictionPolicySelfTest.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/sorted/GridSortedEvictionPolicySelfTest.java
 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/sorted/GridSortedEvictionPolicySelfTest.java
new file mode 100644
index 0000000..5e255a1
--- /dev/null
+++ 
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/eviction/sorted/GridSortedEvictionPolicySelfTest.java
@@ -0,0 +1,373 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.processors.cache.eviction.sorted;
+
+import org.apache.ignite.*;
+import org.apache.ignite.cache.eviction.*;
+import org.apache.ignite.cache.eviction.sorted.*;
+import org.apache.ignite.internal.processors.cache.eviction.*;
+
+import java.util.*;
+
+import static org.apache.ignite.cache.CacheMode.*;
+
+/**
+ * Sorted eviction test.
+ */
+public class GridSortedEvictionPolicySelfTest extends
+    GridCacheEvictionAbstractTest<SortedEvictionPolicy<String, String>> {
+    /**
+     * @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");
+
+            SortedEvictionPolicy<String, String> p = policy();
+
+            p.setMaxSize(3);
+
+            p.onEntryAccessed(false, e1);
+
+            check(p.set(), e1);
+
+            p.onEntryAccessed(false, e2);
+
+            check(p.set(), e1, e2);
+
+            p.onEntryAccessed(false, e3);
+
+            check(p.set(), e1, e2, e3);
+
+            assertFalse(e1.isEvicted());
+            assertFalse(e2.isEvicted());
+            assertFalse(e3.isEvicted());
+
+            assertEquals(3, p.getCurrentSize());
+
+            p.onEntryAccessed(false, e4);
+
+            check(p.set(), e2, e3, e4);
+
+            assertEquals(3, p.getCurrentSize());
+
+            assertTrue(e1.isEvicted());
+            assertFalse(e2.isEvicted());
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+
+            p.onEntryAccessed(false, e5);
+
+            check(p.set(), e3, e4, e5);
+
+            assertEquals(3, p.getCurrentSize());
+
+            assertTrue(e2.isEvicted());
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(false, e1 = new MockEntry("1", "1"));
+
+            check(p.set(), e3, e4, e5);
+
+            assertEquals(3, p.getCurrentSize());
+
+            assertTrue(e1.isEvicted());
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(false, e5);
+
+            check(p.set(), e3, e4, e5);
+
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(false, e1);
+
+            assertEquals(3, p.getCurrentSize());
+
+            check(p.set(), e3, e4, e5);
+
+            assertTrue(e1.isEvicted());
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(false, e5);
+
+            assertEquals(3, p.getCurrentSize());
+
+            check(p.set(), e3, e4, e5);
+
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(true, e3);
+
+            assertEquals(2, p.getCurrentSize());
+
+            assertFalse(e3.isEvicted());
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(true, e4);
+
+            assertEquals(1, p.getCurrentSize());
+
+            assertFalse(e4.isEvicted());
+            assertFalse(e5.isEvicted());
+
+            p.onEntryAccessed(true, e5);
+
+            assertEquals(0, p.getCurrentSize());
+
+            assertFalse(e5.isEvicted());
+
+            info(p);
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMemory() throws Exception {
+        try {
+            startGrid();
+
+            SortedEvictionPolicy<String, String> p = policy();
+
+            int max = 10;
+
+            p.setMaxSize(max);
+
+            int cnt = 11;
+
+            for (int i = 0; i < cnt; i++)
+                p.onEntryAccessed(false, new MockEntry(Integer.toString(i), 
Integer.toString(i)));
+
+            info(p);
+
+            assertEquals(max, p.getCurrentSize());
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testRandom() throws Exception {
+        try {
+            startGrid();
+
+            SortedEvictionPolicy<String, String> p = policy();
+
+            int max = 10;
+
+            p.setMaxSize(max);
+
+            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();
+
+            assertTrue("curSize <= max [curSize=" + curSize + ", max=" + max + 
']', curSize <= max);
+        }
+        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");
+
+            SortedEvictionPolicy<String, String> p = policy();
+
+            p.setMaxSize(10);
+
+            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 = 100;
+
+        Ignite ignite = startGrid();
+
+        try {
+            IgniteCache<Object, Object> 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;
+                }
+            }
+
+            assertTrue("Min cache size is too small: " + min, min >= plcMax);
+
+            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());
+
+            assertTrue("Min cache size is too small: " + min, min >= plcMax);
+        }
+        finally {
+            stopAllGrids();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected SortedEvictionPolicy<String, String> createPolicy(int 
plcMax) {
+        return new SortedEvictionPolicy<>(plcMax);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected SortedEvictionPolicy<String, String> 
createNearPolicy(int nearMax) {
+        return new SortedEvictionPolicy<>(nearMax);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void checkNearPolicies(int endNearPlcSize) {
+        for (int i = 0; i < gridCnt; i++)
+            for (EvictableEntry<String, String> e : nearPolicy(i).set())
+                assert !e.isCached() : "Invalid near policy size: " + 
nearPolicy(i).set();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void checkPolicies(int plcMax) {
+        for (int i = 0; i < gridCnt; i++)
+            assert policy(i).set().size() <= plcMax;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/fabe1a69/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheEvictionSelfTestSuite.java
----------------------------------------------------------------------
diff --git 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheEvictionSelfTestSuite.java
 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheEvictionSelfTestSuite.java
index 1037b54..2c0c46d 100644
--- 
a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheEvictionSelfTestSuite.java
+++ 
b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheEvictionSelfTestSuite.java
@@ -24,6 +24,7 @@ import org.apache.ignite.internal.processors.cache.eviction.*;
 import org.apache.ignite.internal.processors.cache.eviction.fifo.*;
 import org.apache.ignite.internal.processors.cache.eviction.lru.*;
 import org.apache.ignite.internal.processors.cache.eviction.random.*;
+import org.apache.ignite.internal.processors.cache.eviction.sorted.*;
 
 /**
  * Test suite for cache eviction.
@@ -38,6 +39,7 @@ public class IgniteCacheEvictionSelfTestSuite extends 
TestSuite {
 
         suite.addTest(new 
TestSuite(GridCacheFifoEvictionPolicySelfTest.class));
         suite.addTest(new 
TestSuite(GridCacheFifoBatchEvictionPolicySelfTest.class));
+        suite.addTest(new TestSuite(GridSortedEvictionPolicySelfTest.class));
         suite.addTest(new TestSuite(GridCacheLruEvictionPolicySelfTest.class));
         suite.addTest(new 
TestSuite(GridCacheLruNearEvictionPolicySelfTest.class));
         suite.addTest(new 
TestSuite(GridCacheNearOnlyLruNearEvictionPolicySelfTest.class));

Reply via email to