You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by al...@apache.org on 2019/12/24 07:44:15 UTC

[ignite] branch master updated: IGNITE-12301 Free-lists system view - Fixes #6991.

This is an automated email from the ASF dual-hosted git repository.

alexpl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new 77d21ea  IGNITE-12301 Free-lists system view - Fixes #6991.
77d21ea is described below

commit 77d21eaa367ea293233078e85ed0c967dc2b6ee7
Author: Aleksey Plekhanov <pl...@gmail.com>
AuthorDate: Tue Dec 24 10:32:35 2019 +0300

    IGNITE-12301 Free-lists system view - Fixes #6991.
    
    Signed-off-by: Aleksey Plekhanov <pl...@gmail.com>
---
 .../internal/jdbc2/JdbcMetadataSelfTest.java       |   3 +-
 .../ignite/jdbc/thin/JdbcThinMetadataSelfTest.java |  18 +++-
 .../SystemViewRowAttributeWalkerGenerator.java     |  38 +++++++
 ...dapter.java => FiltrableSystemViewAdapter.java} |  57 +++++-----
 .../managers/systemview/GridSystemViewManager.java |  27 ++++-
 .../SystemViewInnerCollectionsAdapter.java         |   6 +-
 .../walker/CachePagesListViewWalker.java           |  78 ++++++++++++++
 .../managers/systemview/walker/Filtrable.java      |  35 ++++++
 .../systemview/walker/PagesListViewWalker.java     |  68 ++++++++++++
 .../processors/cache/GridCacheProcessor.java       |  77 ++++++++++++--
 .../IgniteCacheDatabaseSharedManager.java          |  29 ++++-
 .../cache/persistence/freelist/PagesList.java      |  45 ++++++++
 .../spi/metric/jmx/ReadOnlyDynamicMBean.java       |   2 +
 .../ignite/spi/systemview/jmx/SystemViewMBean.java | 118 +++++++++++++++++----
 .../spi/systemview/view/CachePagesListView.java    |  58 ++++++++++
 .../spi/systemview/view/FiltrableSystemView.java   |  34 ++++++
 .../ignite/spi/systemview/view/PagesListView.java  |  83 +++++++++++++++
 .../view/SystemViewRowAttributeWalker.java         |  10 ++
 .../ignite/internal/metric/JmxExporterSpiTest.java |  62 +++++++++++
 .../ignite/internal/metric/SystemViewSelfTest.java | 100 +++++++++++++++++
 .../processors/query/h2/sys/SqlSystemIndex.java    |  18 +++-
 .../query/h2/sys/SystemViewH2Adapter.java          |  18 ++--
 .../h2/sys/view/SqlAbstractLocalSystemView.java    |   1 -
 .../query/h2/sys/view/SqlAbstractSystemView.java   |   5 +
 .../query/h2/sys/view/SqlSystemView.java           |   5 +
 .../spi/systemview/FiltrableSystemViewLocal.java   |  98 +++++++++++++++++
 .../ignite/spi/systemview/SqlViewExporterSpi.java  |   4 +-
 .../ignite/spi/systemview/SystemViewLocal.java     |  37 +++++--
 .../cache/metric/SqlViewExporterSpiTest.java       |  86 ++++++++++++++-
 29 files changed, 1124 insertions(+), 96 deletions(-)

diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
index 61d9a27..8c0758a 100755
--- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcMetadataSelfTest.java
@@ -341,7 +341,8 @@ public class JdbcMetadataSelfTest extends GridCommonAbstractTest {
             "VIEW_COLUMNS",
             "CONTINUOUS_QUERIES",
             "STRIPED_THREADPOOL_QUEUE",
-            "DATASTREAM_THREADPOOL_QUEUE"
+            "DATASTREAM_THREADPOOL_QUEUE",
+            "CACHE_GROUP_PAGE_LISTS"
         ));
 
         Set<String> actViews = new HashSet<>();
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
index 9655f9a..aad627a 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinMetadataSelfTest.java
@@ -355,7 +355,9 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
                 "SYS.VIEW_COLUMNS",
                 "SYS.CONTINUOUS_QUERIES",
                 "SYS.STRIPED_THREADPOOL_QUEUE",
-                "SYS.DATASTREAM_THREADPOOL_QUEUE"
+                "SYS.DATASTREAM_THREADPOOL_QUEUE",
+                "SYS.CACHE_GROUP_PAGE_LISTS",
+                "SYS.DATA_REGION_PAGE_LISTS"
             ))
         );
     }
@@ -866,7 +868,19 @@ public class JdbcThinMetadataSelfTest extends JdbcThinAbstractSelfTest {
                 "SYS.DATASTREAM_THREADPOOL_QUEUE.STRIPE_INDEX.null.10",
                 "SYS.DATASTREAM_THREADPOOL_QUEUE.DESCRIPTION.null.2147483647",
                 "SYS.DATASTREAM_THREADPOOL_QUEUE.THREAD_NAME.null.2147483647",
-                "SYS.DATASTREAM_THREADPOOL_QUEUE.TASK_NAME.null.2147483647"
+                "SYS.DATASTREAM_THREADPOOL_QUEUE.TASK_NAME.null.2147483647",
+                "SYS.CACHE_GROUP_PAGE_LISTS.CACHE_GROUP_ID.null.10",
+                "SYS.CACHE_GROUP_PAGE_LISTS.PARTITION_ID.null.10",
+                "SYS.CACHE_GROUP_PAGE_LISTS.NAME.null.2147483647",
+                "SYS.CACHE_GROUP_PAGE_LISTS.BUCKET_NUMBER.null.10",
+                "SYS.CACHE_GROUP_PAGE_LISTS.BUCKET_SIZE.null.19",
+                "SYS.CACHE_GROUP_PAGE_LISTS.STRIPES_COUNT.null.10",
+                "SYS.CACHE_GROUP_PAGE_LISTS.CACHED_PAGES_COUNT.null.10",
+                "SYS.DATA_REGION_PAGE_LISTS.NAME.null.2147483647",
+                "SYS.DATA_REGION_PAGE_LISTS.BUCKET_NUMBER.null.10",
+                "SYS.DATA_REGION_PAGE_LISTS.BUCKET_SIZE.null.19",
+                "SYS.DATA_REGION_PAGE_LISTS.STRIPES_COUNT.null.10",
+                "SYS.DATA_REGION_PAGE_LISTS.CACHED_PAGES_COUNT.null.10"
             ));
 
             Assert.assertEquals(expectedCols, actualSystemCols);
diff --git a/modules/codegen/src/main/java/org/apache/ignite/codegen/SystemViewRowAttributeWalkerGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/codegen/SystemViewRowAttributeWalkerGenerator.java
index 1fa96c6..300084b 100644
--- a/modules/codegen/src/main/java/org/apache/ignite/codegen/SystemViewRowAttributeWalkerGenerator.java
+++ b/modules/codegen/src/main/java/org/apache/ignite/codegen/SystemViewRowAttributeWalkerGenerator.java
@@ -32,8 +32,12 @@ import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.ObjIntConsumer;
+import org.apache.ignite.internal.managers.systemview.walker.Filtrable;
 import org.apache.ignite.internal.managers.systemview.walker.Order;
+import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.spi.systemview.SystemViewLocal;
+import org.apache.ignite.spi.systemview.view.CachePagesListView;
+import org.apache.ignite.spi.systemview.view.PagesListView;
 import org.apache.ignite.spi.systemview.jmx.SystemViewMBean;
 import org.apache.ignite.spi.systemview.view.CacheGroupView;
 import org.apache.ignite.spi.systemview.view.CacheView;
@@ -96,6 +100,8 @@ public class SystemViewRowAttributeWalkerGenerator {
         gen.generateAndWrite(SqlQueryView.class, DFLT_SRC_DIR);
         gen.generateAndWrite(SqlQueryHistoryView.class, DFLT_SRC_DIR);
         gen.generateAndWrite(StripedExecutorTaskView.class, DFLT_SRC_DIR);
+        gen.generateAndWrite(PagesListView.class, DFLT_SRC_DIR);
+        gen.generateAndWrite(CachePagesListView.class, DFLT_SRC_DIR);
 
         gen.generateAndWrite(SqlSchemaView.class, INDEXING_SRC_DIR);
         gen.generateAndWrite(SqlTableView.class, INDEXING_SRC_DIR);
@@ -155,6 +161,38 @@ public class SystemViewRowAttributeWalkerGenerator {
         code.add(" * @see " + simpleName);
         code.add(" */");
         code.add("public class " + simpleName + "Walker implements SystemViewRowAttributeWalker<" + simpleName + "> {");
+
+        List<String> filtrableAttrs = new ArrayList<>();
+
+        forEachMethod(clazz, (m, i) -> {
+            if (m.getAnnotation(Filtrable.class) != null) {
+                code.add(TAB + "/** Filter key for attribute \"" + m.getName() + "\" */");
+                code.add(TAB + "public static final String " + m.getName()
+                    .replaceAll("(\\p{Upper})", "_$1")
+                    .toUpperCase() + "_FILTER = \"" + m.getName() + "\";");
+                code.add("");
+
+                filtrableAttrs.add(m.getName());
+            }
+        });
+
+        if (!filtrableAttrs.isEmpty()) {
+            addImport(imports, F.class);
+            addImport(imports, List.class);
+            addImport(imports, Collections.class);
+
+            code.add(TAB + "/** List of filtrable attributes. */");
+            code.add(TAB + "private static final List<String> FILTRABLE_ATTRS = Collections.unmodifiableList(F.asList(");
+            code.add(TAB + TAB + '\"' + String.join("\", \"", filtrableAttrs) + '\"');
+            code.add(TAB + "));");
+            code.add("");
+            code.add(TAB + "/** {@inheritDoc} */");
+            code.add(TAB + "@Override public List<String> filtrableAttributes() {");
+            code.add(TAB + TAB + "return FILTRABLE_ATTRS;");
+            code.add(TAB + "}");
+            code.add("");
+        }
+
         code.add(TAB + "/** {@inheritDoc} */");
         code.add(TAB + "@Override public void visitAll(AttributeVisitor v) {");
 
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewAdapter.java
similarity index 52%
copy from modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java
copy to modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewAdapter.java
index 1839302..38e5072 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewAdapter.java
@@ -17,65 +17,58 @@
 
 package org.apache.ignite.internal.managers.systemview;
 
-import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
-import java.util.function.BiFunction;
+import java.util.Map;
 import java.util.function.Function;
 import org.apache.ignite.internal.util.typedef.F;
-import org.apache.ignite.spi.systemview.view.SystemView;
+import org.apache.ignite.internal.util.typedef.internal.A;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
 import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker;
 import org.jetbrains.annotations.NotNull;
 
 /**
- * System view backed by {@code data} container.
- * Each instance of {@code containers} collections should provide a collection of data.
- *
- * @see SystemView
+ * System view which supports attribute filtering.
  */
-public class SystemViewInnerCollectionsAdapter<C, R, D> extends AbstractSystemView<R> {
-    /** Collections of the data containers. */
-    private final Collection<C> containers;
-
-    /** Function to extract collection of the data from container. */
-    private final Function<C, Collection<D>> dataExtractor;
+public class FiltrableSystemViewAdapter<R, D> extends AbstractSystemView<R> implements FiltrableSystemView<R> {
+    /** Data supplier for the view. */
+    private Function<Map<String, Object>, Iterable<D>> dataSupplier;
 
     /** Row function. */
-    private final BiFunction<C, D, R> rowFunc;
+    private final Function<D, R> rowFunc;
 
     /**
      * @param name Name.
      * @param desc Description.
      * @param walker Walker.
-     * @param containers Container of data.
-     * @param dataExtractor Data extractor function.
+     * @param dataSupplier Data supplier.
      * @param rowFunc Row function.
      */
-    public SystemViewInnerCollectionsAdapter(String name, String desc,
-        SystemViewRowAttributeWalker<R> walker,
-        Collection<C> containers,
-        Function<C, Collection<D>> dataExtractor,
-        BiFunction<C, D, R> rowFunc) {
+    public FiltrableSystemViewAdapter(String name, String desc, SystemViewRowAttributeWalker<R> walker,
+        Function<Map<String, Object>, Iterable<D>> dataSupplier, Function<D, R> rowFunc) {
         super(name, desc, walker);
 
-        this.containers = containers;
-        this.dataExtractor = dataExtractor;
+        A.notNull(dataSupplier, "dataSupplier");
+
+        this.dataSupplier = dataSupplier;
         this.rowFunc = rowFunc;
     }
 
     /** {@inheritDoc} */
-    @Override public int size() {
-        int sz = 0;
-
-        for (C c : containers)
-            sz += dataExtractor.apply(c).size();
+    @NotNull @Override public Iterator<R> iterator(Map<String, Object> filter) {
+        if (filter == null)
+            filter = Collections.emptyMap();
 
-        return sz;
+        return F.iterator(dataSupplier.apply(filter), rowFunc::apply, true);
     }
 
     /** {@inheritDoc} */
     @NotNull @Override public Iterator<R> iterator() {
-        return F.concat(F.iterator(containers,
-                c -> F.iterator(dataExtractor.apply(c).iterator(),
-                    d -> rowFunc.apply(c, d), true), true));
+        return iterator(Collections.emptyMap());
+    }
+
+    /** {@inheritDoc} */
+    @Override public int size() {
+        return F.size(dataSupplier.apply(Collections.emptyMap()).iterator());
     }
 }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/GridSystemViewManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/GridSystemViewManager.java
index e244da6..f16f56b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/GridSystemViewManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/GridSystemViewManager.java
@@ -21,6 +21,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.BiFunction;
@@ -154,7 +155,7 @@ public class GridSystemViewManager extends GridManagerAdapter<SystemViewExporter
      * @param <D> Collection data type.
      */
     public <C, R, D> void registerInnerCollectionView(String name, String desc, SystemViewRowAttributeWalker<R> walker,
-        Collection<C> container, Function<C, Collection<D>> dataExtractor, BiFunction<C, D, R> rowFunc) {
+        Iterable<C> container, Function<C, Collection<D>> dataExtractor, BiFunction<C, D, R> rowFunc) {
         registerView0(name, new SystemViewInnerCollectionsAdapter<>(name,
             desc,
             walker,
@@ -207,15 +208,33 @@ public class GridSystemViewManager extends GridManagerAdapter<SystemViewExporter
     }
 
     /**
+     * Registers {@link FiltrableSystemViewAdapter} view with content filtering capabilities.
+     *
+     * @param name Name.
+     * @param desc Description.
+     * @param walker Row walker.
+     * @param dataSupplier Data supplier with content filtering capabilities.
+     * @param rowFunc Row function
+     * @param <R> View row type.
+     * @param <D> Collection data type.
+     */
+    public <R, D> void registerFiltrableView(String name, String desc, SystemViewRowAttributeWalker<R> walker,
+        Function<Map<String, Object>, Iterable<D>> dataSupplier, Function<D, R> rowFunc) {
+        registerView0(name, new FiltrableSystemViewAdapter<>(name,
+            desc,
+            walker,
+            dataSupplier,
+            rowFunc));
+    }
+
+    /**
      * Registers view.
      *
      * @param name Name.
      * @param sysView System view.
      */
     private void registerView0(String name, SystemView sysView) {
-        SystemView<?> old = systemViews.putIfAbsent(name, sysView);
-
-        assert old == null;
+        systemViews.put(name, sysView);
 
         notifyListeners(sysView, viewCreationLsnrs, log);
     }
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java
index 1839302..326a1d0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewInnerCollectionsAdapter.java
@@ -33,8 +33,8 @@ import org.jetbrains.annotations.NotNull;
  * @see SystemView
  */
 public class SystemViewInnerCollectionsAdapter<C, R, D> extends AbstractSystemView<R> {
-    /** Collections of the data containers. */
-    private final Collection<C> containers;
+    /** Iterable of the data containers. */
+    private final Iterable<C> containers;
 
     /** Function to extract collection of the data from container. */
     private final Function<C, Collection<D>> dataExtractor;
@@ -52,7 +52,7 @@ public class SystemViewInnerCollectionsAdapter<C, R, D> extends AbstractSystemVi
      */
     public SystemViewInnerCollectionsAdapter(String name, String desc,
         SystemViewRowAttributeWalker<R> walker,
-        Collection<C> containers,
+        Iterable<C> containers,
         Function<C, Collection<D>> dataExtractor,
         BiFunction<C, D, R> rowFunc) {
         super(name, desc, walker);
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CachePagesListViewWalker.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CachePagesListViewWalker.java
new file mode 100644
index 0000000..1a795ad
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/CachePagesListViewWalker.java
@@ -0,0 +1,78 @@
+/*
+ * 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.managers.systemview.walker;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.spi.systemview.view.CachePagesListView;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker;
+
+/**
+ * Generated by {@code org.apache.ignite.codegen.SystemViewRowAttributeWalkerGenerator}.
+ * {@link CachePagesListView} attributes walker.
+ * 
+ * @see CachePagesListView
+ */
+public class CachePagesListViewWalker implements SystemViewRowAttributeWalker<CachePagesListView> {
+    /** Filter key for attribute "cacheGroupId" */
+    public static final String CACHE_GROUP_ID_FILTER = "cacheGroupId";
+
+    /** Filter key for attribute "partitionId" */
+    public static final String PARTITION_ID_FILTER = "partitionId";
+
+    /** Filter key for attribute "bucketNumber" */
+    public static final String BUCKET_NUMBER_FILTER = "bucketNumber";
+
+    /** List of filtrable attributes. */
+    private static final List<String> FILTRABLE_ATTRS = Collections.unmodifiableList(F.asList(
+        "cacheGroupId", "partitionId", "bucketNumber"
+    ));
+
+    /** {@inheritDoc} */
+    @Override public List<String> filtrableAttributes() {
+        return FILTRABLE_ATTRS;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void visitAll(AttributeVisitor v) {
+        v.accept(0, "cacheGroupId", int.class);
+        v.accept(1, "partitionId", int.class);
+        v.accept(2, "name", String.class);
+        v.accept(3, "bucketNumber", int.class);
+        v.accept(4, "bucketSize", long.class);
+        v.accept(5, "stripesCount", int.class);
+        v.accept(6, "cachedPagesCount", int.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void visitAll(CachePagesListView row, AttributeWithValueVisitor v) {
+        v.acceptInt(0, "cacheGroupId", row.cacheGroupId());
+        v.acceptInt(1, "partitionId", row.partitionId());
+        v.accept(2, "name", String.class, row.name());
+        v.acceptInt(3, "bucketNumber", row.bucketNumber());
+        v.acceptLong(4, "bucketSize", row.bucketSize());
+        v.acceptInt(5, "stripesCount", row.stripesCount());
+        v.acceptInt(6, "cachedPagesCount", row.cachedPagesCount());
+    }
+
+    /** {@inheritDoc} */
+    @Override public int count() {
+        return 7;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/Filtrable.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/Filtrable.java
new file mode 100644
index 0000000..4093996
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/Filtrable.java
@@ -0,0 +1,35 @@
+/*
+ * 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.managers.systemview.walker;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker;
+
+/**
+ * Annotation to mark view row attribute for a {@link SystemViewRowAttributeWalker} as filtrable.
+ *
+ * @see SystemViewRowAttributeWalker
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface Filtrable {
+    // No-op.
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/PagesListViewWalker.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/PagesListViewWalker.java
new file mode 100644
index 0000000..0e42517
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/systemview/walker/PagesListViewWalker.java
@@ -0,0 +1,68 @@
+/*
+ * 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.managers.systemview.walker;
+
+import java.util.Collections;
+import java.util.List;
+import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.spi.systemview.view.PagesListView;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker;
+
+/**
+ * Generated by {@code org.apache.ignite.codegen.SystemViewRowAttributeWalkerGenerator}.
+ * {@link PagesListView} attributes walker.
+ * 
+ * @see PagesListView
+ */
+public class PagesListViewWalker implements SystemViewRowAttributeWalker<PagesListView> {
+    /** Filter key for attribute "bucketNumber" */
+    public static final String BUCKET_NUMBER_FILTER = "bucketNumber";
+
+    /** List of filtrable attributes. */
+    private static final List<String> FILTRABLE_ATTRS = Collections.unmodifiableList(F.asList(
+        "bucketNumber"
+    ));
+
+    /** {@inheritDoc} */
+    @Override public List<String> filtrableAttributes() {
+        return FILTRABLE_ATTRS;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void visitAll(AttributeVisitor v) {
+        v.accept(0, "name", String.class);
+        v.accept(1, "bucketNumber", int.class);
+        v.accept(2, "bucketSize", long.class);
+        v.accept(3, "stripesCount", int.class);
+        v.accept(4, "cachedPagesCount", int.class);
+    }
+
+    /** {@inheritDoc} */
+    @Override public void visitAll(PagesListView row, AttributeWithValueVisitor v) {
+        v.accept(0, "name", String.class, row.name());
+        v.acceptInt(1, "bucketNumber", row.bucketNumber());
+        v.acceptLong(2, "bucketSize", row.bucketSize());
+        v.acceptInt(3, "stripesCount", row.stripesCount());
+        v.acceptInt(4, "cachedPagesCount", row.cachedPagesCount());
+    }
+
+    /** {@inheritDoc} */
+    @Override public int count() {
+        return 5;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 5cf1122..13663ac 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -35,8 +35,10 @@ import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 import java.util.stream.Stream;
 import javax.management.MBeanServer;
 import org.apache.ignite.IgniteCheckedException;
@@ -74,6 +76,7 @@ import org.apache.ignite.internal.cluster.DetachedClusterNode;
 import org.apache.ignite.internal.managers.communication.GridIoPolicy;
 import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage;
 import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpi;
+import org.apache.ignite.internal.managers.systemview.walker.CachePagesListViewWalker;
 import org.apache.ignite.internal.pagemem.store.IgnitePageStoreManager;
 import org.apache.ignite.internal.pagemem.wal.IgniteWriteAheadLogManager;
 import org.apache.ignite.internal.processors.GridProcessorAdapter;
@@ -101,9 +104,12 @@ import org.apache.ignite.internal.processors.cache.persistence.DataRegion;
 import org.apache.ignite.internal.processors.cache.persistence.DatabaseLifecycleListener;
 import org.apache.ignite.internal.processors.cache.persistence.DbCheckpointListener;
 import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheOffheapManager;
 import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.cache.persistence.RowStore;
 import org.apache.ignite.internal.processors.cache.persistence.file.FilePageStoreManager;
 import org.apache.ignite.internal.processors.cache.persistence.freelist.FreeList;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.PagesList;
 import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetaStorage;
 import org.apache.ignite.internal.processors.cache.persistence.metastorage.MetastorageLifecycleListener;
 import org.apache.ignite.internal.processors.cache.persistence.metastorage.ReadOnlyMetastorage;
@@ -171,6 +177,7 @@ import org.apache.ignite.spi.IgniteNodeValidationResult;
 import org.apache.ignite.spi.discovery.DiscoveryDataBag;
 import org.apache.ignite.spi.discovery.DiscoveryDataBag.GridDiscoveryData;
 import org.apache.ignite.spi.discovery.DiscoveryDataBag.JoiningNodeDiscoveryData;
+import org.apache.ignite.spi.systemview.view.CachePagesListView;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -200,20 +207,18 @@ import static org.apache.ignite.internal.util.IgniteUtils.doInParallel;
  */
 @SuppressWarnings({"unchecked", "TypeMayBeWeakened", "deprecation"})
 public class GridCacheProcessor extends GridProcessorAdapter {
-    /** Invalid region configuration message. */
-    private static final String INVALID_REGION_CONFIGURATION_MESSAGE = "Failed to join node " +
-        "(Incompatible data region configuration [region=%s, locNodeId=%s, isPersistenceEnabled=%s, rmtNodeId=%s, isPersistenceEnabled=%s])";
-
-    /** Template of message of failed node join because encryption settings are different for the same cache. */
-    private static final String ENCRYPT_MISMATCH_MESSAGE = "Failed to join node to the cluster " +
-        "(encryption settings are different for cache '%s' : local=%s, remote=%s.)";
-
     /** */
     private static final String CACHE_NAME_AND_OPERATION_FORMAT = "[cacheName=%s, operation=%s]";
 
     /** */
     private static final String CACHE_NAMES_AND_OPERATION_FORMAT = "[cacheNames=%s, operation=%s]";
 
+    /** System view name for page lists. */
+    public static final String CACHE_GRP_PAGE_LIST_VIEW = "cacheGroupPageLists";
+
+    /** System view description for page lists. */
+    public static final String CACHE_GRP_PAGE_LIST_VIEW_DESC = "Cache group page lists";
+
     /** Enables start caches in parallel. */
     private final boolean IGNITE_ALLOW_START_CACHES_IN_PARALLEL =
         IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_ALLOW_START_CACHES_IN_PARALLEL, true);
@@ -594,8 +599,15 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
         ctx.state().cacheProcessorStarted();
         ctx.authentication().cacheProcessorStarted();
-    }
 
+        ctx.systemView().registerFiltrableView(
+            CACHE_GRP_PAGE_LIST_VIEW,
+            CACHE_GRP_PAGE_LIST_VIEW_DESC,
+            new CachePagesListViewWalker(),
+            this::pagesListViewSupplier,
+            Function.identity()
+        );
+    }
 
     /**
      * @param cfg Initializes cache configuration with proper defaults.
@@ -5323,6 +5335,53 @@ public class GridCacheProcessor extends GridProcessorAdapter {
     }
 
     /**
+     * Pages list view supplier.
+     *
+     * @param filter Filter.
+     */
+    private Iterable<CachePagesListView> pagesListViewSupplier(Map<String, Object> filter) {
+        Integer cacheGrpId = (Integer)filter.get(CachePagesListViewWalker.CACHE_GROUP_ID_FILTER);
+
+        Collection<CacheGroupContext> cacheGrps;
+
+        if (cacheGrpId != null) {
+            CacheGroupContext cacheGrp = this.cacheGrps.get(cacheGrpId);
+
+            if (cacheGrp == null)
+                return Collections.emptyList();
+
+            cacheGrps = Collections.singletonList(cacheGrp);
+        }
+        else
+            cacheGrps = this.cacheGrps.values();
+
+        Integer partId = (Integer)filter.get(CachePagesListViewWalker.PARTITION_ID_FILTER);
+        Integer bucketNum = (Integer)filter.get(CachePagesListViewWalker.BUCKET_NUMBER_FILTER);
+
+        Iterable<IgniteCacheOffheapManager.CacheDataStore> dataStores =
+            F.flat(F.iterator(cacheGrps, grp -> grp.offheap().cacheDataStores(), true));
+
+        return F.flat(F.iterator(dataStores, dataStore -> {
+            RowStore rowStore = dataStore.rowStore();
+
+            if (rowStore == null || !(dataStore instanceof GridCacheOffheapManager.GridCacheDataStore))
+                return Collections.emptySet();
+
+            PagesList pagesList = (PagesList)rowStore.freeList();
+
+            if (bucketNum != null) {
+                return bucketNum >= 0 && bucketNum < pagesList.bucketsCount() ?
+                    Collections.singleton(new CachePagesListView(pagesList, bucketNum, dataStore.partId())) :
+                    Collections.emptyList();
+            }
+
+            return IntStream.range(0, pagesList.bucketsCount())
+                .mapToObj(bucket -> new CachePagesListView(pagesList, bucket, dataStore.partId()))
+                .collect(Collectors.toList());
+        }, true, cacheDataStore -> partId == null || cacheDataStore.partId() == partId));
+    }
+
+    /**
      * Recovery lifecycle for caches.
      */
     private class CacheRecoveryLifecycle implements MetastorageLifecycleListener, DatabaseLifecycleListener {
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
index a1a7913..bb99e44 100644
--- 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
@@ -17,7 +17,6 @@
 
 package org.apache.ignite.internal.processors.cache.persistence;
 
-import javax.management.InstanceNotFoundException;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -27,6 +26,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.management.InstanceNotFoundException;
 import org.apache.ignite.DataRegionMetrics;
 import org.apache.ignite.DataRegionMetricsProvider;
 import org.apache.ignite.DataStorageMetrics;
@@ -42,6 +45,7 @@ import org.apache.ignite.failure.FailureType;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.IgniteInternalFuture;
 import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.managers.systemview.walker.PagesListViewWalker;
 import org.apache.ignite.internal.mem.DirectMemoryProvider;
 import org.apache.ignite.internal.mem.DirectMemoryRegion;
 import org.apache.ignite.internal.mem.IgniteOutOfMemoryException;
@@ -78,6 +82,7 @@ import org.apache.ignite.lang.IgniteBiTuple;
 import org.apache.ignite.lang.IgniteInClosure;
 import org.apache.ignite.lang.IgniteOutClosure;
 import org.apache.ignite.mxbean.DataRegionMetricsMXBean;
+import org.apache.ignite.spi.systemview.view.PagesListView;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_REUSE_MEMORY_ON_DEACTIVATE;
@@ -94,6 +99,12 @@ public class IgniteCacheDatabaseSharedManager extends GridCacheSharedManagerAdap
     /** DataRegionConfiguration name reserved for internal caches. */
     public static final String SYSTEM_DATA_REGION_NAME = "sysMemPlc";
 
+    /** System view name for page lists. */
+    public static final String DATA_REGION_PAGE_LIST_VIEW = "dataRegionPageLists";
+
+    /** System view description for page lists. */
+    public static final String DATA_REGION_PAGE_LIST_VIEW_DESC = "Data region page lists";
+
     /** Minimum size of memory chunk */
     private static final long MIN_PAGE_MEMORY_SIZE = 10L * 1024 * 1024;
 
@@ -151,6 +162,22 @@ public class IgniteCacheDatabaseSharedManager extends GridCacheSharedManagerAdap
         pageSize = memCfg.getPageSize();
 
         initDataRegions(memCfg);
+
+        cctx.kernalContext().systemView().registerView(
+            DATA_REGION_PAGE_LIST_VIEW,
+            DATA_REGION_PAGE_LIST_VIEW_DESC,
+            new PagesListViewWalker(),
+            () -> {
+                Map<String, CacheFreeList> freeLists = freeListMap;
+
+                if (freeLists == null)
+                    return Collections.emptyList();
+
+                return freeLists.values().stream().flatMap(fl -> IntStream.range(0, fl.bucketsCount()).mapToObj(
+                    bucket -> new PagesListView(fl, bucket))).collect(Collectors.toList());
+            },
+            Function.identity()
+        );
     }
 
     /**
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
index f90da40..fa6d0af 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/freelist/PagesList.java
@@ -1830,6 +1830,51 @@ public abstract class PagesList extends DataStructure {
     }
 
     /**
+     * Pages list name.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Buckets count.
+     */
+    public int bucketsCount() {
+        return buckets;
+    }
+
+    /**
+     * Bucket size.
+     *
+     * @param bucket Bucket.
+     */
+    public long bucketSize(int bucket) {
+        return bucketsSize[bucket].get();
+    }
+
+    /**
+     * Stripes count.
+     *
+     * @param bucket Bucket.
+     */
+    public int stripesCount(int bucket) {
+        Stripe[] stripes = getBucket(bucket);
+
+        return stripes == null ? 0 : stripes.length;
+    }
+
+    /**
+     * Cached pages count.
+     *
+     * @param bucket Bucket.
+     */
+    public int cachedPagesCount(int bucket) {
+        PagesCache pagesCache = getBucketCache(bucket, false);
+
+        return pagesCache == null ? 0 : pagesCache.size();
+    }
+
+    /**
      * Singleton reuse bag.
      */
     private static final class SingletonReuseBag implements ReuseBag {
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/metric/jmx/ReadOnlyDynamicMBean.java b/modules/core/src/main/java/org/apache/ignite/spi/metric/jmx/ReadOnlyDynamicMBean.java
index dc885a0..75da1e5 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/metric/jmx/ReadOnlyDynamicMBean.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/metric/jmx/ReadOnlyDynamicMBean.java
@@ -45,6 +45,8 @@ public abstract class ReadOnlyDynamicMBean implements DynamicMBean {
         try {
             if ("getAttribute".equals(actionName))
                 return getAttribute((String)params[0]);
+            else if ("invoke".equals(actionName))
+                return invoke((String)params[0], (Object[])params[1], (String[])params[2]);
         }
         catch (AttributeNotFoundException e) {
             throw new MBeanException(e);
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/jmx/SystemViewMBean.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/jmx/SystemViewMBean.java
index 6eaab1c..6f80bd7 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/systemview/jmx/SystemViewMBean.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/jmx/SystemViewMBean.java
@@ -20,28 +20,39 @@ package org.apache.ignite.spi.systemview.jmx;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.InetSocketAddress;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.UUID;
+import javax.management.MBeanException;
 import javax.management.MBeanInfo;
+import javax.management.MBeanOperationInfo;
 import javax.management.ObjectName;
+import javax.management.ReflectionException;
 import javax.management.openmbean.CompositeDataSupport;
 import javax.management.openmbean.CompositeType;
 import javax.management.openmbean.OpenDataException;
 import javax.management.openmbean.OpenMBeanAttributeInfo;
 import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
 import javax.management.openmbean.OpenMBeanInfoSupport;
+import javax.management.openmbean.OpenMBeanOperationInfo;
+import javax.management.openmbean.OpenMBeanOperationInfoSupport;
+import javax.management.openmbean.OpenMBeanParameterInfo;
+import javax.management.openmbean.OpenMBeanParameterInfoSupport;
 import javax.management.openmbean.OpenType;
 import javax.management.openmbean.SimpleType;
 import javax.management.openmbean.TabularDataSupport;
 import javax.management.openmbean.TabularType;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.spi.metric.jmx.JmxMetricExporterSpi;
 import org.apache.ignite.spi.metric.jmx.ReadOnlyDynamicMBean;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
 import org.apache.ignite.spi.systemview.view.SystemView;
-import org.apache.ignite.lang.IgniteUuid;
 import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeVisitor;
 import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeWithValueVisitor;
 
@@ -55,6 +66,9 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
     /** View attribute. */
     public static final String VIEWS = "views";
 
+    /** Filter operation name. */
+    public static final String FILTER_OPERATION = "filter";
+
     /** Row id attribute name. */
     public static final String ID = "systemViewRowId";
 
@@ -70,6 +84,9 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
     /** System view type. */
     private final TabularType sysViewType;
 
+    /** Filter field names. */
+    private final String[] filterFields;
+
     /**
      * @param sysView System view to export.
      */
@@ -81,6 +98,8 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
         String[] fields = new String[cnt+1];
         OpenType[] types = new OpenType[cnt+1];
 
+        List<Integer> filterFieldIdxs = new ArrayList<>(cnt);
+
         sysView.walker().visitAll(new AttributeVisitor() {
             @Override public <T> void accept(int idx, String name, Class<T> clazz) {
                 fields[idx] = name;
@@ -115,6 +134,9 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
                     types[idx] = SimpleType.DOUBLE;
                 else
                     types[idx] = SimpleType.STRING;
+
+                if (sysView.walker().filtrableAttributes().contains(name))
+                    filterFieldIdxs.add(idx);
             }
         });
 
@@ -128,6 +150,29 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
                 fields,
                 types);
 
+            OpenMBeanOperationInfo[] operations = null;
+
+            if (!filterFieldIdxs.isEmpty() && sysView instanceof FiltrableSystemView) {
+                OpenMBeanParameterInfo[] params = new OpenMBeanParameterInfo[filterFieldIdxs.size()];
+
+                filterFields = new String[filterFieldIdxs.size()];
+
+                for (int i = 0; i < filterFieldIdxs.size(); i++) {
+                    String fieldName = fields[filterFieldIdxs.get(i)];
+
+                    filterFields[i] = fieldName;
+
+                    params[i] = new OpenMBeanParameterInfoSupport(fieldName, fieldName, types[filterFieldIdxs.get(i)]);
+                }
+
+                OpenMBeanOperationInfo operation = new OpenMBeanOperationInfoSupport(FILTER_OPERATION,
+                    "Filter view content", params, rowType, MBeanOperationInfo.INFO);
+
+                operations = new OpenMBeanOperationInfo[] {operation};
+            }
+            else
+                filterFields = null;
+
             info = new OpenMBeanInfoSupport(
                 sysView.name(),
                 sysView.description(),
@@ -135,7 +180,7 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
                     new OpenMBeanAttributeInfoSupport(VIEWS, VIEWS, rowType, true, false, false)
                 },
                 null,
-                null,
+                operations,
                 null
             );
 
@@ -156,34 +201,30 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
         if ("MBeanInfo".equals(attribute))
             return getMBeanInfo();
 
-        if (attribute.equals(VIEWS)) {
-            TabularDataSupport rows = new TabularDataSupport(sysViewType);
+        if (attribute.equals(VIEWS))
+            return viewContent(null);
 
-            AttributeToMapVisitor visitor = new AttributeToMapVisitor();
-
-            try {
-                int idx = 0;
-
-                for (R row : sysView) {
-                    Map<String, Object> data = new HashMap<>();
-
-                    visitor.data(data);
+        throw new IllegalArgumentException("Unknown attribute " + attribute);
+    }
 
-                    sysView.walker().visitAll(row, visitor);
+    /** {@inheritDoc} */
+    @Override public Object invoke(String actName, Object[] params,
+        String[] signature) throws MBeanException, ReflectionException {
+        if (FILTER_OPERATION.equals(actName)) {
+            assert filterFields != null;
+            assert filterFields.length >= params.length;
 
-                    data.put(ID, idx++);
+            Map<String, Object> filter = U.newHashMap(params.length);
 
-                    rows.put(new CompositeDataSupport(rowType, data));
-                }
-            }
-            catch (OpenDataException e) {
-                throw new IgniteException(e);
+            for (int i = 0; i < params.length; i++) {
+                if (params[i] != null)
+                    filter.put(filterFields[i], params[i]);
             }
 
-            return rows;
+            return viewContent(filter);
         }
 
-        throw new IllegalArgumentException("Unknown attribute " + attribute);
+        return super.invoke(actName, params, signature);
     }
 
     /** {@inheritDoc} */
@@ -191,6 +232,39 @@ public class SystemViewMBean<R> extends ReadOnlyDynamicMBean {
         return info;
     }
 
+    /**
+     * Gets tabular data with system view content.
+     */
+    private TabularDataSupport viewContent(Map<String, Object> filter) {
+        TabularDataSupport rows = new TabularDataSupport(sysViewType);
+
+        AttributeToMapVisitor visitor = new AttributeToMapVisitor();
+
+        try {
+            int idx = 0;
+
+            Iterable<R> iter = filter != null && sysView instanceof FiltrableSystemView ?
+                () -> ((FiltrableSystemView<R>)sysView).iterator(filter) : sysView;
+
+            for (R row : iter) {
+                Map<String, Object> data = new HashMap<>();
+
+                visitor.data(data);
+
+                sysView.walker().visitAll(row, visitor);
+
+                data.put(ID, idx++);
+
+                rows.put(new CompositeDataSupport(rowType, data));
+            }
+        }
+        catch (OpenDataException e) {
+            throw new IgniteException(e);
+        }
+
+        return rows;
+    }
+
     /** Fullfill {@code data} Map for specific row. */
     private static class AttributeToMapVisitor implements AttributeWithValueVisitor {
         /** Map to store data. */
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CachePagesListView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CachePagesListView.java
new file mode 100644
index 0000000..4664442
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/CachePagesListView.java
@@ -0,0 +1,58 @@
+/*
+ * 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.spi.systemview.view;
+
+import org.apache.ignite.internal.managers.systemview.walker.Filtrable;
+import org.apache.ignite.internal.managers.systemview.walker.Order;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.PagesList;
+
+/**
+ * Pages-list representation for a {@link SystemView}.
+ */
+public class CachePagesListView extends PagesListView {
+    /** Partition id. */
+    private final int partId;
+
+    /**
+     * @param pagesList Pages list.
+     * @param bucket Bucket number.
+     */
+    public CachePagesListView(PagesList pagesList, int bucket, int partId) {
+        super(pagesList, bucket);
+
+        this.partId = partId;
+    }
+
+    /**
+     * @return Cache group id.
+     */
+    @Order
+    @Filtrable
+    public int cacheGroupId() {
+        return pagesList.groupId();
+    }
+
+    /**
+     * @return Partition id.
+     */
+    @Order(1)
+    @Filtrable
+    public int partitionId() {
+        return partId;
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/FiltrableSystemView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/FiltrableSystemView.java
new file mode 100644
index 0000000..2db8c67
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/FiltrableSystemView.java
@@ -0,0 +1,34 @@
+/*
+ * 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.spi.systemview.view;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * System view with filtering capabilities.
+ *
+ * @param <R> Type of the row.
+ */
+public interface FiltrableSystemView<R> extends SystemView<R> {
+    /**
+     * @param filter Filter for a view ({@code null} or empty filter means no filtering).
+     * @return Iterator for filtered system view content.
+     */
+    public Iterator<R> iterator(Map<String, Object> filter);
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/PagesListView.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/PagesListView.java
new file mode 100644
index 0000000..1e9274c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/PagesListView.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.spi.systemview.view;
+
+import org.apache.ignite.internal.managers.systemview.walker.Filtrable;
+import org.apache.ignite.internal.managers.systemview.walker.Order;
+import org.apache.ignite.internal.processors.cache.persistence.freelist.PagesList;
+
+/**
+ * Pages-list representation for a {@link SystemView}.
+ */
+public class PagesListView {
+    /** Pages list. */
+    PagesList pagesList;
+
+    /** Bucket number. */
+    int bucket;
+
+    /**
+     * @param pagesList Pages list.
+     * @param bucket Bucket number.
+     */
+    public PagesListView(PagesList pagesList, int bucket) {
+        this.pagesList = pagesList;
+        this.bucket = bucket;
+    }
+
+    /**
+     * @return Pages-list name.
+     */
+    @Order(2)
+    public String name() {
+        return pagesList.name();
+    }
+
+    /**
+     * @return Bucket number.
+     * */
+    @Order(3)
+    @Filtrable
+    public int bucketNumber() {
+        return bucket;
+    }
+
+    /**
+     * @return Bucket size.
+     */
+    @Order(4)
+    public long bucketSize() {
+        return pagesList.bucketSize(bucket);
+    }
+
+    /**
+     * @return Bucket stripes count.
+     */
+    @Order(5)
+    public int stripesCount() {
+        return pagesList.stripesCount(bucket);
+    }
+
+    /**
+     * @return Count of pages cached onheap.
+     */
+    @Order(6)
+    public int cachedPagesCount() {
+        return pagesList.cachedPagesCount(bucket);
+    }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/SystemViewRowAttributeWalker.java b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/SystemViewRowAttributeWalker.java
index 0c26997..a902442 100644
--- a/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/SystemViewRowAttributeWalker.java
+++ b/modules/core/src/main/java/org/apache/ignite/spi/systemview/view/SystemViewRowAttributeWalker.java
@@ -17,6 +17,9 @@
 
 package org.apache.ignite.spi.systemview.view;
 
+import java.util.Collections;
+import java.util.List;
+
 /**
  * Utility class for quick iteration over row properties.
  */
@@ -40,6 +43,13 @@ public interface SystemViewRowAttributeWalker<R> {
      */
     public void visitAll(R row, AttributeWithValueVisitor visitor);
 
+    /**
+     * @return List of filtrable attributes for this system view.
+     */
+    public default List<String> filtrableAttributes() {
+        return Collections.emptyList();
+    }
+
     /** Attribute visitor. */
     public interface AttributeVisitor {
         /**
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java b/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
index f9222fa..8d26e58 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/metric/JmxExporterSpiTest.java
@@ -36,6 +36,8 @@ import java.util.function.Consumer;
 import javax.management.DynamicMBean;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanFeatureInfo;
+import javax.management.MBeanOperationInfo;
+import javax.management.MBeanParameterInfo;
 import javax.management.MBeanServer;
 import javax.management.MBeanServerInvocationHandler;
 import javax.management.MalformedObjectNameException;
@@ -48,6 +50,7 @@ import org.apache.ignite.IgniteJdbcThinDriver;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cache.query.ContinuousQuery;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
@@ -59,6 +62,7 @@ import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.client.thin.ProtocolVersion;
+import org.apache.ignite.internal.managers.systemview.walker.CachePagesListViewWalker;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestPredicate;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestRunnable;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestTransformer;
@@ -85,6 +89,7 @@ import static org.apache.ignite.internal.metric.SystemViewSelfTest.TEST_TRANSFOR
 import static org.apache.ignite.internal.processors.cache.CacheMetricsImpl.CACHE_METRICS;
 import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHES_VIEW;
 import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHE_GRPS_VIEW;
+import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CACHE_GRP_PAGE_LIST_VIEW;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheGroupId;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheId;
 import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST;
@@ -100,6 +105,7 @@ import static org.apache.ignite.internal.processors.service.IgniteServiceProcess
 import static org.apache.ignite.internal.processors.task.GridTaskProcessor.TASKS_VIEW;
 import static org.apache.ignite.internal.util.IgniteUtils.toStringSafe;
 import static org.apache.ignite.spi.metric.jmx.MetricRegistryMBean.searchHistogram;
+import static org.apache.ignite.spi.systemview.jmx.SystemViewMBean.FILTER_OPERATION;
 import static org.apache.ignite.spi.systemview.jmx.SystemViewMBean.VIEWS;
 import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
 import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
@@ -464,6 +470,34 @@ public class JmxExporterSpiTest extends AbstractExporterSpiTest {
     }
 
     /** */
+    public TabularDataSupport filteredSystemView(IgniteEx g, String name, Map<String, Object> filter) {
+        try {
+            DynamicMBean mbean = mbean(g, VIEWS, name);
+
+            MBeanOperationInfo[] opers = mbean.getMBeanInfo().getOperations();
+
+            assertEquals(1, opers.length);
+
+            assertEquals(FILTER_OPERATION, opers[0].getName());
+
+            MBeanParameterInfo[] paramInfo = opers[0].getSignature();
+
+            Object params[] = new Object[paramInfo.length];
+            String signature[] = new String[paramInfo.length];
+
+            for (int i = 0; i < paramInfo.length; i++) {
+                params[i] = filter.get(paramInfo[i].getName());
+                signature[i] = paramInfo[i].getType();
+            }
+
+            return (TabularDataSupport)mbean.invoke(FILTER_OPERATION, params, signature);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /** */
     public DynamicMBean mbean(IgniteEx g, String grp, String name) throws MalformedObjectNameException {
         ObjectName mbeanName = U.makeMBeanName(g.name(), grp, name);
 
@@ -857,6 +891,34 @@ public class JmxExporterSpiTest extends AbstractExporterSpiTest {
     }
 
     /** */
+    @Test
+    public void testPagesList() throws Exception {
+        String cacheName = "cacheFL";
+
+        IgniteCache<Integer, Integer> cache = ignite.getOrCreateCache(new CacheConfiguration<Integer, Integer>()
+            .setName(cacheName).setAffinity(new RendezvousAffinityFunction().setPartitions(2)));
+
+        // Put some data to cache to init cache partitions.
+        for (int i = 0; i < 10; i++)
+            cache.put(i, i);
+
+        TabularDataSupport view = filteredSystemView(ignite, CACHE_GRP_PAGE_LIST_VIEW, U.map(
+            CachePagesListViewWalker.CACHE_GROUP_ID_FILTER, cacheId(cacheName),
+            CachePagesListViewWalker.PARTITION_ID_FILTER, 0,
+            CachePagesListViewWalker.BUCKET_NUMBER_FILTER, 0
+        ));
+
+        assertEquals(1, view.size());
+
+        view = filteredSystemView(ignite, CACHE_GRP_PAGE_LIST_VIEW, U.map(
+            CachePagesListViewWalker.CACHE_GROUP_ID_FILTER, cacheId(cacheName),
+            CachePagesListViewWalker.BUCKET_NUMBER_FILTER, 0
+        ));
+
+        assertEquals(2, view.size());
+    }
+
+    /** */
     private void createTestHistogram(MetricRegistry mreg) {
         long[] bounds = new long[] {50, 500};
 
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
index 22bf15a..283e447 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/metric/SystemViewSelfTest.java
@@ -41,6 +41,7 @@ import org.apache.ignite.IgniteJdbcThinDriver;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cache.query.ContinuousQuery;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
@@ -52,13 +53,20 @@ import org.apache.ignite.compute.ComputeJobResultPolicy;
 import org.apache.ignite.compute.ComputeTask;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
 import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.internal.IgniteEx;
 import org.apache.ignite.internal.client.thin.ProtocolVersion;
+import org.apache.ignite.internal.managers.systemview.walker.CachePagesListViewWalker;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
+import org.apache.ignite.spi.systemview.view.CachePagesListView;
+import org.apache.ignite.spi.systemview.view.PagesListView;
 import org.apache.ignite.internal.processors.odbc.jdbc.JdbcConnectionContext;
 import org.apache.ignite.internal.processors.service.DummyService;
 import org.apache.ignite.internal.util.StripedExecutor;
 import org.apache.ignite.internal.util.typedef.F;
+import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiPredicate;
 import org.apache.ignite.lang.IgniteCallable;
 import org.apache.ignite.lang.IgniteClosure;
@@ -71,6 +79,7 @@ import org.apache.ignite.spi.systemview.view.ClientConnectionView;
 import org.apache.ignite.spi.systemview.view.ClusterNodeView;
 import org.apache.ignite.spi.systemview.view.ComputeTaskView;
 import org.apache.ignite.spi.systemview.view.ContinuousQueryView;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
 import org.apache.ignite.spi.systemview.view.ScanQueryView;
 import org.apache.ignite.spi.systemview.view.ServiceView;
 import org.apache.ignite.spi.systemview.view.StripedExecutorTaskView;
@@ -89,8 +98,10 @@ import static org.apache.ignite.internal.managers.systemview.GridSystemViewManag
 import static org.apache.ignite.internal.managers.systemview.ScanQuerySystemView.SCAN_QRY_SYS_VIEW;
 import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHES_VIEW;
 import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHE_GRPS_VIEW;
+import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CACHE_GRP_PAGE_LIST_VIEW;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheGroupId;
 import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheId;
+import static org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager.DATA_REGION_PAGE_LIST_VIEW;
 import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST;
 import static org.apache.ignite.internal.processors.continuous.GridContinuousProcessor.CQ_SYS_VIEW;
 import static org.apache.ignite.internal.processors.odbc.ClientListenerProcessor.CLI_CONN_VIEW;
@@ -983,6 +994,95 @@ public class SystemViewSelfTest extends GridCommonAbstractTest {
         }
     }
 
+    /** */
+    @Test
+    public void testPagesList() throws Exception {
+        cleanPersistenceDir();
+
+        try (IgniteEx ignite = startGrid(getConfiguration()
+            .setDataStorageConfiguration(
+                new DataStorageConfiguration().setDataRegionConfigurations(
+                    new DataRegionConfiguration().setName("dr0").setMaxSize(100L * 1024 * 1024),
+                    new DataRegionConfiguration().setName("dr1").setMaxSize(100L * 1024 * 1024)
+                        .setPersistenceEnabled(true)
+                )))) {
+            ignite.cluster().active(true);
+
+            GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ignite.context().cache().context()
+                .database();
+
+            int pageSize = dbMgr.pageSize();
+
+            dbMgr.enableCheckpoints(false).get();
+
+            for (int i = 0; i < 2; i++) {
+                IgniteCache<Object, Object> cache = ignite.getOrCreateCache(new CacheConfiguration<>("cache" + i)
+                    .setDataRegionName("dr" + i).setAffinity(new RendezvousAffinityFunction().setPartitions(2)));
+
+                int key = 0;
+
+                // Fill up different free-list buckets.
+                for (int j = 0; j < pageSize / 2; j++)
+                    cache.put(key++, new byte[j + 1]);
+
+                // Put some pages to one bucket to overflow pages cache.
+                for (int j = 0; j < 1000; j++)
+                    cache.put(key++, new byte[pageSize / 2]);
+            }
+
+            long dr0flPages = 0;
+            int dr0flStripes = 0;
+
+            SystemView<PagesListView> dataRegionPageLists = ignite.context().systemView().view(DATA_REGION_PAGE_LIST_VIEW);
+
+            for (PagesListView pagesListView : dataRegionPageLists) {
+                if (pagesListView.name().startsWith("dr0")) {
+                    dr0flPages += pagesListView.bucketSize();
+                    dr0flStripes += pagesListView.stripesCount();
+                }
+            }
+
+            assertTrue(dr0flPages > 0);
+            assertTrue(dr0flStripes > 0);
+
+            SystemView<CachePagesListView> cacheGrpPageLists = ignite.context().systemView().view(CACHE_GRP_PAGE_LIST_VIEW);
+
+            long dr1flPages = 0;
+            int dr1flStripes = 0;
+            int dr1flCached = 0;
+
+            for (CachePagesListView pagesListView : cacheGrpPageLists) {
+                if (pagesListView.cacheGroupId() == cacheId("cache1")) {
+                    dr1flPages += pagesListView.bucketSize();
+                    dr1flStripes += pagesListView.stripesCount();
+                    dr1flCached += pagesListView.cachedPagesCount();
+                }
+            }
+
+            assertTrue(dr1flPages > 0);
+            assertTrue(dr1flStripes > 0);
+            assertTrue(dr1flCached > 0);
+
+            // Test filtering.
+            assertTrue(cacheGrpPageLists instanceof FiltrableSystemView);
+
+            Iterator<CachePagesListView> iter = ((FiltrableSystemView<CachePagesListView>)cacheGrpPageLists).iterator(U.map(
+                CachePagesListViewWalker.CACHE_GROUP_ID_FILTER, cacheId("cache1"),
+                CachePagesListViewWalker.PARTITION_ID_FILTER, 0,
+                CachePagesListViewWalker.BUCKET_NUMBER_FILTER, 0
+            ));
+
+            assertEquals(1, F.size(iter));
+
+            iter = ((FiltrableSystemView<CachePagesListView>)cacheGrpPageLists).iterator(U.map(
+                CachePagesListViewWalker.CACHE_GROUP_ID_FILTER, cacheId("cache1"),
+                CachePagesListViewWalker.BUCKET_NUMBER_FILTER, 0
+            ));
+
+            assertEquals(2, F.size(iter));
+        }
+    }
+
     /** Test node filter. */
     public static class TestNodeFilter implements IgnitePredicate<ClusterNode> {
         /** {@inheritDoc} */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SqlSystemIndex.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SqlSystemIndex.java
index 1962342..753a1ab 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SqlSystemIndex.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SqlSystemIndex.java
@@ -19,9 +19,11 @@ package org.apache.ignite.internal.processors.query.h2.sys;
 
 import java.util.Iterator;
 import org.apache.ignite.internal.processors.query.h2.opt.GridH2Cursor;
+import org.h2.engine.Constants;
 import org.h2.engine.Session;
 import org.h2.index.BaseIndex;
 import org.h2.index.Cursor;
+import org.h2.index.IndexCondition;
 import org.h2.index.IndexType;
 import org.h2.message.DbException;
 import org.h2.result.Row;
@@ -82,14 +84,22 @@ public class SqlSystemIndex extends BaseIndex {
     /** {@inheritDoc} */
     @Override public double getCost(Session ses, int[] masks, TableFilter[] filters, int filter, SortOrder sortOrder,
         HashSet<Column> allColsSet) {
-        long rowCnt = getRowCountApproximation();
+        double colsCost = getRowCountApproximation();
 
-        double baseCost = getCostRangeIndex(masks, rowCnt, filters, filter, sortOrder, false, allColsSet);
+        if (masks != null) {
+            for (Column col : columns) {
+                // We can effictivly use only EQUALITY condition in system views.
+                if ((masks[col.getColumnId()] & IndexCondition.EQUALITY) != 0)
+                    colsCost /= 2;
+            }
+        }
+
+        double idxCost = Constants.COST_ROW_OFFSET + colsCost;
 
         if (((SystemViewH2Adapter)table).view.isDistributed())
-            baseCost = baseCost * DISTRIBUTED_MUL;
+            idxCost *= DISTRIBUTED_MUL;
 
-        return baseCost;
+        return idxCost;
     }
 
     /** {@inheritDoc} */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SystemViewH2Adapter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SystemViewH2Adapter.java
index 91e120b..12f36b8 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SystemViewH2Adapter.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/SystemViewH2Adapter.java
@@ -67,17 +67,19 @@ public class SystemViewH2Adapter extends TableBase {
         indexes = new ArrayList<>();
         indexes.add(scanIdx);
 
-        for (String index : view.getIndexes()) {
-            String[] indexedCols = index.split(",");
+        if (view.getIndexes() != null) {
+            for (String index : view.getIndexes()) {
+                String[] indexedCols = index.split(",");
 
-            Column[] cols = new Column[indexedCols.length];
+                Column[] cols = new Column[indexedCols.length];
 
-            for (int i = 0; i < indexedCols.length; i++)
-                cols[i] = getColumn(indexedCols[i]);
+                for (int i = 0; i < indexedCols.length; i++)
+                    cols[i] = getColumn(indexedCols[i]);
 
-            SqlSystemIndex idx = new SqlSystemIndex(this, cols);
+                SqlSystemIndex idx = new SqlSystemIndex(this, cols);
 
-            indexes.add(idx);
+                indexes.add(idx);
+            }
         }
     }
 
@@ -149,7 +151,7 @@ public class SystemViewH2Adapter extends TableBase {
 
     /** {@inheritDoc} */
     @Override public long getRowCountApproximation() {
-        return view.getRowCount();
+        return view.getRowCountApproximation();
     }
 
     /** {@inheritDoc} */
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
index ef1d329..6c3e14a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractLocalSystemView.java
@@ -51,7 +51,6 @@ public abstract class SqlAbstractLocalSystemView extends SqlAbstractSystemView {
 
         assert tblName != null;
         assert cols != null;
-        assert indexes != null;
     }
 
     /**
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractSystemView.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractSystemView.java
index 79d6225..1a5e1ca 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractSystemView.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlAbstractSystemView.java
@@ -105,6 +105,11 @@ public abstract class SqlAbstractSystemView implements SqlSystemView {
     }
 
     /** {@inheritDoc} */
+    @Override public long getRowCountApproximation() {
+        return getRowCount();
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean canGetRowCount() {
         return false;
     }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemView.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemView.java
index 93fdfa0..86d249c 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemView.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sys/view/SqlSystemView.java
@@ -62,6 +62,11 @@ public interface SqlSystemView {
     public long getRowCount();
 
     /**
+     * Gets approximated row count (required to build execution plan).
+     */
+    public long getRowCountApproximation();
+
+    /**
      * Check if the row count can be retrieved quickly.
      *
      * @return true if it can
diff --git a/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/FiltrableSystemViewLocal.java b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/FiltrableSystemViewLocal.java
new file mode 100644
index 0000000..a354e94
--- /dev/null
+++ b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/FiltrableSystemViewLocal.java
@@ -0,0 +1,98 @@
+/*
+ * 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.spi.systemview;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.GridKernalContext;
+import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.query.IgniteSQLException;
+import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewColumnCondition;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
+import org.apache.ignite.spi.systemview.view.SystemView;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeVisitor;
+import org.h2.result.SearchRow;
+
+/**
+ * Filtrable SQL system view to export {@link SystemView} data.
+ */
+public class FiltrableSystemViewLocal<R> extends SystemViewLocal<R> {
+    /** View attribute names. */
+    private final String[] attributeNames;
+
+    /** View attribute classes. */
+    private final Class<?>[] attributeClasses;
+
+    /**
+     * @param ctx Kernal context.
+     * @param sysView View to export.
+     */
+    public FiltrableSystemViewLocal(GridKernalContext ctx, SystemView<R> sysView) {
+        super(ctx, sysView, indexes(sysView));
+
+        assert sysView instanceof FiltrableSystemView;
+
+        attributeNames = new String[sysView.walker().count()];
+        attributeClasses = new Class<?>[sysView.walker().count()];
+
+        sysView.walker().visitAll(new AttributeVisitor() {
+            @Override public <T> void accept(int idx, String name, Class<T> clazz) {
+                attributeNames[idx] = name;
+                attributeClasses[idx] = U.box(clazz);
+            }
+        });
+    }
+
+    /** {@inheritDoc} */
+    @Override protected Iterator<R> viewIterator(SearchRow first, SearchRow last) {
+        Map<String, Object> filter = new HashMap<>();
+
+        for (int i = 0; i < cols.length; i++) {
+            SqlSystemViewColumnCondition cond = SqlSystemViewColumnCondition.forColumn(i, first, last);
+
+            if (cond.isEquality()) {
+                Object val = cond.valueForEquality().getObject();
+
+                if (attributeClasses[i].isInstance(val))
+                    filter.put(attributeNames[i], val);
+                else {
+                    throw new IgniteSQLException("Unexpected filter value type [column=" + cols[i] +
+                        ", actual=" + val.getClass().getSimpleName() +
+                        ", expected=" + attributeClasses[i].getSimpleName(),
+                        IgniteQueryErrorCode.CONVERSION_FAILED);
+                }
+            }
+        }
+
+        return ((FiltrableSystemView<R>)sysView).iterator(filter);
+    }
+
+    /**
+     * Extract indexes for specific {@link SystemView}.
+     *
+     * @param sysView System view.
+     * @return Indexes array for {@code sysView}.
+     */
+    private static String[] indexes(SystemView<?> sysView) {
+        return new String[] {sysView.walker().filtrableAttributes().stream().map(SystemViewLocal::sqlName)
+                .collect(Collectors.joining(","))};
+    }
+}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SqlViewExporterSpi.java b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SqlViewExporterSpi.java
index 301bd9f..c10a01a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SqlViewExporterSpi.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SqlViewExporterSpi.java
@@ -27,6 +27,7 @@ import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.spi.IgniteSpiAdapter;
 import org.apache.ignite.spi.IgniteSpiContext;
 import org.apache.ignite.spi.IgniteSpiException;
+import org.apache.ignite.spi.systemview.view.FiltrableSystemView;
 import org.apache.ignite.spi.systemview.view.SystemView;
 import org.jetbrains.annotations.Nullable;
 
@@ -77,7 +78,8 @@ public class SqlViewExporterSpi extends IgniteSpiAdapter implements SystemViewEx
 
         GridKernalContext ctx = ((IgniteEx)ignite()).context();
 
-        SystemViewLocal<?> view = new SystemViewLocal<>(ctx, sysView);
+        SystemViewLocal<?> view = sysView instanceof FiltrableSystemView ?
+            new FiltrableSystemViewLocal<>(ctx, sysView) : new SystemViewLocal<>(ctx, sysView);
 
         mgr.createSystemView(SCHEMA_SYS, view);
     }
diff --git a/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SystemViewLocal.java b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SystemViewLocal.java
index aba538d8..fa3c17a 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SystemViewLocal.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/spi/systemview/SystemViewLocal.java
@@ -26,9 +26,9 @@ import java.util.Objects;
 import java.util.UUID;
 import org.apache.ignite.internal.GridKernalContext;
 import org.apache.ignite.internal.processors.metric.impl.MetricUtils;
-import org.apache.ignite.spi.systemview.view.SystemView;
 import org.apache.ignite.internal.processors.query.h2.sys.view.SqlAbstractLocalSystemView;
 import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.spi.systemview.view.SystemView;
 import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeVisitor;
 import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeWithValueVisitor;
 import org.h2.engine.Session;
@@ -54,21 +54,37 @@ import org.h2.value.ValueUuid;
  */
 public class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
     /** System view for export. */
-    private final SystemView<R> sysView;
+    protected final SystemView<R> sysView;
 
     /**
      * @param ctx Kernal context.
      * @param sysView View to export.
+     * @param indexes Indexed fields.
      */
-    public SystemViewLocal(GridKernalContext ctx, SystemView<R> sysView) {
-        super(sqlName(sysView.name()), sysView.description(), ctx, columnsList(sysView));
+    protected SystemViewLocal(GridKernalContext ctx, SystemView<R> sysView, String[] indexes) {
+        super(sqlName(sysView.name()), sysView.description(), ctx, indexes, columnsList(sysView));
 
         this.sysView = sysView;
     }
 
+    /**
+     * @param ctx Kernal context.
+     * @param sysView View to export.
+     */
+    public SystemViewLocal(GridKernalContext ctx, SystemView<R> sysView) {
+        this(ctx, sysView, null);
+    }
+
+    /**
+     * System view iterator.
+     */
+    protected Iterator<R> viewIterator(SearchRow first, SearchRow last) {
+        return sysView.iterator();
+    }
+
     /** {@inheritDoc} */
     @Override public Iterator<Row> getRows(Session ses, SearchRow first, SearchRow last) {
-        Iterator<R> rows = sysView.iterator();
+        Iterator<R> rows = viewIterator(first, last);
 
         return new Iterator<Row>() {
             @Override public boolean hasNext() {
@@ -161,7 +177,7 @@ public class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
      *
      * @param sysView System view.
      * @param <R> Row type.
-     * @return SQL column array for {@code rowClass}.
+     * @return SQL column array for {@code sysView}.
      */
     private static <R> Column[] columnsList(SystemView<R> sysView) {
         Column[] cols = new Column[sysView.walker().count()];
@@ -214,6 +230,13 @@ public class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
     }
 
     /** {@inheritDoc} */
+    @Override public long getRowCountApproximation() {
+        // getRowCount() method is not really fast, for some system views it's required to iterate over elements to
+        // calculate size, so it's more safe to use constant here.
+        return DEFAULT_ROW_COUNT_APPROXIMATION;
+    }
+
+    /** {@inheritDoc} */
     @Override public boolean canGetRowCount() {
         return true;
     }
@@ -228,7 +251,7 @@ public class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
      * @param name Name to convert.
      * @return SQL compatible name.
      */
-    public static String sqlName(String name) {
+    protected static String sqlName(String name) {
         return name
             .replaceAll("([A-Z])", "_$1")
             .replaceAll('\\' + MetricUtils.SEPARATOR, "_").toUpperCase();
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
index dc39ec2..3a6652d 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
@@ -35,6 +35,7 @@ import org.apache.ignite.IgniteCache;
 import org.apache.ignite.IgniteJdbcThinDriver;
 import org.apache.ignite.Ignition;
 import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
 import org.apache.ignite.cache.query.ContinuousQuery;
 import org.apache.ignite.cache.query.QueryCursor;
 import org.apache.ignite.cache.query.ScanQuery;
@@ -50,6 +51,7 @@ import org.apache.ignite.internal.metric.AbstractExporterSpiTest;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestPredicate;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestRunnable;
 import org.apache.ignite.internal.metric.SystemViewSelfTest.TestTransformer;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
 import org.apache.ignite.internal.processors.service.DummyService;
 import org.apache.ignite.internal.util.StripedExecutor;
 import org.apache.ignite.lang.IgniteBiTuple;
@@ -90,7 +92,11 @@ public class SqlViewExporterSpiTest extends AbstractExporterSpiTest {
     @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
         IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
 
+        cfg.setConsistentId(igniteInstanceName);
+
         cfg.setDataStorageConfiguration(new DataStorageConfiguration()
+            .setDataRegionConfigurations(
+                new DataRegionConfiguration().setName("in-memory").setMaxSize(100L * 1024 * 1024))
             .setDefaultDataRegionConfiguration(
                 new DataRegionConfiguration()
                     .setPersistenceEnabled(true)));
@@ -417,7 +423,9 @@ public class SqlViewExporterSpiTest extends AbstractExporterSpiTest {
             "TRANSACTIONS",
             "CONTINUOUS_QUERIES",
             "STRIPED_THREADPOOL_QUEUE",
-            "DATASTREAM_THREADPOOL_QUEUE"
+            "DATASTREAM_THREADPOOL_QUEUE",
+            "DATA_REGION_PAGE_LISTS",
+            "CACHE_GROUP_PAGE_LISTS"
         ));
 
         Set<String> actViews = new HashSet<>();
@@ -835,6 +843,82 @@ public class SqlViewExporterSpiTest extends AbstractExporterSpiTest {
         }
     }
 
+    /** */
+    @Test
+    public void testPagesList() throws Exception {
+        String cacheName = "cacheFL";
+
+        IgniteCache<Integer, byte[]> cache = ignite0.getOrCreateCache(new CacheConfiguration<Integer, byte[]>()
+            .setName(cacheName).setAffinity(new RendezvousAffinityFunction().setPartitions(1)));
+
+        GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ignite0.context().cache().context()
+            .database();
+
+        int pageSize = dbMgr.pageSize();
+
+        try {
+            dbMgr.enableCheckpoints(false).get();
+
+            int key = 0;
+
+            // Fill up different free-list buckets.
+            for (int j = 0; j < pageSize / 2; j++)
+                cache.put(key++, new byte[j + 1]);
+
+            // Put some pages to one bucket to overflow pages cache.
+            for (int j = 0; j < 1000; j++)
+                cache.put(key++, new byte[pageSize / 2]);
+
+            // Test filtering by 3 columns.
+            assertFalse(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE BUCKET_NUMBER = 0 " +
+                "AND PARTITION_ID = 0 AND CACHE_GROUP_ID = ?", cacheId(cacheName)).isEmpty());
+
+            // Test filtering with invalid cache group id.
+            assertTrue(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE CACHE_GROUP_ID = ?", -1)
+                .isEmpty());
+
+            // Test filtering with invalid partition id.
+            assertTrue(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE PARTITION_ID = ?", -1)
+                .isEmpty());
+
+            // Test filtering with invalid bucket number.
+            assertTrue(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE BUCKET_NUMBER = -1")
+                .isEmpty());
+
+            assertFalse(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE BUCKET_SIZE > 0 " +
+                "AND CACHE_GROUP_ID = ?", cacheId(cacheName)).isEmpty());
+
+            assertFalse(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE STRIPES_COUNT > 0 " +
+                "AND CACHE_GROUP_ID = ?", cacheId(cacheName)).isEmpty());
+
+            assertFalse(execute(ignite0, "SELECT * FROM SYS.CACHE_GROUP_PAGE_LISTS WHERE CACHED_PAGES_COUNT > 0 " +
+                "AND CACHE_GROUP_ID = ?", cacheId(cacheName)).isEmpty());
+
+            assertFalse(execute(ignite0, "SELECT * FROM SYS.DATA_REGION_PAGE_LISTS WHERE NAME LIKE 'in-memory%'")
+                .isEmpty());
+
+            assertEquals(0L, execute(ignite0, "SELECT COUNT(*) FROM SYS.DATA_REGION_PAGE_LISTS " +
+                "WHERE NAME LIKE 'in-memory%' AND BUCKET_SIZE > 0").get(0).get(0));
+        }
+        finally {
+            dbMgr.enableCheckpoints(true).get();
+        }
+
+        ignite0.cluster().active(false);
+
+        ignite0.cluster().active(true);
+
+        IgniteCache<Integer, Integer> cacheInMemory = ignite0.getOrCreateCache(new CacheConfiguration<Integer, Integer>()
+            .setName("cacheFLInMemory").setDataRegionName("in-memory"));
+
+        cacheInMemory.put(0, 0);
+
+        // After activation/deactivation new view for data region pages lists should be created, check that new view
+        // correctly reflects changes in free-lists.
+        assertFalse(execute(ignite0, "SELECT * FROM SYS.DATA_REGION_PAGE_LISTS WHERE NAME LIKE 'in-memory%' AND " +
+            "BUCKET_SIZE > 0").isEmpty());
+    }
+
     /**
      * Execute query on given node.
      *