ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agoncha...@apache.org
Subject [37/47] ignite git commit: IGNITE-5267 - Moved ignite-ps module to ignite-core
Date Sun, 11 Jun 2017 20:04:03 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheSnapshotManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheSnapshotManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheSnapshotManager.java
new file mode 100644
index 0000000..e490e35
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheSnapshotManager.java
@@ -0,0 +1,133 @@
+/*
+ * 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.persistence;
+
+import java.nio.ByteBuffer;
+import java.util.NavigableMap;
+import java.util.UUID;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.pagemem.FullPageId;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.pagemem.snapshot.SnapshotOperation;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedManagerAdapter;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *
+ */
+public class IgniteCacheSnapshotManager extends GridCacheSharedManagerAdapter {
+    /** Snapshot started lock filename. */
+    public static final String SNAPSHOT_RESTORE_STARTED_LOCK_FILENAME = "snapshot-started.loc";
+
+    /**
+     * @param initiatorNodeId Initiator node id.
+     * @param snapshotOperation Snapshot operation.
+     */
+    @Nullable public IgniteInternalFuture startLocalSnapshotOperation(
+        UUID initiatorNodeId,
+        SnapshotOperation snapshotOperation
+    ) throws IgniteCheckedException {
+        return null;
+    }
+
+    /**
+     * @param snapOp current snapshot operation.
+     *
+     * @return {@code true} if next operation must be snapshot, {@code false} if checkpoint must be executed.
+     */
+    public boolean onMarkCheckPointBegin(
+        SnapshotOperation snapOp,
+        NavigableMap<T2<Integer, Integer>, T2<Integer, Integer>> map
+    ) throws IgniteCheckedException {
+        return false;
+    }
+
+    /**
+     *
+     */
+    public void restoreState() throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /**
+     *
+     */
+    public void onCheckPointBegin() {
+        // No-op.
+    }
+
+    /**
+     *
+     */
+    public void beforeCheckpointPageWritten() {
+        // No-op.
+    }
+
+    /**
+     *
+     */
+    public void afterCheckpointPageWritten() {
+        // No-op.
+    }
+
+    /**
+     * @param fullId Full id.
+     */
+    public void beforePageWrite(FullPageId fullId) {
+        // No-op.
+    }
+
+    /**
+     * @param fullId Full id.
+     */
+    public void onPageWrite(FullPageId fullId, ByteBuffer tmpWriteBuf) {
+        // No-op.
+    }
+
+    /**
+     * @param cctx Cctx.
+     */
+    public void onCacheStop(GridCacheContext cctx) {
+        // No-op.
+    }
+
+    /**
+     *
+     */
+    public void onChangeTrackerPage(
+        Long page,
+        FullPageId fullId,
+        PageMemory pageMem
+    ) throws IgniteCheckedException {
+
+    }
+
+    /**
+     *
+     */
+    public void flushDirtyPageHandler(
+        FullPageId fullId,
+        ByteBuffer pageBuf,
+        Integer tag
+    ) throws IgniteCheckedException {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsImpl.java
new file mode 100644
index 0000000..271767c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsImpl.java
@@ -0,0 +1,284 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.MemoryMetrics;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeListImpl;
+import org.apache.ignite.internal.processors.cache.ratemetrics.HitRateMetrics;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.jsr166.LongAdder8;
+
+/**
+ *
+ */
+public class MemoryMetricsImpl implements MemoryMetrics {
+    /** */
+    private FreeListImpl freeList;
+
+    /** */
+    private final LongAdder8 totalAllocatedPages = new LongAdder8();
+
+    /**
+     * Counter for number of pages occupied by large entries (one entry is larger than one page).
+     */
+    private final LongAdder8 largeEntriesPages = new LongAdder8();
+
+    /** Counter for number of dirty pages. */
+    private LongAdder8 dirtyPages = new LongAdder8();
+
+    /** */
+    private volatile boolean metricsEnabled;
+
+    /** */
+    private boolean persistenceEnabled;
+
+    /** */
+    private volatile int subInts;
+
+    /** Allocation rate calculator. */
+    private volatile HitRateMetrics allocRate = new HitRateMetrics(60_000, 5);
+
+    /** */
+    private volatile HitRateMetrics pageReplaceRate = new HitRateMetrics(60_000, 5);
+
+    /** */
+    private final MemoryPolicyConfiguration memPlcCfg;
+
+    /** */
+    private PageMemory pageMem;
+
+    /** Time interval (in milliseconds) when allocations/evictions are counted to calculate rate. */
+    private volatile long rateTimeInterval;
+
+    /**
+     * @param memPlcCfg MemoryPolicyConfiguration.
+     */
+    public MemoryMetricsImpl(MemoryPolicyConfiguration memPlcCfg) {
+        this.memPlcCfg = memPlcCfg;
+
+        metricsEnabled = memPlcCfg.isMetricsEnabled();
+
+        rateTimeInterval = memPlcCfg.getRateTimeInterval();
+
+        subInts = memPlcCfg.getSubIntervals();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return U.maskName(memPlcCfg.getName());
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getTotalAllocatedPages() {
+        return metricsEnabled ? totalAllocatedPages.longValue() : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getAllocationRate() {
+        if (!metricsEnabled)
+            return 0;
+
+        return ((float) allocRate.getRate()) / rateTimeInterval;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getEvictionRate() {
+        return 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getLargeEntriesPagesPercentage() {
+        if (!metricsEnabled)
+            return 0;
+
+        return totalAllocatedPages.longValue() != 0 ?
+                (float) largeEntriesPages.doubleValue() / totalAllocatedPages.longValue()
+                : 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesFillFactor() {
+        if (!metricsEnabled || freeList == null)
+            return 0;
+
+        return freeList.fillFactor();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getDirtyPages() {
+        if (!metricsEnabled || !persistenceEnabled)
+            return 0;
+
+        return dirtyPages.longValue();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesReplaceRate() {
+        if (!metricsEnabled || !persistenceEnabled)
+            return 0;
+
+        return ((float) pageReplaceRate.getRate()) / rateTimeInterval;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getPhysicalMemoryPages() {
+        if (!metricsEnabled || !persistenceEnabled)
+            return 0;
+
+        assert pageMem != null;
+
+        return pageMem.loadedPages();
+    }
+
+    /**
+     * Updates pageReplaceRate metric.
+     */
+    public void updatePageReplaceRate() {
+        if (metricsEnabled)
+            pageReplaceRate.onHit();
+    }
+
+    /**
+     * Increments dirtyPages counter.
+     */
+    public void incrementDirtyPages() {
+        if (metricsEnabled)
+            dirtyPages.increment();
+    }
+
+    /**
+     * Decrements dirtyPages counter.
+     */
+    public void decrementDirtyPages() {
+        if (metricsEnabled)
+            dirtyPages.decrement();
+    }
+
+    /**
+     * Resets dirtyPages counter to zero.
+     */
+    public void resetDirtyPages() {
+        if (metricsEnabled)
+            dirtyPages.reset();
+    }
+
+    /**
+     * Increments totalAllocatedPages counter.
+     */
+    public void incrementTotalAllocatedPages() {
+        if (metricsEnabled) {
+            totalAllocatedPages.increment();
+
+            updateAllocationRateMetrics();
+        }
+    }
+
+    /**
+     *
+     */
+    private void updateAllocationRateMetrics() {
+        allocRate.onHit();
+    }
+
+    /**
+     * @param intervalNum Interval number.
+     */
+    private long subInt(int intervalNum) {
+        return (rateTimeInterval * intervalNum) / subInts;
+    }
+
+    /**
+     *
+     */
+    public void incrementLargeEntriesPages() {
+        if (metricsEnabled)
+            largeEntriesPages.increment();
+    }
+
+    /**
+     *
+     */
+    public void decrementLargeEntriesPages() {
+        if (metricsEnabled)
+            largeEntriesPages.decrement();
+    }
+
+    /**
+     * Enable metrics.
+     */
+    public void enableMetrics() {
+        metricsEnabled = true;
+    }
+
+    /**
+     * Disable metrics.
+     */
+    public void disableMetrics() {
+        metricsEnabled = false;
+    }
+
+    /**
+     * @param persistenceEnabled Persistence enabled.
+     */
+    public void persistenceEnabled(boolean persistenceEnabled) {
+        this.persistenceEnabled = persistenceEnabled;
+    }
+
+    /**
+     * @param pageMem Page mem.
+     */
+    public void pageMemory(PageMemory pageMem) {
+        this.pageMem = pageMem;
+    }
+
+    /**
+     * @param rateTimeInterval Time interval (in milliseconds) used to calculate allocation/eviction rate.
+     */
+    public void rateTimeInterval(long rateTimeInterval) {
+        this.rateTimeInterval = rateTimeInterval;
+
+        allocRate = new HitRateMetrics((int) rateTimeInterval, subInts);
+        pageReplaceRate = new HitRateMetrics((int) rateTimeInterval, subInts);
+    }
+
+    /**
+     * Sets number of subintervals the whole rateTimeInterval will be split into to calculate allocation rate.
+     *
+     * @param subInts Number of subintervals.
+     */
+    public void subIntervals(int subInts) {
+        assert subInts > 0;
+
+        if (this.subInts == subInts)
+            return;
+
+        if (rateTimeInterval / subInts < 10)
+            subInts = (int) rateTimeInterval / 10;
+
+        allocRate = new HitRateMetrics((int) rateTimeInterval, subInts);
+        pageReplaceRate = new HitRateMetrics((int) rateTimeInterval, subInts);
+    }
+
+    /**
+     * @param freeList Free list.
+     */
+    void freeList(FreeListImpl freeList) {
+        this.freeList = freeList;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsMXBeanImpl.java
new file mode 100644
index 0000000..392f83f
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsMXBeanImpl.java
@@ -0,0 +1,131 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.MemoryMetrics;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.mxbean.MemoryMetricsMXBean;
+
+/**
+ * MBean to expose {@link MemoryMetrics} through JMX interface.
+ */
+class MemoryMetricsMXBeanImpl implements MemoryMetricsMXBean {
+    /** */
+    private final MemoryMetricsImpl memMetrics;
+
+    /** */
+    private final MemoryPolicyConfiguration memPlcCfg;
+
+    /**
+     * @param memMetrics MemoryMetrics instance to expose through JMX interface.
+     * @param memPlcCfg configuration of memory policy this MX Bean is created for.
+     */
+    MemoryMetricsMXBeanImpl(MemoryMetricsImpl memMetrics,
+        MemoryPolicyConfiguration memPlcCfg
+    ) {
+        this.memMetrics = memMetrics;
+        this.memPlcCfg = memPlcCfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getAllocationRate() {
+        return memMetrics.getAllocationRate();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getEvictionRate() {
+        return memMetrics.getEvictionRate();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getLargeEntriesPagesPercentage() {
+        return memMetrics.getLargeEntriesPagesPercentage();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesFillFactor() {
+        return memMetrics.getPagesFillFactor();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getTotalAllocatedPages() {
+        return memMetrics.getTotalAllocatedPages();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getDirtyPages() {
+        return memMetrics.getDirtyPages();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesReplaceRate() {
+        return memMetrics.getPagesReplaceRate();
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getPhysicalMemoryPages() {
+        return memMetrics.getPhysicalMemoryPages();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void rateTimeInterval(long rateTimeInterval) {
+        if (rateTimeInterval < 1000)
+            throw new IllegalArgumentException("rateTimeInterval property must be positive " +
+                "and greater than 1_000 milliseconds (one second)");
+
+        memMetrics.rateTimeInterval(rateTimeInterval);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void subIntervals(int subInts) {
+        if (subInts <= 1)
+            throw new IllegalArgumentException("subIntervals property must be positive " +
+                "and greater than one");
+
+        memMetrics.subIntervals(subInts);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void enableMetrics() {
+        memMetrics.enableMetrics();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void disableMetrics() {
+        memMetrics.disableMetrics();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return memMetrics.getName();
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getInitialSize() {
+        return (int) (memPlcCfg.getInitialSize() / (1024 * 1024));
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getMaxSize() {
+        return (int) (memPlcCfg.getMaxSize() / (1024 * 1024));
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getSwapFilePath() {
+        return memPlcCfg.getSwapFilePath();
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsSnapshot.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsSnapshot.java
new file mode 100644
index 0000000..4e7f90a
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryMetricsSnapshot.java
@@ -0,0 +1,112 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.MemoryMetrics;
+
+/**
+ *
+ */
+public class MemoryMetricsSnapshot implements MemoryMetrics {
+    /** */
+    private String name;
+
+    /** */
+    private long totalAllocatedPages;
+
+    /** */
+    private float allocationRate;
+
+    /** */
+    private float evictionRate;
+
+    /** */
+    private float largeEntriesPagesPercentage;
+
+    /** */
+    private float pagesFillFactor;
+
+    /** */
+    private long dirtyPages;
+
+    /** */
+    private float pageReplaceRate;
+
+    /** */
+    private long physicalMemoryPages;
+
+    /**
+     * @param metrics Metrics instance to take a copy.
+     */
+    public MemoryMetricsSnapshot(MemoryMetrics metrics) {
+        name = metrics.getName();
+        totalAllocatedPages = metrics.getTotalAllocatedPages();
+        allocationRate = metrics.getAllocationRate();
+        evictionRate = metrics.getEvictionRate();
+        largeEntriesPagesPercentage = metrics.getLargeEntriesPagesPercentage();
+        pagesFillFactor = metrics.getPagesFillFactor();
+        dirtyPages = metrics.getDirtyPages();
+        pageReplaceRate = metrics.getPagesReplaceRate();
+        physicalMemoryPages = metrics.getPhysicalMemoryPages();
+    }
+
+    /** {@inheritDoc} */
+    @Override public String getName() {
+        return name;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getTotalAllocatedPages() {
+        return totalAllocatedPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getAllocationRate() {
+        return allocationRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getEvictionRate() {
+        return evictionRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getLargeEntriesPagesPercentage() {
+        return largeEntriesPagesPercentage;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesFillFactor() {
+        return pagesFillFactor;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getDirtyPages() {
+        return dirtyPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getPagesReplaceRate() {
+        return pageReplaceRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getPhysicalMemoryPages() {
+        return physicalMemoryPages;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryPolicy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryPolicy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryPolicy.java
new file mode 100644
index 0000000..7c7d7bc
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MemoryPolicy.java
@@ -0,0 +1,83 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.processors.cache.persistence.evict.PageEvictionTracker;
+
+/**
+ * Memory policy provides access to objects configured with {@link MemoryPolicyConfiguration} configuration.
+ */
+public class MemoryPolicy {
+    /** */
+    private final PageMemory pageMem;
+
+    /** */
+    private final MemoryMetricsImpl memMetrics;
+
+    /** */
+    private final MemoryPolicyConfiguration cfg;
+
+    /** */
+    private final PageEvictionTracker evictionTracker;
+
+    /**
+     * @param pageMem PageMemory instance.
+     * @param memMetrics MemoryMetrics instance.
+     * @param cfg Configuration of given MemoryPolicy.
+     * @param evictionTracker Eviction tracker.
+     */
+    public MemoryPolicy(
+        PageMemory pageMem,
+        MemoryPolicyConfiguration cfg,
+        MemoryMetricsImpl memMetrics,
+        PageEvictionTracker evictionTracker) {
+        this.pageMem = pageMem;
+        this.memMetrics = memMetrics;
+        this.cfg = cfg;
+        this.evictionTracker = evictionTracker;
+    }
+
+    /**
+     *
+     */
+    public PageMemory pageMemory() {
+        return pageMem;
+    }
+
+    /**
+     * @return Config.
+     */
+    public MemoryPolicyConfiguration config() {
+        return cfg;
+    }
+
+    /**
+     * @return Memory Metrics.
+     */
+    public MemoryMetricsImpl memoryMetrics() {
+        return memMetrics;
+    }
+
+    /**
+     *
+     */
+    public PageEvictionTracker evictionTracker() {
+        return evictionTracker;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetaStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetaStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetaStore.java
new file mode 100644
index 0000000..c09ce4e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetaStore.java
@@ -0,0 +1,51 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.IgniteCheckedException;
+
+/**
+ * Meta store.
+ */
+public interface MetaStore {
+    /**
+     * Get or allocate initial page for an index.
+     *
+     * @param idxName Index name.
+     * @return {@link RootPage} that keeps pageId, allocated flag that shows whether the page
+     *      was newly allocated, and rootId that is counter which increments each time new page allocated.
+     * @throws IgniteCheckedException If failed.
+     */
+    public RootPage getOrAllocateForTree(String idxName) throws IgniteCheckedException;
+
+    /**
+     * Deallocate index page and remove from tree.
+     *
+     * @param idxName Index name.
+     * @return Root ID or -1 if no page was removed.
+     * @throws IgniteCheckedException  If failed.
+     */
+    public RootPage dropRootPage(String idxName) throws IgniteCheckedException;
+
+    /**
+     * Destroy this meta store.
+     *
+     * @throws IgniteCheckedException  If failed.
+     */
+    public void destroy() throws IgniteCheckedException;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
new file mode 100644
index 0000000..806afb8
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/MetadataStorage.java
@@ -0,0 +1,417 @@
+/*
+ * 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.persistence;
+
+import java.nio.charset.StandardCharsets;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.pagemem.FullPageId;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.pagemem.PageUtils;
+import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
+import org.apache.ignite.internal.processors.cache.persistence.tree.BPlusTree;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusInnerIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.BPlusLeafIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.IOVersions;
+import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList;
+import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ * Metadata storage.
+ */
+public class MetadataStorage implements MetaStore {
+    /** Max index name length (bytes num) */
+    public static final int MAX_IDX_NAME_LEN = 768;
+
+    /** Bytes in byte. */
+    private static final int BYTE_LEN = 1;
+
+    /** Page memory. */
+    private final PageMemory pageMem;
+
+    /** Index tree. */
+    private final MetaTree metaTree;
+
+    /** Meta page reuse tree. */
+    private final ReuseList reuseList;
+
+    /** Cache group ID. */
+    private final int grpId;
+
+    /** */
+    private final int allocPartId;
+
+    /** */
+    private final byte allocSpace;
+
+    /**
+     * @param pageMem Page memory.
+     * @param wal Write ahead log manager.
+     */
+    public MetadataStorage(
+        final PageMemory pageMem,
+        final IgniteWriteAheadLogManager wal,
+        final AtomicLong globalRmvId,
+        final int grpId,
+        final int allocPartId,
+        final byte allocSpace,
+        final ReuseList reuseList,
+        final long rootPageId,
+        final boolean initNew
+    ) {
+        try {
+            this.pageMem = pageMem;
+            this.grpId = grpId;
+            this.allocPartId = allocPartId;
+            this.allocSpace = allocSpace;
+            this.reuseList = reuseList;
+
+            metaTree = new MetaTree(grpId, allocPartId, allocSpace, pageMem, wal, globalRmvId, rootPageId,
+                reuseList, MetaStoreInnerIO.VERSIONS, MetaStoreLeafIO.VERSIONS, initNew);
+        }
+        catch (IgniteCheckedException e) {
+            throw new IgniteException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public RootPage getOrAllocateForTree(final String idxName) throws IgniteCheckedException {
+        final MetaTree tree = metaTree;
+
+        synchronized (this) {
+            byte[] idxNameBytes = idxName.getBytes(StandardCharsets.UTF_8);
+
+            if (idxNameBytes.length > MAX_IDX_NAME_LEN)
+                throw new IllegalArgumentException("Too long encoded indexName [maxAllowed=" + MAX_IDX_NAME_LEN +
+                    ", currentLength=" + idxNameBytes.length + ", name=" + idxName + "]");
+
+            final IndexItem row = tree.findOne(new IndexItem(idxNameBytes, 0));
+
+            if (row == null) {
+                long pageId = 0;
+
+                if (reuseList != null)
+                    pageId = reuseList.takeRecycledPage();
+
+                pageId = pageId == 0 ? pageMem.allocatePage(grpId, allocPartId, allocSpace) : pageId;
+
+                tree.put(new IndexItem(idxNameBytes, pageId));
+
+                return new RootPage(new FullPageId(pageId, grpId), true);
+            }
+            else {
+                final FullPageId pageId = new FullPageId(row.pageId, grpId);
+
+                return new RootPage(pageId, false);
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public RootPage dropRootPage(final String idxName)
+        throws IgniteCheckedException {
+        byte[] idxNameBytes = idxName.getBytes(StandardCharsets.UTF_8);
+
+        final IndexItem row = metaTree.remove(new IndexItem(idxNameBytes, 0));
+
+        if (row != null) {
+            if (reuseList == null)
+                pageMem.freePage(grpId, row.pageId);
+        }
+
+        return row != null ? new RootPage(new FullPageId(row.pageId, grpId), false) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void destroy() throws IgniteCheckedException {
+        metaTree.destroy();
+    }
+
+    /**
+     *
+     */
+    private static class MetaTree extends BPlusTree<IndexItem, IndexItem> {
+        /** */
+        private final int allocPartId;
+
+        /** */
+        private final byte allocSpace;
+
+        /**
+         * @param pageMem Page memory.
+         * @param metaPageId Meta page ID.
+         * @param reuseList Reuse list.
+         * @param innerIos Inner IOs.
+         * @param leafIos Leaf IOs.
+         * @throws IgniteCheckedException If failed.
+         */
+        private MetaTree(
+            final int cacheId,
+            final int allocPartId,
+            final byte allocSpace,
+            final PageMemory pageMem,
+            final IgniteWriteAheadLogManager wal,
+            final AtomicLong globalRmvId,
+            final long metaPageId,
+            final ReuseList reuseList,
+            final IOVersions<? extends BPlusInnerIO<IndexItem>> innerIos,
+            final IOVersions<? extends BPlusLeafIO<IndexItem>> leafIos,
+            final boolean initNew
+        ) throws IgniteCheckedException {
+            super(treeName("meta", "Meta"), cacheId, pageMem, wal, globalRmvId, metaPageId, reuseList, innerIos, leafIos);
+
+            this.allocPartId = allocPartId;
+            this.allocSpace = allocSpace;
+
+            initTree(initNew);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected long allocatePageNoReuse() throws IgniteCheckedException {
+            return pageMem.allocatePage(getCacheId(), allocPartId, allocSpace);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected int compare(final BPlusIO<IndexItem> io, final long pageAddr, final int idx,
+            final IndexItem row) throws IgniteCheckedException {
+            final int off = ((IndexIO)io).getOffset(pageAddr, idx);
+
+            int shift = 0;
+
+            // Compare index names.
+            final byte len = PageUtils.getByte(pageAddr, off + shift);
+
+            shift += BYTE_LEN;
+
+            for (int i = 0; i < len && i < row.idxName.length; i++) {
+                final int cmp = Byte.compare(PageUtils.getByte(pageAddr, off + i + shift), row.idxName[i]);
+
+                if (cmp != 0)
+                    return cmp;
+            }
+
+            return Integer.compare(len, row.idxName.length);
+        }
+
+        /** {@inheritDoc} */
+        @Override protected IndexItem getRow(final BPlusIO<IndexItem> io, final long pageAddr,
+            final int idx, Object ignore) throws IgniteCheckedException {
+            return readRow(pageAddr, ((IndexIO)io).getOffset(pageAddr, idx));
+        }
+    }
+
+    /**
+     *
+     */
+    private static class IndexItem {
+        /** */
+        private byte[] idxName;
+
+        /** */
+        private long pageId;
+
+        /**
+         * @param idxName Index name.
+         * @param pageId Page ID.
+         */
+        private IndexItem(final byte[] idxName, final long pageId) {
+            this.idxName = idxName;
+            this.pageId = pageId;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return "I [idxName=" + new String(idxName) + ", pageId=" + U.hexLong(pageId) + ']';
+        }
+    }
+
+    /**
+     * Store row to buffer.
+     *
+     * @param pageAddr Page address.
+     * @param off Offset in buf.
+     * @param row Row to store.
+     */
+    private static void storeRow(
+        final long pageAddr,
+        int off,
+        final IndexItem row
+    ) {
+        // Index name length.
+        PageUtils.putByte(pageAddr, off, (byte)row.idxName.length);
+        off++;
+
+        // Index name.
+        PageUtils.putBytes(pageAddr, off, row.idxName);
+        off += row.idxName.length;
+
+        // Page ID.
+        PageUtils.putLong(pageAddr, off, row.pageId);
+    }
+
+    /**
+     * Copy row data.
+     *
+     * @param dstPageAddr Destination page address.
+     * @param dstOff Destination buf offset.
+     * @param srcPageAddr Source page address.
+     * @param srcOff Src buf offset.
+     */
+    private static void storeRow(
+        final long dstPageAddr,
+        int dstOff,
+        final long srcPageAddr,
+        int srcOff
+    ) {
+        // Index name length.
+        final byte len = PageUtils.getByte(srcPageAddr, srcOff);
+        srcOff++;
+
+        PageUtils.putByte(dstPageAddr, dstOff, len);
+        dstOff++;
+
+        PageHandler.copyMemory(srcPageAddr, dstPageAddr, srcOff, dstOff, len);
+        srcOff += len;
+        dstOff += len;
+
+        // Page ID.
+        PageUtils.putLong(dstPageAddr, dstOff, PageUtils.getLong(srcPageAddr, srcOff));
+    }
+
+    /**
+     * Read row from buffer.
+     *
+     * @param pageAddr Page address.
+     * @param off Offset.
+     * @return Read row.
+     */
+    private static IndexItem readRow(final long pageAddr, int off) {
+        // Index name length.
+        final int len = PageUtils.getByte(pageAddr, off) & 0xFF;
+        off++;
+
+        // Index name.
+        final byte[] idxName = PageUtils.getBytes(pageAddr, off, len);
+        off += len;
+
+        // Page ID.
+        final long pageId = PageUtils.getLong(pageAddr, off);
+
+        return new IndexItem(idxName, pageId);
+    }
+
+    /**
+     *
+     */
+    private interface IndexIO {
+        /**
+         * @param pageAddr Page address.
+         * @param idx Index.
+         * @return Offset in buffer according to {@code idx}.
+         */
+        int getOffset(long pageAddr, int idx);
+    }
+
+    /**
+     *
+     */
+    public static final class MetaStoreInnerIO extends BPlusInnerIO<IndexItem> implements IndexIO {
+        /** */
+        public static final IOVersions<MetaStoreInnerIO> VERSIONS = new IOVersions<>(
+            new MetaStoreInnerIO(1)
+        );
+
+        /**
+         * @param ver Version.
+         */
+        private MetaStoreInnerIO(final int ver) {
+            // name bytes and 1 byte for length, 8 bytes pageId
+            super(T_METASTORE_INNER, ver, false, MAX_IDX_NAME_LEN + 1 + 8);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void storeByOffset(long pageAddr, int off, IndexItem row) throws IgniteCheckedException {
+            storeRow(pageAddr, off, row);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void store(final long dstPageAddr, final int dstIdx, final BPlusIO<IndexItem> srcIo,
+            final long srcPageAddr,
+            final int srcIdx) throws IgniteCheckedException {
+            storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcPageAddr, srcIdx));
+        }
+
+        /** {@inheritDoc} */
+        @Override public IndexItem getLookupRow(final BPlusTree<IndexItem, ?> tree, final long pageAddr,
+            final int idx) throws IgniteCheckedException {
+            return readRow(pageAddr, offset(idx));
+        }
+
+        /** {@inheritDoc} */
+        @Override public int getOffset(long pageAddr, final int idx) {
+            return offset(idx);
+        }
+    }
+
+    /**
+     *
+     */
+    public static final class MetaStoreLeafIO extends BPlusLeafIO<IndexItem> implements IndexIO {
+        /** */
+        public static final IOVersions<MetaStoreLeafIO> VERSIONS = new IOVersions<>(
+            new MetaStoreLeafIO(1)
+        );
+
+        /**
+         * @param ver Version.
+         */
+        private MetaStoreLeafIO(final int ver) {
+            // 4 byte cache ID, UTF-16 symbols and 1 byte for length, 8 bytes pageId
+            super(T_METASTORE_LEAF, ver, MAX_IDX_NAME_LEN + 1 + 8);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void storeByOffset(long buf, int off, IndexItem row) throws IgniteCheckedException {
+            storeRow(buf, off, row);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void store(final long dstPageAddr,
+            final int dstIdx,
+            final BPlusIO<IndexItem> srcIo,
+            final long srcPageAddr,
+            final int srcIdx) throws IgniteCheckedException {
+            storeRow(dstPageAddr, offset(dstIdx), srcPageAddr, ((IndexIO)srcIo).getOffset(srcPageAddr, srcIdx));
+        }
+
+        /** {@inheritDoc} */
+        @Override public IndexItem getLookupRow(final BPlusTree<IndexItem, ?> tree,
+            final long pageAddr,
+            final int idx) throws IgniteCheckedException {
+            return readRow(pageAddr, offset(idx));
+        }
+
+        /** {@inheritDoc} */
+        @Override public int getOffset(long pageAddr, final int idx) {
+            return offset(idx);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsImpl.java
new file mode 100644
index 0000000..7952937
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsImpl.java
@@ -0,0 +1,297 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
+import org.apache.ignite.internal.processors.cache.ratemetrics.HitRateMetrics;
+import org.apache.ignite.mxbean.PersistenceMetricsMXBean;
+
+/**
+ *
+ */
+public class PersistenceMetricsImpl implements PersistenceMetricsMXBean {
+    /** */
+    private volatile HitRateMetrics walLoggingRate;
+
+    /** */
+    private volatile HitRateMetrics walWritingRate;
+
+    /** */
+    private volatile HitRateMetrics walFsyncTimeDuration;
+
+    /** */
+    private volatile HitRateMetrics walFsyncTimeNumber;
+
+    /** */
+    private volatile long lastCpLockWaitDuration;
+
+    /** */
+    private volatile long lastCpMarkDuration;
+
+    /** */
+    private volatile long lastCpPagesWriteDuration;
+
+    /** */
+    private volatile long lastCpDuration;
+
+    /** */
+    private volatile long lastCpFsyncDuration;
+
+    /** */
+    private volatile long lastCpTotalPages;
+
+    /** */
+    private volatile long lastCpDataPages;
+
+    /** */
+    private volatile long lastCpCowPages;
+
+    /** */
+    private volatile long rateTimeInterval;
+
+    /** */
+    private volatile int subInts;
+
+    /** */
+    private volatile boolean metricsEnabled;
+
+    /** */
+    private IgniteWriteAheadLogManager wal;
+
+    /**
+     * @param metricsEnabled Metrics enabled flag.
+     * @param rateTimeInterval Rate time interval.
+     * @param subInts Number of sub-intervals.
+     */
+    public PersistenceMetricsImpl(
+        boolean metricsEnabled,
+        long rateTimeInterval,
+        int subInts
+    ) {
+        this.metricsEnabled = metricsEnabled;
+        this.rateTimeInterval = rateTimeInterval;
+        this.subInts = subInts;
+
+        resetRates();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalLoggingRate() {
+        if (!metricsEnabled)
+            return 0;
+
+        return ((float)walLoggingRate.getRate()) / rateTimeInterval;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalWritingRate() {
+        if (!metricsEnabled)
+            return 0;
+
+        return ((float)walWritingRate.getRate()) / rateTimeInterval;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getWalArchiveSegments() {
+        if (!metricsEnabled)
+            return 0;
+
+        return wal.walArchiveSegments();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalFsyncTimeAverage() {
+        if (!metricsEnabled)
+            return 0;
+
+        long numRate = walFsyncTimeNumber.getRate();
+
+        if (numRate == 0)
+            return 0;
+
+        return (float)walFsyncTimeDuration.getRate() / numRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointingDuration() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointLockWaitDuration() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpLockWaitDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointMarkDuration() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpMarkDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointPagesWriteDuration() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpPagesWriteDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointFsyncDuration() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpFsyncDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointTotalPagesNumber() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpTotalPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointDataPagesNumber() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpDataPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointCopiedOnWritePagesNumber() {
+        if (!metricsEnabled)
+            return 0;
+
+        return lastCpCowPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void enableMetrics() {
+        metricsEnabled = true;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void disableMetrics() {
+        metricsEnabled = false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void rateTimeInterval(long rateTimeInterval) {
+        this.rateTimeInterval = rateTimeInterval;
+
+        resetRates();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void subIntervals(int subInts) {
+        this.subInts = subInts;
+
+        resetRates();
+    }
+
+    /**
+     * @param wal Write-ahead log manager.
+     */
+    public void wal(IgniteWriteAheadLogManager wal) {
+        this.wal = wal;
+    }
+
+    /**
+     * @return Metrics enabled flag.
+     */
+    public boolean metricsEnabled() {
+        return metricsEnabled;
+    }
+
+    /**
+     * @param lockWaitDuration Lock wait duration.
+     * @param markDuration Mark duration.
+     * @param pagesWriteDuration Pages write duration.
+     * @param fsyncDuration Total checkpoint fsync duration.
+     * @param duration Total checkpoint duration.
+     * @param totalPages Total number of all pages in checkpoint.
+     * @param dataPages Total number of data pages in checkpoint.
+     * @param cowPages Total number of COW-ed pages in checkpoint.
+     */
+    public void onCheckpoint(
+        long lockWaitDuration,
+        long markDuration,
+        long pagesWriteDuration,
+        long fsyncDuration,
+        long duration,
+        long totalPages,
+        long dataPages,
+        long cowPages
+    ) {
+        if (metricsEnabled) {
+            lastCpLockWaitDuration = lockWaitDuration;
+            lastCpMarkDuration = markDuration;
+            lastCpPagesWriteDuration = pagesWriteDuration;
+            lastCpFsyncDuration = fsyncDuration;
+            lastCpDuration = duration;
+            lastCpTotalPages = totalPages;
+            lastCpDataPages = dataPages;
+            lastCpCowPages = cowPages;
+        }
+    }
+
+    /**
+     *
+     */
+    public void onWalRecordLogged() {
+        walLoggingRate.onHit();
+    }
+
+    /**
+     * @param size Size written.
+     */
+    public void onWalBytesWritten(int size) {
+        walWritingRate.onHits(size);
+    }
+
+    /**
+     * @param nanoTime Fsync nano time.
+     */
+    public void onFsync(long nanoTime) {
+        long microseconds = nanoTime / 1_000;
+
+        walFsyncTimeDuration.onHits(microseconds);
+        walFsyncTimeNumber.onHit();
+    }
+
+    /**
+     *
+     */
+    private void resetRates() {
+        walLoggingRate = new HitRateMetrics((int)rateTimeInterval, subInts);
+        walWritingRate = new HitRateMetrics((int)rateTimeInterval, subInts);
+
+        walFsyncTimeDuration = new HitRateMetrics((int)rateTimeInterval, subInts);
+        walFsyncTimeNumber = new HitRateMetrics((int)rateTimeInterval, subInts);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsSnapshot.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsSnapshot.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsSnapshot.java
new file mode 100644
index 0000000..0de9950
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/PersistenceMetricsSnapshot.java
@@ -0,0 +1,144 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.PersistenceMetrics;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ *
+ */
+public class PersistenceMetricsSnapshot implements PersistenceMetrics {
+    /** */
+    private float walLoggingRate;
+
+    /** */
+    private float walWritingRate;
+
+    /** */
+    private int walArchiveSegments;
+
+    /** */
+    private float walFsyncTimeAvg;
+
+    /** */
+    private long lastCpDuration;
+
+    /** */
+    private long lastCpLockWaitDuration;
+
+    /** */
+    private long lastCpMmarkDuration;
+
+    /** */
+    private long lastCpPagesWriteDuration;
+
+    /** */
+    private long lastCpFsyncDuration;
+
+    /** */
+    private long lastCpTotalPages;
+
+    /** */
+    private long lastCpDataPages;
+
+    /** */
+    private long lastCpCowPages;
+
+    /**
+     * @param metrics Metrics.
+     */
+    public PersistenceMetricsSnapshot(PersistenceMetrics metrics) {
+        walLoggingRate = metrics.getWalLoggingRate();
+        walWritingRate = metrics.getWalWritingRate();
+        walArchiveSegments = metrics.getWalArchiveSegments();
+        walFsyncTimeAvg = metrics.getWalFsyncTimeAverage();
+        lastCpDuration = metrics.getLastCheckpointingDuration();
+        lastCpLockWaitDuration = metrics.getLastCheckpointLockWaitDuration();
+        lastCpMmarkDuration = metrics.getLastCheckpointMarkDuration();
+        lastCpPagesWriteDuration = metrics.getLastCheckpointPagesWriteDuration();
+        lastCpFsyncDuration = metrics.getLastCheckpointFsyncDuration();
+        lastCpTotalPages = metrics.getLastCheckpointTotalPagesNumber();
+        lastCpDataPages = metrics.getLastCheckpointDataPagesNumber();
+        lastCpCowPages = metrics.getLastCheckpointCopiedOnWritePagesNumber();
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalLoggingRate() {
+        return walLoggingRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalWritingRate() {
+        return walWritingRate;
+    }
+
+    /** {@inheritDoc} */
+    @Override public int getWalArchiveSegments() {
+        return walArchiveSegments;
+    }
+
+    /** {@inheritDoc} */
+    @Override public float getWalFsyncTimeAverage() {
+        return walFsyncTimeAvg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointingDuration() {
+        return lastCpDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointLockWaitDuration() {
+        return lastCpLockWaitDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointMarkDuration() {
+        return lastCpMmarkDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointPagesWriteDuration() {
+        return lastCpPagesWriteDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointFsyncDuration() {
+        return lastCpFsyncDuration;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointTotalPagesNumber() {
+        return lastCpTotalPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointDataPagesNumber() {
+        return lastCpDataPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public long getLastCheckpointCopiedOnWritePagesNumber() {
+        return lastCpCowPages;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(PersistenceMetricsSnapshot.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RootPage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RootPage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RootPage.java
new file mode 100644
index 0000000..da9efe5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RootPage.java
@@ -0,0 +1,62 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.internal.pagemem.FullPageId;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ *
+ */
+public class RootPage {
+    /** */
+    @GridToStringInclude
+    private FullPageId pageId;
+
+    /** */
+    private boolean allocated;
+
+    /**
+     * @param pageId Page ID.
+     * @param allocated {@code True} if was allocated new page.
+     */
+    public RootPage(final FullPageId pageId, final boolean allocated) {
+        this.pageId = pageId;
+        this.allocated = allocated;
+    }
+
+    /**
+     * @return Page ID.
+     */
+    public FullPageId pageId() {
+        return pageId;
+    }
+
+    /**
+     * @return {@code True} if was allocated.
+     */
+    public boolean isAllocated() {
+        return allocated;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(RootPage.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java
new file mode 100644
index 0000000..9cc5c62
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/RowStore.java
@@ -0,0 +1,107 @@
+/*
+ * 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.persistence;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
+import org.apache.ignite.internal.processors.cache.CacheObjectContext;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList;
+
+/**
+ * Data store for H2 rows.
+ */
+public class RowStore {
+    /** */
+    private final FreeList freeList;
+
+    /** */
+    private final GridCacheSharedContext ctx;
+
+    /** */
+    protected final PageMemory pageMem;
+
+    /** */
+    protected final CacheObjectContext coctx;
+
+
+
+    /**
+     * @param grp Cache group.
+     * @param freeList Free list.
+     */
+    public RowStore(CacheGroupContext grp, FreeList freeList) {
+        assert grp != null;
+        assert freeList != null;
+
+        this.freeList = freeList;
+
+        ctx = grp.shared();
+        coctx = grp.cacheObjectContext();
+        pageMem = grp.memoryPolicy().pageMemory();
+    }
+
+    /**
+     * @param link Row link.
+     * @throws IgniteCheckedException If failed.
+     */
+    public void removeRow(long link) throws IgniteCheckedException {
+        assert link != 0;
+        ctx.database().checkpointReadLock();
+
+        try {
+            freeList.removeDataRowByLink(link);
+        }
+        finally {
+            ctx.database().checkpointReadUnlock();
+        }
+    }
+
+    /**
+     * @param row Row.
+     * @throws IgniteCheckedException If failed.
+     */
+    public void addRow(CacheDataRow row) throws IgniteCheckedException {
+        ctx.database().checkpointReadLock();
+
+        try {
+            freeList.insertDataRow(row);
+        }
+        finally {
+            ctx.database().checkpointReadUnlock();
+        }
+    }
+
+    /**
+     * @param link Row link.
+     * @param row New row data.
+     * @throws IgniteCheckedException If failed.
+     * @return {@code True} if was able to update row.
+     */
+    public boolean updateRow(long link, CacheDataRow row) throws IgniteCheckedException {
+        return freeList.updateDataRow(link, row);
+    }
+
+    /**
+     * @return Free list.
+     */
+    public FreeList freeList() {
+        return freeList;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java
new file mode 100644
index 0000000..f5c7c8a
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/FairFifoPageEvictionTracker.java
@@ -0,0 +1,76 @@
+/*
+* 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.persistence.evict;
+
+import java.util.LinkedList;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.pagemem.PageIdUtils;
+import org.apache.ignite.internal.pagemem.impl.PageMemoryNoStoreImpl;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+
+/**
+ * On-heap FIFO page eviction tracker. Only for test purposes.
+ */
+public class FairFifoPageEvictionTracker extends PageAbstractEvictionTracker {
+    /** Page usage deque. */
+    private final LinkedList<Integer> pageUsageList = new LinkedList<>();
+
+    /**
+     * @param pageMem Page memory.
+     * @param plcCfg Memory policy configuration.
+     * @param sharedCtx Shared context.
+     */
+    public FairFifoPageEvictionTracker(
+        PageMemoryNoStoreImpl pageMem,
+        MemoryPolicyConfiguration plcCfg,
+        GridCacheSharedContext sharedCtx) {
+        super(pageMem, plcCfg, sharedCtx);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start() throws IgniteException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() throws IgniteException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public synchronized void touchPage(long pageId) throws IgniteCheckedException {
+        pageUsageList.addLast(PageIdUtils.pageIndex(pageId));
+    }
+
+    /** {@inheritDoc} */
+    @Override public synchronized void evictDataPage() throws IgniteCheckedException {
+        evictDataPage(pageUsageList.pollFirst());
+    }
+
+    /** {@inheritDoc} */
+    @Override public synchronized void forgetPage(long pageId) throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override protected synchronized boolean checkTouch(long pageId) {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.java
new file mode 100644
index 0000000..b420ecd
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/NoOpPageEvictionTracker.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.internal.processors.cache.persistence.evict;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+
+/**
+ *
+ */
+public class NoOpPageEvictionTracker implements PageEvictionTracker {
+    /** {@inheritDoc} */
+    @Override public void start() throws IgniteException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() throws IgniteException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void touchPage(long pageId) throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void evictDataPage() throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /** {@inheritDoc} */
+    @Override public void forgetPage(long pageId) throws IgniteCheckedException {
+        // No-op.
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
new file mode 100644
index 0000000..a524d5e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageAbstractEvictionTracker.java
@@ -0,0 +1,171 @@
+/*
+* 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.persistence.evict;
+
+import java.util.List;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.pagemem.PageIdUtils;
+import org.apache.ignite.internal.pagemem.impl.PageMemoryNoStoreImpl;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheEntryEx;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.processors.cache.persistence.CacheDataRowAdapter;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.DataPageIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersionManager;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ *
+ */
+public abstract class PageAbstractEvictionTracker implements PageEvictionTracker {
+    /** This number of least significant bits is dropped from timestamp. */
+    private static final int COMPACT_TS_SHIFT = 8; // Enough if grid works for less than 17 years.
+
+    /** Millis in day. */
+    private static final int DAY = 24 * 60 * 60 * 1000;
+
+    /** Page memory. */
+    protected final PageMemoryNoStoreImpl pageMem;
+
+    /** Tracking array size. */
+    protected final int trackingSize;
+
+    /** Base compact timestamp. */
+    private final long baseCompactTs;
+
+    /** Shared context. */
+    private final GridCacheSharedContext sharedCtx;
+
+    /**
+     * @param pageMem Page memory.
+     * @param plcCfg Memory policy configuration.
+     * @param sharedCtx Shared context.
+     */
+    PageAbstractEvictionTracker(
+        PageMemoryNoStoreImpl pageMem,
+        MemoryPolicyConfiguration plcCfg,
+        GridCacheSharedContext sharedCtx
+    ) {
+        this.pageMem = pageMem;
+
+        this.sharedCtx = sharedCtx;
+
+        trackingSize = pageMem.totalPages();
+
+        baseCompactTs = (U.currentTimeMillis() - DAY) >> COMPACT_TS_SHIFT;
+        // We subtract day to avoid fail in case of daylight shift or timezone change.
+    }
+
+    /**
+     * @param pageIdx Page index.
+     * @return true if at least one data row has been evicted
+     * @throws IgniteCheckedException If failed.
+     */
+    final boolean evictDataPage(int pageIdx) throws IgniteCheckedException {
+        long fakePageId = PageIdUtils.pageId(0, (byte)0, pageIdx);
+
+        long page = pageMem.acquirePage(0, fakePageId);
+
+        List<CacheDataRowAdapter> rowsToEvict;
+
+        try {
+            long pageAddr = pageMem.readLockForce(0, fakePageId, page);
+
+            try {
+                if (PageIO.getType(pageAddr) != PageIO.T_DATA)
+                    return false; // Can't evict: page has been recycled into non-data page.
+
+                DataPageIO io = DataPageIO.VERSIONS.forPage(pageAddr);
+
+                long realPageId = PageIO.getPageId(pageAddr);
+
+                if (!checkTouch(realPageId))
+                    return false; // Can't evict: another thread concurrently invoked forgetPage()
+
+                rowsToEvict = io.forAllItems(pageAddr, new DataPageIO.CC<CacheDataRowAdapter>() {
+                    @Override public CacheDataRowAdapter apply(long link) throws IgniteCheckedException {
+                        CacheDataRowAdapter row = new CacheDataRowAdapter(link);
+
+                        row.initFromLink(null, sharedCtx, pageMem, CacheDataRowAdapter.RowData.KEY_ONLY);
+
+                        assert row.cacheId() != 0 : "Cache ID should be stored in rows of evictable cache";
+
+                        return row;
+                    }
+                });
+            }
+            finally {
+                pageMem.readUnlock(0, fakePageId, page);
+            }
+        }
+        finally {
+            pageMem.releasePage(0, fakePageId, page);
+        }
+
+        boolean evictionDone = false;
+
+        for (CacheDataRowAdapter dataRow : rowsToEvict) {
+            GridCacheContext<?, ?> cacheCtx = sharedCtx.cacheContext(dataRow.cacheId());
+
+            if (!cacheCtx.userCache())
+                continue;
+
+            GridCacheEntryEx entryEx = cacheCtx.isNear() ? cacheCtx.near().dht().entryEx(dataRow.key()) :
+                cacheCtx.cache().entryEx(dataRow.key());
+
+            evictionDone |= entryEx.evictInternal(GridCacheVersionManager.EVICT_VER, null, true);
+        }
+
+        return evictionDone;
+    }
+
+    /**
+     * @param pageId Page ID.
+     * @return true if page was touched at least once.
+     */
+    protected abstract boolean checkTouch(long pageId);
+
+    /**
+     * @param epochMilli Time millis.
+     * @return Compact timestamp. Comparable and fits in 4 bytes.
+     */
+    final long compactTimestamp(long epochMilli) {
+        return (epochMilli >> COMPACT_TS_SHIFT) - baseCompactTs;
+    }
+
+    /**
+     * Resolves position in tracking array by page index.
+     *
+     * @param pageIdx Page index.
+     * @return Position of page in tracking array.
+     */
+    int trackingIdx(int pageIdx) {
+        return pageMem.pageSequenceNumber(pageIdx);
+    }
+
+    /**
+     * Reverse of {@link #trackingIdx(int)}.
+     *
+     * @param trackingIdx Tracking index.
+     * @return Page index.
+     */
+    int pageIdx(int trackingIdx) {
+        return pageMem.pageIndex(trackingIdx);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java
new file mode 100644
index 0000000..baa5462
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/PageEvictionTracker.java
@@ -0,0 +1,52 @@
+/*
+* 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.persistence.evict;
+
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.lifecycle.LifecycleAware;
+
+/**
+ * Entry point for per-page eviction. Accepts information about touching data pages,
+ * capable of evicting "the least needed" page (according to implemented eviction algorithm).
+ */
+public interface PageEvictionTracker extends LifecycleAware {
+    /**
+     * Call this method when data page is accessed.
+     *
+     * @param pageId Page id.
+     * @throws IgniteCheckedException In case of page memory error.
+     */
+    public void touchPage(long pageId) throws IgniteCheckedException;
+
+    /**
+     * Evicts one data page.
+     * In most cases, all entries will be removed from the page.
+     * Method guarantees removing at least one entry from "evicted" data page. Removing all entries may be
+     * not possible, as some of them can be used by active transactions.
+     *
+     * @throws IgniteCheckedException In case of page memory error.
+     */
+    public void evictDataPage() throws IgniteCheckedException;
+
+    /**
+     * Call this method when last entry is removed from data page.
+     *
+     * @param pageId Page id.
+     * @throws IgniteCheckedException In case of page memory error.
+     */
+    public void forgetPage(long pageId) throws IgniteCheckedException;
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java
new file mode 100644
index 0000000..00f1b16
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/evict/Random2LruPageEvictionTracker.java
@@ -0,0 +1,180 @@
+/*
+* 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.persistence.evict;
+
+import java.util.concurrent.ThreadLocalRandom;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.configuration.MemoryConfiguration;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.pagemem.PageIdUtils;
+import org.apache.ignite.internal.pagemem.impl.PageMemoryNoStoreImpl;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedContext;
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.typedef.internal.LT;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/**
+ *
+ */
+public class Random2LruPageEvictionTracker extends PageAbstractEvictionTracker {
+    /** Evict attempts limit. */
+    private static final int EVICT_ATTEMPTS_LIMIT = 30;
+
+    /** LRU Sample size. */
+    private static final int SAMPLE_SIZE = 5;
+
+    /** Maximum sample search spin count */
+    private static final int SAMPLE_SPIN_LIMIT = SAMPLE_SIZE * 1000;
+
+    /** Logger. */
+    private final IgniteLogger log;
+
+    /** Tracking array ptr. */
+    private long trackingArrPtr;
+
+    /**
+     * @param pageMem Page memory.
+     * @param plcCfg Policy config.
+     * @param sharedCtx Shared context.
+     */
+    public Random2LruPageEvictionTracker(
+        PageMemoryNoStoreImpl pageMem,
+        MemoryPolicyConfiguration plcCfg,
+        GridCacheSharedContext<?, ?> sharedCtx
+    ) {
+        super(pageMem, plcCfg, sharedCtx);
+
+        MemoryConfiguration memCfg = sharedCtx.kernalContext().config().getMemoryConfiguration();
+
+        assert plcCfg.getMaxSize() / memCfg.getPageSize() < Integer.MAX_VALUE;
+
+        log = sharedCtx.logger(getClass());
+    }
+
+    /** {@inheritDoc} */
+    @Override public void start() throws IgniteException {
+        trackingArrPtr = GridUnsafe.allocateMemory(trackingSize * 8);
+
+        GridUnsafe.setMemory(trackingArrPtr, trackingSize * 8, (byte)0);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() throws IgniteException {
+        GridUnsafe.freeMemory(trackingArrPtr);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void touchPage(long pageId) throws IgniteCheckedException {
+        int pageIdx = PageIdUtils.pageIndex(pageId);
+
+        long latestTs = compactTimestamp(U.currentTimeMillis());
+
+        assert latestTs >= 0 && latestTs < Integer.MAX_VALUE;
+
+        boolean success;
+
+        do {
+            int trackingIdx = trackingIdx(pageIdx);
+
+            int firstTs = GridUnsafe.getIntVolatile(null, trackingArrPtr + trackingIdx * 8);
+
+            int secondTs = GridUnsafe.getIntVolatile(null, trackingArrPtr + trackingIdx * 8 + 4);
+
+            if (firstTs <= secondTs)
+                success = GridUnsafe.compareAndSwapInt(null, trackingArrPtr + trackingIdx * 8, firstTs, (int)latestTs);
+            else {
+                success = GridUnsafe.compareAndSwapInt(
+                    null, trackingArrPtr + trackingIdx * 8 + 4, secondTs, (int)latestTs);
+            }
+        } while (!success);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void evictDataPage() throws IgniteCheckedException {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+
+        int evictAttemptsCnt = 0;
+
+        while (evictAttemptsCnt < EVICT_ATTEMPTS_LIMIT) {
+            int lruTrackingIdx = -1;
+
+            int lruCompactTs = Integer.MAX_VALUE;
+
+            int dataPagesCnt = 0;
+
+            int sampleSpinCnt = 0;
+
+            while (dataPagesCnt < SAMPLE_SIZE) {
+                int trackingIdx = rnd.nextInt(trackingSize);
+
+                int firstTs = GridUnsafe.getIntVolatile(null, trackingArrPtr + trackingIdx * 8);
+
+                int secondTs = GridUnsafe.getIntVolatile(null, trackingArrPtr + trackingIdx * 8 + 4);
+
+                int minTs = Math.min(firstTs, secondTs);
+
+                int maxTs = Math.max(firstTs, secondTs);
+
+                if (maxTs != 0) {
+                    // We chose data page with at least one touch.
+                    if (minTs < lruCompactTs) {
+                        lruTrackingIdx = trackingIdx;
+
+                        lruCompactTs = minTs;
+                    }
+
+                    dataPagesCnt++;
+                }
+
+                sampleSpinCnt++;
+
+                if (sampleSpinCnt > SAMPLE_SPIN_LIMIT) {
+                    LT.warn(log, "Too many attempts to choose data page: " + SAMPLE_SPIN_LIMIT);
+
+                    return;
+                }
+            }
+
+            if (evictDataPage(pageIdx(lruTrackingIdx)))
+                return;
+
+            evictAttemptsCnt++;
+        }
+
+        LT.warn(log, "Too many failed attempts to evict page: " + EVICT_ATTEMPTS_LIMIT);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected boolean checkTouch(long pageId) {
+        int trackingIdx = trackingIdx(PageIdUtils.pageIndex(pageId));
+
+        int firstTs = GridUnsafe.getIntVolatile(null, trackingArrPtr + trackingIdx * 8);
+
+        return firstTs != 0;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void forgetPage(long pageId) {
+        int pageIdx = PageIdUtils.pageIndex(pageId);
+
+        int trackingIdx = trackingIdx(pageIdx);
+
+        GridUnsafe.putLongVolatile(null, trackingArrPtr + trackingIdx * 8, 0L);
+    }
+}


Mime
View raw message