ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From agoncha...@apache.org
Subject [38/47] ignite git commit: IGNITE-5267 - Moved ignite-ps module to ignite-core
Date Sun, 11 Jun 2017 20:04:04 GMT
http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
new file mode 100644
index 0000000..eb9f4df
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/GridCacheOffheapManager.java
@@ -0,0 +1,1316 @@
+/*
+ * 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.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.pagemem.FullPageId;
+import org.apache.ignite.internal.pagemem.PageIdAllocator;
+import org.apache.ignite.internal.pagemem.PageIdUtils;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
+import org.apache.ignite.internal.pagemem.wal.WALIterator;
+import org.apache.ignite.internal.pagemem.wal.WALPointer;
+import org.apache.ignite.internal.pagemem.wal.record.DataEntry;
+import org.apache.ignite.internal.pagemem.wal.record.DataRecord;
+import org.apache.ignite.internal.pagemem.wal.record.WALRecord;
+import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageInitRecord;
+import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdateNextSnapshotId;
+import org.apache.ignite.internal.pagemem.wal.record.delta.MetaPageUpdatePartitionDataRecord;
+import org.apache.ignite.internal.pagemem.wal.record.delta.PartitionDestroyRecord;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
+import org.apache.ignite.internal.processors.cache.CacheObject;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.IgniteCacheOffheapManagerImpl;
+import org.apache.ignite.internal.processors.cache.IgniteRebalanceIterator;
+import org.apache.ignite.internal.processors.cache.KeyCacheObject;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeListImpl;
+import org.apache.ignite.internal.processors.cache.persistence.pagemem.PageMemoryEx;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PageMetaIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionCountersIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.io.PagePartitionMetaIO;
+import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList;
+import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseListImpl;
+import org.apache.ignite.internal.processors.cache.persistence.tree.util.PageHandler;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtLocalPartition;
+import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtPartitionState;
+import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionMap;
+import org.apache.ignite.internal.processors.cache.version.GridCacheVersion;
+import org.apache.ignite.internal.util.GridUnsafe;
+import org.apache.ignite.internal.util.lang.GridCursor;
+import org.apache.ignite.internal.util.tostring.GridToStringInclude;
+import org.apache.ignite.internal.util.typedef.T2;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Used when persistence enabled.
+ */
+public class GridCacheOffheapManager extends IgniteCacheOffheapManagerImpl implements DbCheckpointListener {
+    /** */
+    private MetaStore metaStore;
+
+    /** */
+    private ReuseListImpl reuseList;
+
+    /** {@inheritDoc} */
+    @Override protected void initDataStructures() throws IgniteCheckedException {
+        Metas metas = getOrAllocateCacheMetas();
+
+        RootPage reuseListRoot = metas.reuseListRoot;
+
+        reuseList = new ReuseListImpl(grp.groupId(),
+            grp.cacheOrGroupName(),
+            grp.memoryPolicy().pageMemory(),
+            ctx.wal(),
+            reuseListRoot.pageId().pageId(),
+            reuseListRoot.isAllocated());
+
+        RootPage metastoreRoot = metas.treeRoot;
+
+        metaStore = new MetadataStorage(grp.memoryPolicy().pageMemory(),
+            ctx.wal(),
+            globalRemoveId(),
+            grp.groupId(),
+            PageIdAllocator.INDEX_PARTITION,
+            PageIdAllocator.FLAG_IDX,
+            reuseList,
+            metastoreRoot.pageId().pageId(),
+            metastoreRoot.isAllocated());
+
+        ((GridCacheDatabaseSharedManager)ctx.database()).addCheckpointListener(this);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onCacheStarted(GridCacheContext cctx) throws IgniteCheckedException {
+        if (cctx.affinityNode() && cctx.ttl().eagerTtlEnabled() && pendingEntries == null) {
+            ctx.database().checkpointReadLock();
+
+            try {
+                final String name = "PendingEntries";
+
+                RootPage pendingRootPage = metaStore.getOrAllocateForTree(name);
+
+                pendingEntries = new PendingEntriesTree(
+                    grp,
+                    name,
+                    grp.memoryPolicy().pageMemory(),
+                    pendingRootPage.pageId().pageId(),
+                    reuseList,
+                    pendingRootPage.isAllocated()
+                );
+            }
+            finally {
+                ctx.database().checkpointReadUnlock();
+            }
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override protected CacheDataStore createCacheDataStore0(final int p)
+        throws IgniteCheckedException {
+        GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ctx.database();
+
+        boolean exists = ctx.pageStore() != null
+            && ctx.pageStore().exists(grp.groupId(), p);
+
+        return new GridCacheDataStore(p, exists);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onCheckpointBegin(Context ctx) throws IgniteCheckedException {
+        assert grp.memoryPolicy().pageMemory() instanceof PageMemoryEx;
+
+        reuseList.saveMetadata();
+
+        boolean metaWasUpdated = false;
+
+        for (CacheDataStore store : partDataStores.values()) {
+            RowStore rowStore = store.rowStore();
+
+            if (rowStore == null)
+                continue;
+
+            metaWasUpdated |= saveStoreMetadata(store, ctx, !metaWasUpdated, false);
+        }
+    }
+
+    /**
+     * @param store Store to save metadata.
+     * @throws IgniteCheckedException If failed.
+     */
+    private boolean saveStoreMetadata(CacheDataStore store, Context ctx, boolean saveMeta,
+        boolean beforeDestroy) throws IgniteCheckedException {
+        RowStore rowStore0 = store.rowStore();
+
+        boolean beforeSnapshot = ctx != null && ctx.nextSnapshot();
+
+        boolean wasSaveToMeta = false;
+
+        if (rowStore0 != null) {
+            FreeListImpl freeList = (FreeListImpl)rowStore0.freeList();
+
+            freeList.saveMetadata();
+
+            long updCntr = store.updateCounter();
+            int size = store.fullSize();
+            long rmvId = globalRemoveId().get();
+
+            PageMemoryEx pageMem = (PageMemoryEx)grp.memoryPolicy().pageMemory();
+            IgniteWriteAheadLogManager wal = this.ctx.wal();
+
+            if (size > 0 || updCntr > 0) {
+                int state = -1;
+
+                if (beforeDestroy)
+                    state = GridDhtPartitionState.EVICTED.ordinal();
+                else {
+                    // localPartition will not acquire writeLock here because create=false.
+                    GridDhtLocalPartition part = grp.topology().localPartition(store.partId(),
+                        AffinityTopologyVersion.NONE, false);
+
+                    if (part != null && part.state() != GridDhtPartitionState.EVICTED)
+                        state = part.state().ordinal();
+                }
+
+                // Do not save meta for evicted partitions on next checkpoints.
+                if (state == -1)
+                    return false;
+
+                int grpId = grp.groupId();
+                long partMetaId = pageMem.partitionMetaPageId(grpId, store.partId());
+                long partMetaPage = pageMem.acquirePage(grpId, partMetaId);
+
+                try {
+                    long pageAddr = pageMem.writeLock(grpId, partMetaId, partMetaPage);
+
+                    if (pageAddr == 0L) {
+                        U.warn(log, "Failed to acquire write lock for meta page [metaPage=" + partMetaPage +
+                            ", saveMeta=" + saveMeta + ", beforeDestroy=" + beforeDestroy + ", size=" + size +
+                            ", updCntr=" + updCntr + ", state=" + state + ']');
+
+                        return false;
+                    }
+
+                    boolean changed = false;
+
+                    try {
+                        PagePartitionMetaIO io = PageIO.getPageIO(pageAddr);
+
+                        changed |= io.setUpdateCounter(pageAddr, updCntr);
+                        changed |= io.setGlobalRemoveId(pageAddr, rmvId);
+                        changed |= io.setSize(pageAddr, size);
+
+                        changed |= io.setPartitionState(pageAddr, (byte)state);
+
+                        long cntrsPageId;
+
+                        if (grp.sharedGroup()) {
+                            cntrsPageId = io.getCountersPageId(pageAddr);
+
+                            byte[] data = serializeCacheSizes(store.cacheSizes());
+
+                            int items = data.length / 12;
+                            int written = 0;
+                            int pageSize = pageMem.pageSize();
+
+                            boolean init = cntrsPageId == 0;
+
+                            if (init) {
+                                cntrsPageId = pageMem.allocatePage(grpId, store.partId(), PageIdAllocator.FLAG_DATA);
+
+                                io.setCountersPageId(pageAddr, cntrsPageId);
+
+                                changed = true;
+                            }
+
+                            long nextId = cntrsPageId;
+
+                            while (written != items) {
+                                final long curId = nextId;
+                                final long curPage = pageMem.acquirePage(grpId, curId);
+
+                                try {
+                                    final long curAddr = pageMem.writeLock(grpId, curId, curPage);
+
+                                    assert curAddr != 0;
+
+                                    try {
+                                        PagePartitionCountersIO partMetaIo;
+
+                                        if (init) {
+                                            partMetaIo = PagePartitionCountersIO.VERSIONS.latest();
+
+                                            partMetaIo.initNewPage(curAddr, curId, pageSize);
+                                        }
+                                        else
+                                            partMetaIo = PageIO.getPageIO(curAddr);
+
+                                        written += partMetaIo.writeCacheSizes(pageSize, curAddr, data, written);
+
+                                        nextId = partMetaIo.getNextCountersPageId(curAddr);
+
+                                        if(written != items && (init = nextId == 0)) {
+                                            //allocate new counters page
+                                            nextId = pageMem.allocatePage(grpId, store.partId(), PageIdAllocator.FLAG_DATA);
+                                            partMetaIo.setNextCountersPageId(curAddr, nextId);
+                                        }
+                                    }
+                                    finally {
+                                        // Write full page
+                                        pageMem.writeUnlock(grpId, curId, curPage, Boolean.TRUE, true);
+                                    }
+                                }
+                                finally {
+                                    pageMem.releasePage(grpId, curId, curPage);
+                                }
+                            }
+                        }
+                        else
+                            cntrsPageId = 0L;
+
+                        int pageCnt;
+
+                        if (beforeSnapshot) {
+                            pageCnt = this.ctx.pageStore().pages(grpId, store.partId());
+                            io.setCandidatePageCount(pageAddr, pageCnt);
+
+                            if (saveMeta) {
+                                long metaPageId = pageMem.metaPageId(grpId);
+                                long metaPage = pageMem.acquirePage(grpId, metaPageId);
+
+                                try {
+                                    long metaPageAddr = pageMem.writeLock(grpId, metaPageId, metaPage);
+
+                                    try {
+                                        long nextSnapshotTag = io.getNextSnapshotTag(metaPageAddr);
+
+                                        io.setNextSnapshotTag(metaPageAddr, nextSnapshotTag + 1);
+
+                                        if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, metaPageId,
+                                            metaPage, wal, null))
+                                            wal.log(new MetaPageUpdateNextSnapshotId(grpId, metaPageId,
+                                                nextSnapshotTag + 1));
+
+                                        addPartition(ctx.partitionStatMap(), metaPageAddr, io, grpId, PageIdAllocator.INDEX_PARTITION,
+                                            this.ctx.kernalContext().cache().context().pageStore().pages(grpId, PageIdAllocator.INDEX_PARTITION));
+                                    }
+                                    finally {
+                                        pageMem.writeUnlock(grpId, metaPageId, metaPage, null, true);
+                                    }
+                                }
+                                finally {
+                                    pageMem.releasePage(grpId, metaPageId, metaPage);
+                                }
+
+                                wasSaveToMeta = true;
+                            }
+
+                            GridDhtPartitionMap partMap = grp.topology().localPartitionMap();
+
+                            if (partMap.containsKey(store.partId()) &&
+                                partMap.get(store.partId()) == GridDhtPartitionState.OWNING)
+                                addPartition(ctx.partitionStatMap(), pageAddr, io, grpId, store.partId(),
+                                    this.ctx.pageStore().pages(grpId, store.partId()));
+
+                            changed = true;
+                        }
+                        else
+                            pageCnt = io.getCandidatePageCount(pageAddr);
+
+                        if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null))
+                            wal.log(new MetaPageUpdatePartitionDataRecord(
+                                grpId,
+                                partMetaId,
+                                updCntr,
+                                rmvId,
+                                size,
+                                cntrsPageId,
+                                (byte)state,
+                                pageCnt
+                            ));
+                    }
+                    finally {
+                        pageMem.writeUnlock(grpId, partMetaId, partMetaPage, null, changed);
+                    }
+                }
+                finally {
+                    pageMem.releasePage(grpId, partMetaId, partMetaPage);
+                }
+            }
+        }
+
+        return wasSaveToMeta;
+    }
+
+    /**
+     * @param cacheSizes Cache sizes.
+     * @return Serialized cache sizes
+     */
+    private byte[] serializeCacheSizes(Map<Integer, Long> cacheSizes) {
+        // Item size = 4 bytes (cache ID) + 8 bytes (cache size) = 12 bytes
+        byte[] data = new byte[cacheSizes.size() * 12];
+        long off = GridUnsafe.BYTE_ARR_OFF;
+
+        for (Map.Entry<Integer, Long> entry : cacheSizes.entrySet()) {
+            GridUnsafe.putInt(data, off, entry.getKey()); off += 4;
+            GridUnsafe.putLong(data, off, entry.getValue()); off += 8;
+        }
+
+        return data;
+    }
+
+    /**
+     * @param map Map to add values to.
+     * @param pageAddr page address
+     * @param io Page Meta IO
+     * @param cacheId Cache ID.
+     * @param partition Partition ID.
+     * @param pages Number of pages to add.
+     */
+    private static void addPartition(
+        Map<T2<Integer, Integer>, T2<Integer, Integer>> map,
+        long pageAddr,
+        PagePartitionMetaIO io,
+        int cacheId,
+        int partition,
+        int pages
+    ) {
+        if (pages <= 1)
+            return;
+
+        assert PageIO.getPageId(pageAddr) != 0;
+
+        int lastAllocatedIdx = io.getLastPageCount(pageAddr);
+        map.put(new T2<>(cacheId, partition), new T2<>(lastAllocatedIdx, pages));
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void destroyCacheDataStore0(CacheDataStore store) throws IgniteCheckedException {
+        ctx.database().checkpointReadLock();
+
+        try {
+            int p = store.partId();
+
+            saveStoreMetadata(store, null, false, true);
+
+            PageMemoryEx pageMemory = (PageMemoryEx)grp.memoryPolicy().pageMemory();
+
+            int tag = pageMemory.invalidate(grp.groupId(), p);
+
+            ctx.wal().log(new PartitionDestroyRecord(grp.groupId(), p));
+
+            ctx.pageStore().onPartitionDestroyed(grp.groupId(), p, tag);
+        }
+        finally {
+            ctx.database().checkpointReadUnlock();
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onPartitionCounterUpdated(int part, long cntr) {
+        CacheDataStore store = partDataStores.get(part);
+
+        assert store != null;
+
+        long oldCnt = store.updateCounter();
+
+        if (oldCnt < cntr)
+            store.updateCounter(cntr);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onPartitionInitialCounterUpdated(int part, long cntr) {
+        CacheDataStore store = partDataStores.get(part);
+
+        assert store != null;
+
+        long oldCnt = store.initialUpdateCounter();
+
+        if (oldCnt < cntr)
+            store.updateInitialCounter(cntr);
+    }
+
+    /** {@inheritDoc} */
+    @Override public long lastUpdatedPartitionCounter(int part) {
+        return partDataStores.get(part).updateCounter();
+    }
+
+    /** {@inheritDoc} */
+    @Override public RootPage rootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
+        if (grp.sharedGroup())
+            idxName = Integer.toString(cacheId) + "_" + idxName;
+
+        return metaStore.getOrAllocateForTree(idxName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void dropRootPageForIndex(int cacheId, String idxName) throws IgniteCheckedException {
+        if (grp.sharedGroup())
+            idxName = Integer.toString(cacheId) + "_" + idxName;
+
+        metaStore.dropRootPage(idxName);
+    }
+
+    /** {@inheritDoc} */
+    @Override public ReuseList reuseListForIndex(String idxName) {
+        return reuseList;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void stop() {
+        if (grp.affinityNode())
+            ((GridCacheDatabaseSharedManager)ctx.database()).removeCheckpointListener(this);
+    }
+
+    /**
+     * @return Meta root pages info.
+     * @throws IgniteCheckedException If failed.
+     */
+    private Metas getOrAllocateCacheMetas() throws IgniteCheckedException {
+        PageMemoryEx pageMem = (PageMemoryEx)grp.memoryPolicy().pageMemory();
+        IgniteWriteAheadLogManager wal = ctx.wal();
+
+        int grpId = grp.groupId();
+        long metaId = pageMem.metaPageId(grpId);
+        long metaPage = pageMem.acquirePage(grpId, metaId);
+
+        try {
+            final long pageAddr = pageMem.writeLock(grpId, metaId, metaPage);
+
+            boolean allocated = false;
+
+            try {
+                long metastoreRoot, reuseListRoot;
+
+                if (PageIO.getType(pageAddr) != PageIO.T_META) {
+                    PageMetaIO pageIO = PageMetaIO.VERSIONS.latest();
+
+                    pageIO.initNewPage(pageAddr, metaId, pageMem.pageSize());
+
+                    metastoreRoot = pageMem.allocatePage(grpId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX);
+                    reuseListRoot = pageMem.allocatePage(grpId, PageIdAllocator.INDEX_PARTITION, PageMemory.FLAG_IDX);
+
+                    pageIO.setTreeRoot(pageAddr, metastoreRoot);
+                    pageIO.setReuseListRoot(pageAddr, reuseListRoot);
+
+                    if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, metaId, metaPage, wal, null))
+                        wal.log(new MetaPageInitRecord(
+                            grpId,
+                            metaId,
+                            pageIO.getType(),
+                            pageIO.getVersion(),
+                            metastoreRoot,
+                            reuseListRoot
+                        ));
+
+                    allocated = true;
+                }
+                else {
+                    PageMetaIO pageIO = PageIO.getPageIO(pageAddr);
+
+                    metastoreRoot = pageIO.getTreeRoot(pageAddr);
+                    reuseListRoot = pageIO.getReuseListRoot(pageAddr);
+
+                    assert reuseListRoot != 0L;
+                }
+
+                return new Metas(
+                    new RootPage(new FullPageId(metastoreRoot, grpId), allocated),
+                    new RootPage(new FullPageId(reuseListRoot, grpId), allocated));
+            }
+            finally {
+                pageMem.writeUnlock(grpId, metaId, metaPage, null, allocated);
+            }
+        }
+        finally {
+            pageMem.releasePage(grpId, metaId, metaPage);
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgniteRebalanceIterator rebalanceIterator(int part, AffinityTopologyVersion topVer,
+        Long partCntrSince) throws IgniteCheckedException {
+        if (partCntrSince == null)
+            return super.rebalanceIterator(part, topVer, partCntrSince);
+
+        GridCacheDatabaseSharedManager database = (GridCacheDatabaseSharedManager)ctx.database();
+
+        try {
+            WALPointer startPtr = database.searchPartitionCounter(grp.groupId(), part, partCntrSince);
+
+            if (startPtr == null) {
+                assert false : "partCntr=" + partCntrSince + ", reservations=" + S.toString(Map.class, database.reservedForPreloading());
+
+                return super.rebalanceIterator(part, topVer, partCntrSince);
+            }
+
+            WALIterator it = ctx.wal().replay(startPtr);
+
+            return new RebalanceIteratorAdapter(grp, it, part);
+        }
+        catch (IgniteCheckedException e) {
+            U.warn(log, "Failed to create WAL-based rebalance iterator (a full partition will transferred to a " +
+                "remote node) [part=" + part + ", partCntrSince=" + partCntrSince + ", err=" + e + ']');
+
+            return super.rebalanceIterator(part, topVer, partCntrSince);
+        }
+    }
+
+    /**
+     *
+     */
+    private static class RebalanceIteratorAdapter implements IgniteRebalanceIterator {
+        /** Serial version uid. */
+        private static final long serialVersionUID = 0L;
+
+        /** Cache group caches. */
+        private final Set<Integer> cacheGrpCaches;
+
+        /** WAL iterator. */
+        private final WALIterator walIt;
+
+        /** Partition to scan. */
+        private final int part;
+
+        /** */
+        private Iterator<DataEntry> entryIt;
+
+        /** */
+        private CacheDataRow next;
+
+        /**
+         * @param grp Cache group.
+         * @param walIt WAL iterator.
+         * @param part Partition ID.
+         */
+        private RebalanceIteratorAdapter(CacheGroupContext grp, WALIterator walIt, int part) {
+            this.cacheGrpCaches = grp.cacheIds();
+            this.walIt = walIt;
+            this.part = part;
+
+            advance();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean historical() {
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void close() throws IgniteCheckedException {
+            walIt.close();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean isClosed() {
+            return walIt.isClosed();
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean hasNextX() {
+            return hasNext();
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheDataRow nextX() throws IgniteCheckedException {
+            return next();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void removeX() throws IgniteCheckedException {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        @Override public Iterator<CacheDataRow> iterator() {
+            return this;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean hasNext() {
+            return next != null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheDataRow next() {
+            if (next == null)
+                throw new NoSuchElementException();
+
+            CacheDataRow val = next;
+
+            advance();
+
+            return val;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         *
+         */
+        private void advance() {
+            next = null;
+
+            while (true) {
+                if (entryIt != null) {
+                    while (entryIt.hasNext()) {
+                        DataEntry entry = entryIt.next();
+
+                        if (entry.partitionId() == part && cacheGrpCaches.contains(entry.cacheId())) {
+
+                            next = new DataEntryRow(entry);
+
+                            return;
+                        }
+                    }
+                }
+
+                entryIt = null;
+
+                while (walIt.hasNext()) {
+                    IgniteBiTuple<WALPointer, WALRecord> rec = walIt.next();
+
+                    if (rec.get2() instanceof DataRecord) {
+                        DataRecord data = (DataRecord)rec.get2();
+
+                        entryIt = data.writeEntries().iterator();
+                        // Move on to the next valid data entry.
+
+                        break;
+                    }
+                }
+
+                if (entryIt == null)
+                    return;
+            }
+        }
+    }
+
+    /**
+     * Data entry row.
+     */
+    private static class DataEntryRow implements CacheDataRow {
+        /** */
+        private final DataEntry entry;
+
+        /**
+         * @param entry Data entry.
+         */
+        private DataEntryRow(DataEntry entry) {
+            this.entry = entry;
+        }
+
+        /** {@inheritDoc} */
+        @Override public KeyCacheObject key() {
+            return entry.key();
+        }
+
+        /** {@inheritDoc} */
+        @Override public void key(KeyCacheObject key) {
+            throw new IllegalStateException();
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheObject value() {
+            return entry.value();
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridCacheVersion version() {
+            return entry.writeVersion();
+        }
+
+        /** {@inheritDoc} */
+        @Override public long expireTime() {
+            return entry.expireTime();
+        }
+
+        /** {@inheritDoc} */
+        @Override public int partition() {
+            return entry.partitionId();
+        }
+
+        /** {@inheritDoc} */
+        @Override public long link() {
+            return 0;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void link(long link) {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hash() {
+            return entry.key().hashCode();
+        }
+
+        /** {@inheritDoc} */
+        @Override public int cacheId() {
+            return entry.cacheId();
+        }
+    }
+
+    /**
+     *
+     */
+    private static class Metas {
+        /** */
+        @GridToStringInclude
+        private final RootPage reuseListRoot;
+
+        /** */
+        @GridToStringInclude
+        private final RootPage treeRoot;
+
+        /**
+         * @param treeRoot Metadata storage root.
+         * @param reuseListRoot Reuse list root.
+         */
+        Metas(RootPage treeRoot, RootPage reuseListRoot) {
+            this.treeRoot = treeRoot;
+            this.reuseListRoot = reuseListRoot;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(Metas.class, this);
+        }
+    }
+
+    /**
+     *
+     */
+    private class GridCacheDataStore implements CacheDataStore {
+        /** */
+        private final int partId;
+
+        /** */
+        private String name;
+
+        /** */
+        private volatile FreeListImpl freeList;
+
+        /** */
+        private volatile CacheDataStore delegate;
+
+        /** */
+        private final boolean exists;
+
+        /** */
+        private final AtomicBoolean init = new AtomicBoolean();
+
+        /** */
+        private final CountDownLatch latch = new CountDownLatch(1);
+
+        /**
+         * @param partId Partition.
+         * @param exists {@code True} if store for this index exists.
+         */
+        private GridCacheDataStore(int partId, boolean exists) {
+            this.partId = partId;
+            this.exists = exists;
+
+            name = treeName(partId);
+        }
+
+        /**
+         * @return Store delegate.
+         * @throws IgniteCheckedException If failed.
+         */
+        private CacheDataStore init0(boolean checkExists) throws IgniteCheckedException {
+            CacheDataStore delegate0 = delegate;
+
+            if (delegate0 != null)
+                return delegate0;
+
+            if (checkExists) {
+                if (!exists)
+                    return null;
+            }
+
+            IgniteCacheDatabaseSharedManager dbMgr = ctx.database();
+
+            dbMgr.checkpointReadLock();
+
+            if (init.compareAndSet(false, true)) {
+                try {
+                    Metas metas = getOrAllocatePartitionMetas();
+
+                    RootPage reuseRoot = metas.reuseListRoot;
+
+                    freeList = new FreeListImpl(
+                        grp.groupId(),
+                        grp.cacheOrGroupName() + "-" + partId,
+                        grp.memoryPolicy().memoryMetrics(),
+                        grp.memoryPolicy(),
+                        null,
+                        ctx.wal(),
+                        reuseRoot.pageId().pageId(),
+                        reuseRoot.isAllocated()) {
+                        @Override protected long allocatePageNoReuse() throws IgniteCheckedException {
+                            return pageMem.allocatePage(cacheId, partId, PageIdAllocator.FLAG_DATA);
+                        }
+                    };
+
+                    CacheDataRowStore rowStore = new CacheDataRowStore(grp, freeList, partId);
+
+                    RootPage treeRoot = metas.treeRoot;
+
+                    CacheDataTree dataTree = new CacheDataTree(
+                        grp,
+                        name,
+                        freeList,
+                        rowStore,
+                        treeRoot.pageId().pageId(),
+                        treeRoot.isAllocated()) {
+                        @Override protected long allocatePageNoReuse() throws IgniteCheckedException {
+                            return pageMem.allocatePage(cacheId, partId, PageIdAllocator.FLAG_DATA);
+                        }
+                    };
+
+                    PageMemoryEx pageMem = (PageMemoryEx)grp.memoryPolicy().pageMemory();
+
+                    delegate0 = new CacheDataStoreImpl(partId, name, rowStore, dataTree);
+
+                    int grpId = grp.groupId();
+                    long partMetaId = pageMem.partitionMetaPageId(grpId, partId);
+                    long partMetaPage = pageMem.acquirePage(grpId, partMetaId);
+
+                    try {
+                        long pageAddr = pageMem.readLock(grpId, partMetaId, partMetaPage);
+
+                        try {
+                            if (PageIO.getType(pageAddr) != 0) {
+                                PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest();
+
+                                Map<Integer, Long> cacheSizes = null;
+
+                                if (grp.sharedGroup()) {
+                                    long cntrsPageId = io.getCountersPageId(pageAddr);
+
+                                    if (cntrsPageId != 0L) {
+                                        cacheSizes = new HashMap<>();
+
+                                        long nextId = cntrsPageId;
+
+                                        while (true){
+                                            final long curId = nextId;
+                                            final long curPage = pageMem.acquirePage(grpId, curId);
+
+                                            try {
+                                                final long curAddr = pageMem.readLock(grpId, curId, curPage);
+
+                                                assert curAddr != 0;
+
+                                                try {
+                                                    PagePartitionCountersIO cntrsIO = PageIO.getPageIO(curAddr);
+
+                                                    if (cntrsIO.readCacheSizes(curAddr, cacheSizes))
+                                                        break;
+
+                                                    nextId = cntrsIO.getNextCountersPageId(curAddr);
+
+                                                    assert nextId != 0;
+                                                }
+                                                finally {
+                                                    pageMem.readUnlock(grpId, curId, curPage);
+                                                }
+                                            }
+                                            finally {
+                                                pageMem.releasePage(grpId, curId, curPage);
+                                            }
+                                        }
+                                    }
+                                }
+
+                                delegate0.init(io.getSize(pageAddr), io.getUpdateCounter(pageAddr), cacheSizes);
+
+                                globalRemoveId().setIfGreater(io.getGlobalRemoveId(pageAddr));
+                            }
+                        }
+                        finally {
+                            pageMem.readUnlock(grpId, partMetaId, partMetaPage);
+                        }
+                    }
+                    finally {
+                        pageMem.releasePage(grpId, partMetaId, partMetaPage);
+                    }
+
+                    delegate = delegate0;
+                }
+                finally {
+                    latch.countDown();
+
+                    dbMgr.checkpointReadUnlock();
+                }
+            }
+            else {
+                dbMgr.checkpointReadUnlock();
+
+                U.await(latch);
+
+                delegate0 = delegate;
+
+                if (delegate0 == null)
+                    throw new IgniteCheckedException("Cache store initialization failed.");
+            }
+
+            return delegate0;
+        }
+
+        /**
+         * @return Partition metas.
+         */
+        private Metas getOrAllocatePartitionMetas() throws IgniteCheckedException {
+            PageMemoryEx pageMem = (PageMemoryEx)grp.memoryPolicy().pageMemory();
+            IgniteWriteAheadLogManager wal = ctx.wal();
+
+            int grpId = grp.groupId();
+            long partMetaId = pageMem.partitionMetaPageId(grpId, partId);
+            long partMetaPage = pageMem.acquirePage(grpId, partMetaId);
+            try {
+                boolean allocated = false;
+                long pageAddr = pageMem.writeLock(grpId, partMetaId, partMetaPage);
+
+                try {
+                    long treeRoot, reuseListRoot;
+
+                    // Initialize new page.
+                    if (PageIO.getType(pageAddr) != PageIO.T_PART_META) {
+                        PagePartitionMetaIO io = PagePartitionMetaIO.VERSIONS.latest();
+
+                        io.initNewPage(pageAddr, partMetaId, pageMem.pageSize());
+
+                        treeRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA);
+                        reuseListRoot = pageMem.allocatePage(grpId, partId, PageMemory.FLAG_DATA);
+
+                        assert PageIdUtils.flag(treeRoot) == PageMemory.FLAG_DATA;
+                        assert PageIdUtils.flag(reuseListRoot) == PageMemory.FLAG_DATA;
+
+                        io.setTreeRoot(pageAddr, treeRoot);
+                        io.setReuseListRoot(pageAddr, reuseListRoot);
+
+                        if (PageHandler.isWalDeltaRecordNeeded(pageMem, grpId, partMetaId, partMetaPage, wal, null))
+                            wal.log(new MetaPageInitRecord(
+                                grpId,
+                                partMetaId,
+                                io.getType(),
+                                io.getVersion(),
+                                treeRoot,
+                                reuseListRoot
+                            ));
+
+                        allocated = true;
+                    }
+                    else {
+                        PagePartitionMetaIO io = PageIO.getPageIO(pageAddr);
+
+                        treeRoot = io.getTreeRoot(pageAddr);
+                        reuseListRoot = io.getReuseListRoot(pageAddr);
+
+                        assert PageIdUtils.flag(treeRoot) == PageMemory.FLAG_DATA :
+                            U.hexLong(treeRoot) + ", part=" + partId + ", grpId=" + grpId;
+                        assert PageIdUtils.flag(reuseListRoot) == PageMemory.FLAG_DATA :
+                            U.hexLong(reuseListRoot) + ", part=" + partId + ", grpId=" + grpId;
+                    }
+
+                    return new Metas(
+                        new RootPage(new FullPageId(treeRoot, grpId), allocated),
+                        new RootPage(new FullPageId(reuseListRoot, grpId), allocated));
+                }
+                finally {
+                    pageMem.writeUnlock(grpId, partMetaId, partMetaPage, null, allocated);
+                }
+            }
+            finally {
+                pageMem.releasePage(grpId, partMetaId, partMetaPage);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public int partId() {
+            return partId;
+        }
+
+        /** {@inheritDoc} */
+        @Override public String name() {
+            return name;
+        }
+
+        /** {@inheritDoc} */
+        @Override public RowStore rowStore() {
+            CacheDataStore delegate0 = delegate;
+
+            return delegate0 == null ? null : delegate0.rowStore();
+        }
+
+        /** {@inheritDoc} */
+        @Override public int fullSize() {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                return delegate0 == null ? 0 : delegate0.fullSize();
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public int cacheSize(int cacheId) {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                return delegate0 == null ? 0 : delegate0.cacheSize(cacheId);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public Map<Integer, Long> cacheSizes() {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                return delegate0 == null ? null : delegate0.cacheSizes();
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public long updateCounter() {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                return delegate0 == null ? 0 : delegate0.updateCounter();
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void init(long size, long updCntr, @Nullable Map<Integer, Long> cacheSizes) {
+            throw new IllegalStateException("Should be never called.");
+        }
+
+        /** {@inheritDoc} */
+        @Override public void updateCounter(long val) {
+            try {
+                CacheDataStore delegate0 = init0(false);
+
+                if (delegate0 != null)
+                    delegate0.updateCounter(val);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public long nextUpdateCounter() {
+            try {
+                CacheDataStore delegate0 = init0(false);
+
+                return delegate0 == null ? 0 : delegate0.nextUpdateCounter();
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public Long initialUpdateCounter() {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                return delegate0 == null ? 0 : delegate0.initialUpdateCounter();
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void updateInitialCounter(long cntr) {
+            try {
+                CacheDataStore delegate0 = init0(true);
+
+                if (delegate0 != null)
+                    delegate0.updateInitialCounter(cntr);
+            }
+            catch (IgniteCheckedException e) {
+                throw new IgniteException(e);
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void update(
+            GridCacheContext cctx,
+            KeyCacheObject key,
+            CacheObject val,
+            GridCacheVersion ver,
+            long expireTime,
+            @Nullable CacheDataRow oldRow
+        ) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(false);
+
+            delegate.update(cctx, key, val, ver, expireTime, oldRow);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void updateIndexes(GridCacheContext cctx, KeyCacheObject key) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(false);
+
+            delegate.updateIndexes(cctx, key);
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheDataRow createRow(
+            GridCacheContext cctx,
+            KeyCacheObject key,
+            CacheObject val,
+            GridCacheVersion ver,
+            long expireTime,
+            @Nullable CacheDataRow oldRow) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(false);
+
+            return delegate.createRow(cctx, key, val, ver, expireTime, oldRow);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void invoke(GridCacheContext cctx, KeyCacheObject key, OffheapInvokeClosure c)
+            throws IgniteCheckedException {
+            CacheDataStore delegate = init0(false);
+
+            delegate.invoke(cctx, key, c);
+        }
+
+        /** {@inheritDoc} */
+        @Override public void remove(GridCacheContext cctx, KeyCacheObject key, int partId)
+            throws IgniteCheckedException {
+            CacheDataStore delegate = init0(false);
+
+            delegate.remove(cctx, key, partId);
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheDataRow find(GridCacheContext cctx, KeyCacheObject key) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                return delegate.find(cctx, key);
+
+            return null;
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridCursor<? extends CacheDataRow> cursor() throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                return delegate.cursor();
+
+            return EMPTY_CURSOR;
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridCursor<? extends CacheDataRow> cursor(
+            int cacheId,
+            KeyCacheObject lower,
+            KeyCacheObject upper) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                return delegate.cursor(cacheId, lower, upper);
+
+            return EMPTY_CURSOR;
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridCursor<? extends CacheDataRow> cursor(int cacheId,
+            KeyCacheObject lower,
+            KeyCacheObject upper,
+            Object x)
+            throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                return delegate.cursor(cacheId, lower, upper, x);
+
+            return EMPTY_CURSOR;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void destroy() throws IgniteCheckedException {
+            // No need to destroy delegate.
+        }
+
+        /** {@inheritDoc} */
+        @Override public GridCursor<? extends CacheDataRow> cursor(int cacheId) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                return delegate.cursor(cacheId);
+
+            return EMPTY_CURSOR;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void clear(int cacheId) throws IgniteCheckedException {
+            CacheDataStore delegate = init0(true);
+
+            if (delegate != null)
+                delegate.clear(cacheId);
+        }
+    }
+
+    /**
+     *
+     */
+    private static final GridCursor<CacheDataRow> EMPTY_CURSOR = new GridCursor<CacheDataRow>() {
+        /** {@inheritDoc} */
+        @Override public boolean next() {
+            return false;
+        }
+
+        /** {@inheritDoc} */
+        @Override public CacheDataRow get() {
+            return null;
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/6bf5ce46/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
new file mode 100644
index 0000000..e45d379
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/IgniteCacheDatabaseSharedManager.java
@@ -0,0 +1,968 @@
+/*
+ * 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.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javax.management.JMException;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.MemoryMetrics;
+import org.apache.ignite.PersistenceMetrics;
+import org.apache.ignite.configuration.DataPageEvictionMode;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.MemoryConfiguration;
+import org.apache.ignite.configuration.MemoryPolicyConfiguration;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.mem.DirectMemoryProvider;
+import org.apache.ignite.internal.mem.file.MappedFileMemoryProvider;
+import org.apache.ignite.internal.mem.unsafe.UnsafeMemoryProvider;
+import org.apache.ignite.internal.pagemem.PageMemory;
+import org.apache.ignite.internal.pagemem.impl.PageMemoryNoStoreImpl;
+import org.apache.ignite.internal.processors.cache.CacheGroupContext;
+import org.apache.ignite.internal.processors.cache.GridCacheContext;
+import org.apache.ignite.internal.processors.cache.GridCacheMapEntry;
+import org.apache.ignite.internal.processors.cache.GridCacheSharedManagerAdapter;
+import org.apache.ignite.internal.processors.cache.persistence.evict.FairFifoPageEvictionTracker;
+import org.apache.ignite.internal.processors.cache.persistence.evict.NoOpPageEvictionTracker;
+import org.apache.ignite.internal.processors.cache.persistence.evict.PageEvictionTracker;
+import org.apache.ignite.internal.processors.cache.persistence.evict.Random2LruPageEvictionTracker;
+import org.apache.ignite.internal.processors.cache.persistence.evict.RandomLruPageEvictionTracker;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeListImpl;
+import org.apache.ignite.internal.processors.cache.persistence.tree.reuse.ReuseList;
+import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsExchangeFuture;
+import org.apache.ignite.internal.processors.cluster.IgniteChangeGlobalStateSupport;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.LT;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteBiTuple;
+import org.apache.ignite.mxbean.MemoryMetricsMXBean;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.configuration.MemoryConfiguration.DFLT_MEMORY_POLICY_INITIAL_SIZE;
+import static org.apache.ignite.configuration.MemoryConfiguration.DFLT_MEM_PLC_DEFAULT_NAME;
+
+/**
+ *
+ */
+public class IgniteCacheDatabaseSharedManager extends GridCacheSharedManagerAdapter
+    implements IgniteChangeGlobalStateSupport, CheckpointLockStateChecker {
+    /** MemoryPolicyConfiguration name reserved for internal caches. */
+    static final String SYSTEM_MEMORY_POLICY_NAME = "sysMemPlc";
+
+    /** Minimum size of memory chunk */
+    private static final long MIN_PAGE_MEMORY_SIZE = 10 * 1024 * 1024;
+
+    /** Maximum initial size on 32-bit JVM */
+    private static final long MAX_PAGE_MEMORY_INIT_SIZE_32_BIT = 2L * 1024 * 1024 * 1024;
+
+    /** */
+    protected Map<String, MemoryPolicy> memPlcMap;
+
+    /** */
+    protected Map<String, MemoryMetrics> memMetricsMap;
+
+    /** */
+    protected MemoryPolicy dfltMemPlc;
+
+    /** */
+    private Map<String, FreeListImpl> freeListMap;
+
+    /** */
+    private FreeListImpl dfltFreeList;
+
+    /** */
+    private int pageSize;
+
+    /** {@inheritDoc} */
+    @Override protected void start0() throws IgniteCheckedException {
+        if (cctx.kernalContext().clientNode() && cctx.kernalContext().config().getMemoryConfiguration() == null)
+            return;
+
+        init();
+    }
+
+    /**
+     * @throws IgniteCheckedException If failed.
+     */
+    public void init() throws IgniteCheckedException {
+        MemoryConfiguration memCfg = cctx.kernalContext().config().getMemoryConfiguration();
+
+        assert memCfg != null;
+
+        validateConfiguration(memCfg);
+
+        pageSize = memCfg.getPageSize();
+
+        initPageMemoryPolicies(memCfg);
+
+        //registerMetricsMBeans();
+
+        startMemoryPolicies();
+
+        initPageMemoryDataStructures(memCfg);
+    }
+
+    /**
+     * Registers MBeans for all MemoryMetrics configured in this instance.
+     */
+    private void registerMetricsMBeans() {
+        IgniteConfiguration cfg = cctx.gridConfig();
+
+        for (MemoryMetrics memMetrics : memMetricsMap.values()) {
+            MemoryPolicyConfiguration memPlcCfg = memPlcMap.get(memMetrics.getName()).config();
+
+            registerMetricsMBean((MemoryMetricsImpl)memMetrics, memPlcCfg, cfg);
+        }
+    }
+
+    /**
+     * @param memMetrics Memory metrics.
+     * @param memPlcCfg Memory policy configuration.
+     * @param cfg Ignite configuration.
+     */
+    private void registerMetricsMBean(
+        MemoryMetricsImpl memMetrics,
+        MemoryPolicyConfiguration memPlcCfg,
+        IgniteConfiguration cfg
+    ) {
+        try {
+            U.registerMBean(
+                    cfg.getMBeanServer(),
+                    cfg.getIgniteInstanceName(),
+                    "MemoryMetrics",
+                    memPlcCfg.getName(),
+                    new MemoryMetricsMXBeanImpl(memMetrics, memPlcCfg),
+                    MemoryMetricsMXBean.class);
+        }
+        catch (JMException e) {
+            U.error(log, "Failed to register MBean for MemoryMetrics with name: '" + memMetrics.getName() + "'", e);
+        }
+    }
+
+    /**
+     * @param dbCfg Database config.
+     */
+    protected void initPageMemoryDataStructures(MemoryConfiguration dbCfg) throws IgniteCheckedException {
+        freeListMap = U.newHashMap(memPlcMap.size());
+
+        String dfltMemPlcName = dbCfg.getDefaultMemoryPolicyName();
+
+        for (MemoryPolicy memPlc : memPlcMap.values()) {
+            MemoryPolicyConfiguration memPlcCfg = memPlc.config();
+
+            MemoryMetricsImpl memMetrics = (MemoryMetricsImpl) memMetricsMap.get(memPlcCfg.getName());
+
+            FreeListImpl freeList = new FreeListImpl(0,
+                    cctx.igniteInstanceName(),
+                    memMetrics,
+                    memPlc,
+                    null,
+                    cctx.wal(),
+                    0L,
+                    true);
+
+            memMetrics.freeList(freeList);
+
+            freeListMap.put(memPlcCfg.getName(), freeList);
+        }
+
+        dfltFreeList = freeListMap.get(dfltMemPlcName);
+    }
+
+    /**
+     * @return Size of page used for PageMemory regions.
+     */
+    public int pageSize() {
+        return pageSize;
+    }
+
+    /**
+     *
+     */
+    private void startMemoryPolicies() {
+        for (MemoryPolicy memPlc : memPlcMap.values()) {
+            memPlc.pageMemory().start();
+
+            memPlc.evictionTracker().start();
+        }
+    }
+
+    /**
+     * @param memCfg Database config.
+     */
+    protected void initPageMemoryPolicies(MemoryConfiguration memCfg) {
+        MemoryPolicyConfiguration[] memPlcsCfgs = memCfg.getMemoryPolicies();
+
+        if (memPlcsCfgs == null) {
+            //reserve place for default and system memory policies
+            memPlcMap = U.newHashMap(2);
+            memMetricsMap = U.newHashMap(2);
+
+            addMemoryPolicy(
+                memCfg,
+                memCfg.createDefaultPolicyConfig(),
+                DFLT_MEM_PLC_DEFAULT_NAME
+            );
+
+            U.warn(log, "No user-defined default MemoryPolicy found; system default of 1GB size will be used.");
+        }
+        else {
+            String dfltMemPlcName = memCfg.getDefaultMemoryPolicyName();
+
+            if (DFLT_MEM_PLC_DEFAULT_NAME.equals(dfltMemPlcName) && !hasCustomDefaultMemoryPolicy(memPlcsCfgs)) {
+                //reserve additional place for default and system memory policies
+                memPlcMap = U.newHashMap(memPlcsCfgs.length + 2);
+                memMetricsMap = U.newHashMap(memPlcsCfgs.length + 2);
+
+                addMemoryPolicy(
+                    memCfg,
+                    memCfg.createDefaultPolicyConfig(),
+                    DFLT_MEM_PLC_DEFAULT_NAME
+                );
+
+                U.warn(log, "No user-defined default MemoryPolicy found; system default of 1GB size will be used.");
+            }
+            else {
+                //reserve additional space for system memory policy only
+                memPlcMap = U.newHashMap(memPlcsCfgs.length + 1);
+                memMetricsMap = U.newHashMap(memPlcsCfgs.length + 1);
+            }
+
+            for (MemoryPolicyConfiguration memPlcCfg : memPlcsCfgs)
+                addMemoryPolicy(memCfg, memPlcCfg, memPlcCfg.getName());
+        }
+
+        addMemoryPolicy(
+            memCfg,
+            createSystemMemoryPolicy(
+                memCfg.getSystemCacheInitialSize(),
+                memCfg.getSystemCacheMaxSize()
+            ),
+            SYSTEM_MEMORY_POLICY_NAME
+        );
+    }
+
+    /**
+     * @param memCfg Database config.
+     * @param memPlcCfg Memory policy config.
+     * @param memPlcName Memory policy name.
+     */
+    private void addMemoryPolicy(
+        MemoryConfiguration memCfg,
+        MemoryPolicyConfiguration memPlcCfg,
+        String memPlcName
+    ) {
+        String dfltMemPlcName = memCfg.getDefaultMemoryPolicyName();
+
+        if (dfltMemPlcName == null)
+            dfltMemPlcName = DFLT_MEM_PLC_DEFAULT_NAME;
+
+        MemoryMetricsImpl memMetrics = new MemoryMetricsImpl(memPlcCfg);
+
+        MemoryPolicy memPlc = initMemory(memCfg, memPlcCfg, memMetrics);
+
+        memPlcMap.put(memPlcName, memPlc);
+
+        memMetricsMap.put(memPlcName, memMetrics);
+
+        if (memPlcName.equals(dfltMemPlcName))
+            dfltMemPlc = memPlc;
+        else if (memPlcName.equals(DFLT_MEM_PLC_DEFAULT_NAME))
+            U.warn(log, "Memory Policy with name 'default' isn't used as a default. " +
+                    "Please check Memory Policies configuration.");
+    }
+
+    /**
+     * @param memPlcsCfgs User-defined memory policy configurations.
+     */
+    private boolean hasCustomDefaultMemoryPolicy(MemoryPolicyConfiguration[] memPlcsCfgs) {
+        for (MemoryPolicyConfiguration memPlcsCfg : memPlcsCfgs) {
+            if (DFLT_MEM_PLC_DEFAULT_NAME.equals(memPlcsCfg.getName()))
+                return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param dbCfg Database configuration.
+     * @param memPlcCfg MemoryPolicy configuration.
+     * @param memMetrics MemoryMetrics instance.
+     */
+    private MemoryPolicy createDefaultMemoryPolicy(MemoryConfiguration dbCfg, MemoryPolicyConfiguration memPlcCfg, MemoryMetricsImpl memMetrics) {
+        return initMemory(dbCfg, memPlcCfg, memMetrics);
+    }
+
+    /**
+     * @param sysCacheInitSize Initial size of PageMemory to be created for system cache.
+     * @param sysCacheMaxSize Maximum size of PageMemory to be created for system cache.
+     *
+     * @return {@link MemoryPolicyConfiguration configuration} of MemoryPolicy for system cache.
+     */
+    private MemoryPolicyConfiguration createSystemMemoryPolicy(long sysCacheInitSize, long sysCacheMaxSize) {
+        MemoryPolicyConfiguration res = new MemoryPolicyConfiguration();
+
+        res.setName(SYSTEM_MEMORY_POLICY_NAME);
+        res.setInitialSize(sysCacheInitSize);
+        res.setMaxSize(sysCacheMaxSize);
+
+        return res;
+    }
+
+    /**
+     * @param memCfg configuration to validate.
+     */
+    private void validateConfiguration(MemoryConfiguration memCfg) throws IgniteCheckedException {
+        MemoryPolicyConfiguration[] plcCfgs = memCfg.getMemoryPolicies();
+
+        Set<String> plcNames = (plcCfgs != null) ? U.<String>newHashSet(plcCfgs.length) : new HashSet<String>(0);
+
+        checkSystemMemoryPolicySizeConfiguration(
+            memCfg.getSystemCacheInitialSize(),
+            memCfg.getSystemCacheMaxSize()
+        );
+
+        if (plcCfgs != null) {
+            for (MemoryPolicyConfiguration plcCfg : plcCfgs) {
+                assert plcCfg != null;
+
+                checkPolicyName(plcCfg.getName(), plcNames);
+
+                checkPolicySize(plcCfg);
+
+                checkMetricsProperties(plcCfg);
+
+                checkPolicyEvictionProperties(plcCfg, memCfg);
+            }
+        }
+
+        checkDefaultPolicyConfiguration(
+            memCfg.getDefaultMemoryPolicyName(),
+            memCfg.getDefaultMemoryPolicySize(),
+            plcNames
+        );
+    }
+
+    /**
+     * @param plcCfg Memory policy config.
+     *
+     * @throws IgniteCheckedException if validation of memory metrics properties fails.
+     */
+    private static void checkMetricsProperties(MemoryPolicyConfiguration plcCfg) throws IgniteCheckedException {
+        if (plcCfg.getRateTimeInterval() <= 0)
+            throw new IgniteCheckedException("Rate time interval must be greater than zero " +
+                "(use MemoryPolicyConfiguration.rateTimeInterval property to adjust the interval) " +
+                "[name=" + plcCfg.getName() +
+                ", rateTimeInterval=" + plcCfg.getRateTimeInterval() + "]"
+            );
+        if (plcCfg.getSubIntervals() <= 0)
+            throw new IgniteCheckedException("Sub intervals must be greater than zero " +
+                "(use MemoryPolicyConfiguration.subIntervals property to adjust the sub intervals) " +
+                "[name=" + plcCfg.getName() +
+                ", subIntervals=" + plcCfg.getSubIntervals() + "]"
+            );
+
+        if (plcCfg.getRateTimeInterval() < 1_000)
+            throw new IgniteCheckedException("Rate time interval must be longer that 1 second (1_000 milliseconds) " +
+                "(use MemoryPolicyConfiguration.rateTimeInterval property to adjust the interval) " +
+                "[name=" + plcCfg.getName() +
+                ", rateTimeInterval=" + plcCfg.getRateTimeInterval() + "]");
+    }
+
+    /**
+     * @param sysCacheInitSize System cache initial size.
+     * @param sysCacheMaxSize System cache max size.
+     *
+     * @throws IgniteCheckedException In case of validation violation.
+     */
+    private static void checkSystemMemoryPolicySizeConfiguration(
+        long sysCacheInitSize,
+        long sysCacheMaxSize
+    ) throws IgniteCheckedException {
+        if (sysCacheInitSize < MIN_PAGE_MEMORY_SIZE)
+            throw new IgniteCheckedException("Initial size for system cache must have size more than 10MB (use " +
+                "MemoryConfiguration.systemCacheInitialSize property to set correct size in bytes) " +
+                "[size=" + U.readableSize(sysCacheInitSize, true) + ']'
+            );
+
+        if (U.jvm32Bit() && sysCacheInitSize > MAX_PAGE_MEMORY_INIT_SIZE_32_BIT)
+            throw new IgniteCheckedException("Initial size for system cache exceeds 2GB on 32-bit JVM (use " +
+                "MemoryPolicyConfiguration.systemCacheInitialSize property to set correct size in bytes " +
+                "or use 64-bit JVM) [size=" + U.readableSize(sysCacheInitSize, true) + ']'
+            );
+
+        if (sysCacheMaxSize < sysCacheInitSize)
+            throw new IgniteCheckedException("MaxSize of system cache must not be smaller than " +
+                "initialSize [initSize=" + U.readableSize(sysCacheInitSize, true) +
+                ", maxSize=" + U.readableSize(sysCacheMaxSize, true) + "]. " +
+                "Use MemoryConfiguration.systemCacheInitialSize/MemoryConfiguration.systemCacheMaxSize " +
+                "properties to set correct sizes in bytes."
+            );
+    }
+
+    /**
+     * @param dfltPlcName Default MemoryPolicy name.
+     * @param dfltPlcSize Default size of MemoryPolicy overridden by user (equals to -1 if wasn't specified by user).
+     * @param plcNames All MemoryPolicy names.
+     * @throws IgniteCheckedException In case of validation violation.
+     */
+    private static void checkDefaultPolicyConfiguration(
+        String dfltPlcName,
+        long dfltPlcSize,
+        Collection<String> plcNames
+    ) throws IgniteCheckedException {
+        if (dfltPlcSize != MemoryConfiguration.DFLT_MEMORY_POLICY_MAX_SIZE) {
+            if (!F.eq(dfltPlcName, MemoryConfiguration.DFLT_MEM_PLC_DEFAULT_NAME))
+                throw new IgniteCheckedException("User-defined MemoryPolicy configuration " +
+                    "and defaultMemoryPolicySize properties are set at the same time. " +
+                    "Delete either MemoryConfiguration.defaultMemoryPolicySize property " +
+                    "or user-defined default MemoryPolicy configuration");
+
+            if (dfltPlcSize < MIN_PAGE_MEMORY_SIZE)
+                throw new IgniteCheckedException("User-defined default MemoryPolicy size is less than 1MB. " +
+                        "Use MemoryConfiguration.defaultMemoryPolicySize property to set correct size.");
+
+            if (U.jvm32Bit() && dfltPlcSize > MAX_PAGE_MEMORY_INIT_SIZE_32_BIT)
+                throw new IgniteCheckedException("User-defined default MemoryPolicy size exceeds 2GB on 32-bit JVM " +
+                    "(use MemoryConfiguration.defaultMemoryPolicySize property to set correct size in bytes " +
+                    "or use 64-bit JVM) [size=" + U.readableSize(dfltPlcSize, true) + ']'
+                );
+        }
+
+        if (!DFLT_MEM_PLC_DEFAULT_NAME.equals(dfltPlcName)) {
+            if (dfltPlcName.isEmpty())
+                throw new IgniteCheckedException("User-defined default MemoryPolicy name must be non-empty");
+
+            if (!plcNames.contains(dfltPlcName))
+                throw new IgniteCheckedException("User-defined default MemoryPolicy name " +
+                    "must be presented among configured MemoryPolices: " + dfltPlcName);
+        }
+    }
+
+    /**
+     * @param plcCfg MemoryPolicyConfiguration to validate.
+     * @throws IgniteCheckedException If config is invalid.
+     */
+    private void checkPolicySize(MemoryPolicyConfiguration plcCfg) throws IgniteCheckedException {
+        if (plcCfg.getInitialSize() < MIN_PAGE_MEMORY_SIZE)
+            throw new IgniteCheckedException("MemoryPolicy must have size more than 10MB (use " +
+                "MemoryPolicyConfiguration.initialSize property to set correct size in bytes) " +
+                "[name=" + plcCfg.getName() + ", size=" + U.readableSize(plcCfg.getInitialSize(), true) + "]"
+            );
+
+        if (plcCfg.getMaxSize() < plcCfg.getInitialSize()) {
+            // We will know for sure if initialSize has been changed if we compare Longs by "==".
+            if (plcCfg.getInitialSize() == DFLT_MEMORY_POLICY_INITIAL_SIZE) {
+                plcCfg.setInitialSize(plcCfg.getMaxSize());
+
+                LT.warn(log, "MemoryPolicy maxSize=" + U.readableSize(plcCfg.getMaxSize(), true) +
+                    " is smaller than defaultInitialSize=" +
+                    U.readableSize(MemoryConfiguration.DFLT_MEMORY_POLICY_INITIAL_SIZE, true) +
+                    ", setting initialSize to " + U.readableSize(plcCfg.getMaxSize(), true));
+            }
+            else {
+                throw new IgniteCheckedException("MemoryPolicy maxSize must not be smaller than " +
+                    "initialSize [name=" + plcCfg.getName() +
+                    ", initSize=" + U.readableSize(plcCfg.getInitialSize(), true) +
+                    ", maxSize=" + U.readableSize(plcCfg.getMaxSize(), true) + ']');
+            }
+        }
+
+        if (U.jvm32Bit() && plcCfg.getInitialSize() > MAX_PAGE_MEMORY_INIT_SIZE_32_BIT)
+            throw new IgniteCheckedException("MemoryPolicy initialSize exceeds 2GB on 32-bit JVM (use " +
+                "MemoryPolicyConfiguration.initialSize property to set correct size in bytes or use 64-bit JVM) " +
+                "[name=" + plcCfg.getName() +
+                ", size=" + U.readableSize(plcCfg.getInitialSize(), true) + "]");
+    }
+
+    /**
+     * @param plcCfg MemoryPolicyConfiguration to validate.
+     * @param dbCfg Memory configuration.
+     * @throws IgniteCheckedException If config is invalid.
+     */
+    protected void checkPolicyEvictionProperties(MemoryPolicyConfiguration plcCfg, MemoryConfiguration dbCfg)
+        throws IgniteCheckedException {
+        if (plcCfg.getPageEvictionMode() == DataPageEvictionMode.DISABLED)
+            return;
+
+        if (plcCfg.getEvictionThreshold() < 0.5 || plcCfg.getEvictionThreshold() > 0.999) {
+            throw new IgniteCheckedException("Page eviction threshold must be between 0.5 and 0.999: " +
+                plcCfg.getName());
+        }
+
+        if (plcCfg.getEmptyPagesPoolSize() <= 10)
+            throw new IgniteCheckedException("Evicted pages pool size should be greater than 10: " + plcCfg.getName());
+
+        long maxPoolSize = plcCfg.getMaxSize() / dbCfg.getPageSize() / 10;
+
+        if (plcCfg.getEmptyPagesPoolSize() >= maxPoolSize) {
+            throw new IgniteCheckedException("Evicted pages pool size should be lesser than " + maxPoolSize +
+                ": " + plcCfg.getName());
+        }
+    }
+
+    /**
+     * @param plcName MemoryPolicy name to validate.
+     * @param observedNames Names of MemoryPolicies observed before.
+     * @throws IgniteCheckedException If config is invalid.
+     */
+    private static void checkPolicyName(String plcName, Collection<String> observedNames)
+        throws IgniteCheckedException {
+        if (plcName == null || plcName.isEmpty())
+            throw new IgniteCheckedException("User-defined MemoryPolicyConfiguration must have non-null and " +
+                "non-empty name.");
+
+        if (observedNames.contains(plcName))
+            throw new IgniteCheckedException("Two MemoryPolicies have the same name: " + plcName);
+
+        if (SYSTEM_MEMORY_POLICY_NAME.equals(plcName))
+            throw new IgniteCheckedException("'sysMemPlc' policy name is reserved for internal use.");
+
+        observedNames.add(plcName);
+    }
+
+    /**
+     * @param log Logger.
+     */
+    public void dumpStatistics(IgniteLogger log) {
+        if (freeListMap != null) {
+            for (FreeListImpl freeList : freeListMap.values())
+                freeList.dumpStatistics(log);
+        }
+    }
+
+    /**
+     * @throws IgniteCheckedException If failed.
+     */
+    public void initDataBase() throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /**
+     * @return collection of all configured {@link MemoryPolicy policies}.
+     */
+    public Collection<MemoryPolicy> memoryPolicies() {
+        return memPlcMap != null ? memPlcMap.values() : null;
+    }
+
+    /**
+     * @return MemoryMetrics for all MemoryPolicies configured in Ignite instance.
+     */
+    public Collection<MemoryMetrics> memoryMetrics() {
+        if (!F.isEmpty(memMetricsMap)) {
+            // Intentionally return a collection copy to make it explicitly serializable.
+            Collection<MemoryMetrics> res = new ArrayList<>(memMetricsMap.size());
+
+            for (MemoryMetrics metrics : memMetricsMap.values())
+                res.add(new MemoryMetricsSnapshot(metrics));
+
+            return res;
+        }
+        else
+            return Collections.emptyList();
+    }
+
+    /**
+     * @return PersistenceMetrics if persistence is enabled or {@code null} otherwise.
+     */
+    public PersistenceMetrics persistentStoreMetrics() {
+        return null;
+    }
+
+    /**
+     * @param memPlcName Name of {@link MemoryPolicy} to obtain {@link MemoryMetrics} for.
+     * @return {@link MemoryMetrics} snapshot for specified {@link MemoryPolicy} or {@code null} if
+     * no {@link MemoryPolicy} is configured for specified name.
+     */
+    @Nullable public MemoryMetrics memoryMetrics(String memPlcName) {
+        if (!F.isEmpty(memMetricsMap)) {
+            MemoryMetrics memMetrics = memMetricsMap.get(memPlcName);
+
+            if (memMetrics == null)
+                return null;
+            else
+                return new MemoryMetricsSnapshot(memMetrics);
+        }
+        else
+            return null;
+    }
+
+    /**
+     * @param memPlcName Memory policy name.
+     * @return {@link MemoryPolicy} instance associated with a given {@link MemoryPolicyConfiguration}.
+     * @throws IgniteCheckedException in case of request for unknown MemoryPolicy.
+     */
+    public MemoryPolicy memoryPolicy(String memPlcName) throws IgniteCheckedException {
+        if (memPlcName == null)
+            return dfltMemPlc;
+
+        if (memPlcMap == null)
+            return null;
+
+        MemoryPolicy plc;
+
+        if ((plc = memPlcMap.get(memPlcName)) == null)
+            throw new IgniteCheckedException("Requested MemoryPolicy is not configured: " + memPlcName);
+
+        return plc;
+    }
+
+    /**
+     * @param memPlcName MemoryPolicyConfiguration name.
+     * @return {@link FreeList} instance associated with a given {@link MemoryPolicyConfiguration}.
+     */
+    public FreeList freeList(String memPlcName) {
+        if (memPlcName == null)
+            return dfltFreeList;
+
+        return freeListMap != null ? freeListMap.get(memPlcName) : null;
+    }
+
+    /**
+     * @param memPlcName MemoryPolicyConfiguration name.
+     * @return {@link ReuseList} instance associated with a given {@link MemoryPolicyConfiguration}.
+     */
+    public ReuseList reuseList(String memPlcName) {
+        if (memPlcName == null)
+            return dfltFreeList;
+
+        return freeListMap != null ? freeListMap.get(memPlcName) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void stop0(boolean cancel) {
+        if (memPlcMap != null) {
+            for (MemoryPolicy memPlc : memPlcMap.values()) {
+                memPlc.pageMemory().stop();
+
+                memPlc.evictionTracker().stop();
+
+                IgniteConfiguration cfg = cctx.gridConfig();
+
+              /*  try {
+                    cfg.getMBeanServer().unregisterMBean(
+                        U.makeMBeanName(
+                            cfg.getIgniteInstanceName(),
+                            "MemoryMetrics",
+                            memPlc.memoryMetrics().getName()));
+                }
+                catch (JMException e) {
+                    U.error(log, "Failed to unregister MBean for memory metrics: " +
+                        memPlc.memoryMetrics().getName(), e);
+                }*/
+            }
+        }
+    }
+
+    /**
+     *
+     */
+    public boolean persistenceEnabled() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean checkpointLockIsHeldByThread() {
+        return false;
+    }
+
+    /**
+     *
+     */
+    public void lock() throws IgniteCheckedException {
+
+    }
+
+    /**
+     *
+     */
+    public void unLock() {
+
+    }
+
+    /**
+     * No-op for non-persistent storage.
+     */
+    public void checkpointReadLock() {
+        // No-op.
+    }
+
+    /**
+     * No-op for non-persistent storage.
+     */
+    public void checkpointReadUnlock() {
+        // No-op.
+    }
+
+    /**
+     *
+     */
+    @Nullable public IgniteInternalFuture wakeupForCheckpoint(String reason) {
+        return null;
+    }
+
+    /**
+     * Waits until current state is checkpointed.
+     *
+     * @throws IgniteCheckedException If failed.
+     */
+    public void waitForCheckpoint(String reason) throws IgniteCheckedException {
+        // No-op
+    }
+
+    /**
+     * @param discoEvt Before exchange for the given discovery event.
+     */
+    public void beforeExchange(GridDhtPartitionsExchangeFuture discoEvt) throws IgniteCheckedException {
+        // No-op.
+    }
+
+    /**
+     * Needed action before any cache will stop
+     */
+    public void prepareCachesStop() {
+        // No-op.
+    }
+
+    /**
+     * @param stoppedGrps A collection of tuples (cache group, destroy flag).
+     */
+    public void onCacheGroupsStopped(Collection<IgniteBiTuple<CacheGroupContext, Boolean>> stoppedGrps) {
+        // No-op.
+    }
+
+    /**
+     * @param cctx Stopped cache context.
+     */
+    public void onCacheStop(GridCacheContext cctx) {
+        // No-op
+    }
+
+    /**
+     * @return Future that will be completed when indexes for given cache are restored.
+     */
+    @Nullable public IgniteInternalFuture indexRebuildFuture(int cacheId) {
+        return null;
+    }
+
+    /**
+     * Reserve update history for exchange.
+     *
+     * @return Reserved update counters per cache and partition.
+     */
+    public Map<Integer, Map<Integer, Long>> reserveHistoryForExchange() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Release reserved update history.
+     */
+    public void releaseHistoryForExchange() {
+        // No-op
+    }
+
+    /**
+     * Reserve update history for preloading.
+     * @param grpId Cache group ID.
+     * @param partId Partition Id.
+     * @param cntr Update counter.
+     * @return True if successfully reserved.
+     */
+    public boolean reserveHistoryForPreloading(int grpId, int partId, long cntr) {
+        return false;
+    }
+
+    /**
+     * Release reserved update history.
+     */
+    public void releaseHistoryForPreloading() {
+        // No-op
+    }
+
+    /**
+     * See {@link GridCacheMapEntry#ensureFreeSpace()}
+     *
+     * @param memPlc Memory policy.
+     */
+    public void ensureFreeSpace(MemoryPolicy memPlc) throws IgniteCheckedException {
+        if (memPlc == null)
+            return;
+
+        MemoryPolicyConfiguration plcCfg = memPlc.config();
+
+        if (plcCfg.getPageEvictionMode() == DataPageEvictionMode.DISABLED)
+            return;
+
+        long memorySize = plcCfg.getMaxSize();
+
+        PageMemory pageMem = memPlc.pageMemory();
+
+        int sysPageSize = pageMem.systemPageSize();
+
+        FreeListImpl freeListImpl = freeListMap.get(plcCfg.getName());
+
+        for (;;) {
+            long allocatedPagesCnt = pageMem.loadedPages();
+
+            int emptyDataPagesCnt = freeListImpl.emptyDataPages();
+
+            boolean shouldEvict = allocatedPagesCnt > (memorySize / sysPageSize * plcCfg.getEvictionThreshold()) &&
+                emptyDataPagesCnt < plcCfg.getEmptyPagesPoolSize();
+
+            if (shouldEvict)
+                memPlc.evictionTracker().evictDataPage();
+            else
+                break;
+        }
+    }
+
+    /**
+     * @param memCfg memory configuration with common parameters.
+     * @param plcCfg memory policy with PageMemory specific parameters.
+     * @param memMetrics {@link MemoryMetrics} object to collect memory usage metrics.
+     * @return Memory policy instance.
+     */
+    private MemoryPolicy initMemory(
+        MemoryConfiguration memCfg,
+        MemoryPolicyConfiguration plcCfg,
+        MemoryMetricsImpl memMetrics
+    ) {
+        File allocPath = buildAllocPath(plcCfg);
+
+        DirectMemoryProvider memProvider = allocPath == null ?
+            new UnsafeMemoryProvider(log) :
+            new MappedFileMemoryProvider(
+                log,
+                allocPath);
+
+        PageMemory pageMem = createPageMemory(memProvider, memCfg, plcCfg, memMetrics);
+
+        return new MemoryPolicy(pageMem, plcCfg, memMetrics, createPageEvictionTracker(plcCfg, pageMem));
+    }
+
+    /**
+     * @param plc Memory Policy Configuration.
+     * @param pageMem Page memory.
+     */
+    private PageEvictionTracker createPageEvictionTracker(MemoryPolicyConfiguration plc, PageMemory pageMem) {
+        if (plc.getPageEvictionMode() == DataPageEvictionMode.DISABLED)
+            return new NoOpPageEvictionTracker();
+
+        assert pageMem instanceof PageMemoryNoStoreImpl : pageMem.getClass();
+
+        PageMemoryNoStoreImpl pageMem0 = (PageMemoryNoStoreImpl)pageMem;
+
+        if (Boolean.getBoolean("override.fair.fifo.page.eviction.tracker"))
+            return new FairFifoPageEvictionTracker(pageMem0, plc, cctx);
+
+        switch (plc.getPageEvictionMode()) {
+            case RANDOM_LRU:
+                return new RandomLruPageEvictionTracker(pageMem0, plc, cctx);
+            case RANDOM_2_LRU:
+                return new Random2LruPageEvictionTracker(pageMem0, plc, cctx);
+            default:
+                return new NoOpPageEvictionTracker();
+        }
+    }
+
+    /**
+     * Builds allocation path for memory mapped file to be used with PageMemory.
+     *
+     * @param plc MemoryPolicyConfiguration.
+     */
+    @Nullable protected File buildAllocPath(MemoryPolicyConfiguration plc) {
+        String path = plc.getSwapFilePath();
+
+        if (path == null)
+            return null;
+
+        String consId = String.valueOf(cctx.discovery().consistentId());
+
+        consId = consId.replaceAll("[:,\\.]", "_");
+
+        return buildPath(path, consId);
+    }
+
+    /**
+     * Creates PageMemory with given size and memory provider.
+     *
+     * @param memProvider Memory provider.
+     * @param memCfg Memory configuartion.
+     * @param memPlcCfg Memory policy configuration.
+     * @param memMetrics MemoryMetrics to collect memory usage metrics.
+     * @return PageMemory instance.
+     */
+    protected PageMemory createPageMemory(
+        DirectMemoryProvider memProvider,
+        MemoryConfiguration memCfg,
+        MemoryPolicyConfiguration memPlcCfg,
+        MemoryMetricsImpl memMetrics
+    ) {
+        memMetrics.persistenceEnabled(false);
+
+        return new PageMemoryNoStoreImpl(
+            log,
+            memProvider,
+            cctx,
+            memCfg.getPageSize(),
+            memPlcCfg,
+            memMetrics,
+            false
+        );
+    }
+
+    /**
+     * @param path Path to the working directory.
+     * @param consId Consistent ID of the local node.
+     * @return DB storage path.
+     */
+    protected File buildPath(String path, String consId) {
+        String igniteHomeStr = U.getIgniteHome();
+
+        File igniteHome = igniteHomeStr != null ? new File(igniteHomeStr) : null;
+
+        File workDir = igniteHome == null ? new File(path) : new File(igniteHome, path);
+
+        return new File(workDir, consId);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onActivate(GridKernalContext kctx) throws IgniteCheckedException {
+        start0();
+    }
+
+    /** {@inheritDoc} */
+    @Override public void onDeActivate(GridKernalContext kctx) throws IgniteCheckedException {
+        stop0(true);
+    }
+
+    /**
+     * @return Name of MemoryPolicyConfiguration for internal caches.
+     */
+    public String systemMemoryPolicyName() {
+        return SYSTEM_MEMORY_POLICY_NAME;
+    }
+}


Mime
View raw message