You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by sb...@apache.org on 2017/12/22 11:11:13 UTC

[04/13] ignite git commit: INITE-369 Cache statistics enable/disable in runtime

INITE-369 Cache statistics enable/disable in runtime

Signed-off-by: Andrey Gura <ag...@apache.org>


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

Branch: refs/heads/ignite-zk
Commit: e70b01d02845e9d469d5f635764acdb48624b860
Parents: e9702a5
Author: Aleksey Plekhanov <Pl...@gmail.com>
Authored: Wed Dec 20 15:48:11 2017 +0300
Committer: Andrey Gura <ag...@apache.org>
Committed: Wed Dec 20 15:48:11 2017 +0300

----------------------------------------------------------------------
 .../java/org/apache/ignite/IgniteCache.java     |   7 +
 .../java/org/apache/ignite/IgniteCluster.java   |   8 +
 .../org/apache/ignite/cache/CacheManager.java   |   6 +-
 .../cluster/IgniteClusterAsyncImpl.java         |   5 +
 .../internal/cluster/IgniteClusterImpl.java     |  15 +
 .../discovery/GridDiscoveryManager.java         |   2 +-
 .../cache/CacheClusterMetricsMXBeanImpl.java    |  21 +
 .../cache/CacheLocalMetricsMXBeanImpl.java      |  22 +
 .../processors/cache/CacheMetricsImpl.java      |   4 +-
 .../cache/CacheStatisticsModeChangeMessage.java | 141 +++++++
 .../cache/CacheStatisticsModeChangeTask.java    |  54 +++
 .../processors/cache/ClusterCachesInfo.java     |   2 +
 .../cache/GatewayProtectedCacheProxy.java       |  20 +-
 .../processors/cache/GridCacheAdapter.java      |  42 +-
 .../processors/cache/GridCacheContext.java      |  20 +
 .../cache/GridCacheEvictionManager.java         |   2 +-
 .../processors/cache/GridCacheMapEntry.java     |  16 +-
 .../processors/cache/GridCacheProcessor.java    | 178 ++++++++
 .../processors/cache/IgniteCacheProxyImpl.java  |  10 +
 .../dht/GridPartitionedGetFuture.java           |   2 +-
 .../dht/GridPartitionedSingleGetFuture.java     |   4 +-
 .../dht/atomic/GridDhtAtomicCache.java          |   2 +-
 .../dht/colocated/GridDhtColocatedCache.java    |   2 +-
 .../dht/preloader/GridDhtPartitionDemander.java |  10 +-
 .../distributed/near/GridNearCacheEntry.java    |   2 +-
 .../distributed/near/GridNearGetFuture.java     |   4 +-
 .../distributed/near/GridNearLockFuture.java    |   4 +-
 .../local/atomic/GridLocalAtomicCache.java      |   4 +-
 .../cache/query/GridCacheQueryManager.java      |   8 +-
 .../transactions/IgniteTxLocalStateAdapter.java |   2 +-
 .../processors/query/GridQueryProcessor.java    |  34 +-
 .../ignite/mxbean/CacheMetricsMXBean.java       |  12 +
 .../cache/CacheMetricsEnableRuntimeTest.java    | 401 +++++++++++++++++++
 .../cache/GridCacheAbstractMetricsSelfTest.java |  12 +-
 .../near/GridCacheNearMetricsSelfTest.java      |   4 +-
 .../multijvm/IgniteCacheProcessProxy.java       |   5 +
 .../multijvm/IgniteClusterProcessProxy.java     |   5 +
 .../IgniteCacheMetricsSelfTestSuite.java        |   3 +
 38 files changed, 1000 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
index 973eeab..6a0add9 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCache.java
@@ -1434,4 +1434,11 @@ public interface IgniteCache<K, V> extends javax.cache.Cache<K, V>, IgniteAsyncS
      * @return Lost paritions.
      */
     public Collection<Integer> lostPartitions();
+
+    /**
+     * Sets statistics enabled flag cluster wide for this cache.
+     *
+     * @param enabled Statistics enabled flag.
+     */
+    public void enableStatistics(boolean enabled);
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
index 0846066..cb2484f 100644
--- a/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
+++ b/modules/core/src/main/java/org/apache/ignite/IgniteCluster.java
@@ -412,6 +412,14 @@ public interface IgniteCluster extends ClusterGroup, IgniteAsyncSupport {
     public void resetMetrics();
 
     /**
+     * Enables/disables statistics for caches cluster wide.
+     *
+     * @param caches Collection of cache names.
+     * @param enabled Statistics enabled flag.
+     */
+    public void enableStatistics(Collection<String> caches, boolean enabled);
+
+    /**
      * If local client node disconnected from cluster returns future
      * that will be completed when client reconnected.
      *

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/cache/CacheManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/cache/CacheManager.java b/modules/core/src/main/java/org/apache/ignite/cache/CacheManager.java
index 03d1f40..b572dd5 100644
--- a/modules/core/src/main/java/org/apache/ignite/cache/CacheManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/cache/CacheManager.java
@@ -351,14 +351,12 @@ public class CacheManager implements javax.cache.CacheManager {
             if (cache == null)
                 throw new CacheException("Cache not found: " + cacheName);
 
-            CacheConfiguration cfg = cache.getConfiguration(CacheConfiguration.class);
-
             if (enabled)
                 registerCacheObject(cache.mxBean(), cacheName, CACHE_STATISTICS);
             else
                 unregisterCacheObject(cacheName, CACHE_STATISTICS);
 
-            cfg.setStatisticsEnabled(enabled);
+            ignite.context().cache().cache(cacheName).context().statisticsEnabled(enabled);
         }
         finally {
             kernalGateway.readUnlock();
@@ -450,4 +448,4 @@ public class CacheManager implements javax.cache.CacheManager {
 
         throw new IllegalArgumentException();
     }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
index c7554cb..f2c14eb 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterAsyncImpl.java
@@ -166,6 +166,11 @@ public class IgniteClusterAsyncImpl extends AsyncSupportAdapter<IgniteCluster>
     }
 
     /** {@inheritDoc} */
+    @Override public void enableStatistics(Collection<String> caches, boolean enabled) {
+        cluster.enableStatistics(caches, enabled);
+    }
+
+    /** {@inheritDoc} */
     @Override public Ignite ignite() {
         return cluster.ignite();
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
index ba4aac3..0c95dc2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/cluster/IgniteClusterImpl.java
@@ -284,6 +284,21 @@ public class IgniteClusterImpl extends ClusterGroupAdapter implements IgniteClus
     }
 
     /** {@inheritDoc} */
+    @Override public void enableStatistics(Collection<String> caches, boolean enabled) {
+        guard();
+
+        try {
+            ctx.cache().enableStatistics(caches, enabled);
+        }
+        catch (IgniteCheckedException e) {
+            throw U.convertException(e);
+        }
+        finally {
+            unguard();
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public IgniteCluster withAsync() {
         return new IgniteClusterAsyncImpl(this);
     }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
index 3c7df92..be789e2 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/discovery/GridDiscoveryManager.java
@@ -1147,7 +1147,7 @@ public class GridDiscoveryManager extends GridManagerAdapter<DiscoverySpi> {
                 Map<Integer, CacheMetrics> metrics = null;
 
                 for (GridCacheAdapter<?, ?> cache : caches) {
-                    if (cache.configuration().isStatisticsEnabled() &&
+                    if (cache.context().statisticsEnabled() &&
                         cache.context().started() &&
                         cache.context().affinity().affinityTopologyVersion().topologyVersion() > 0) {
                         if (metrics == null)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
index 7d57eb0..fb9c035 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheClusterMetricsMXBeanImpl.java
@@ -17,6 +17,7 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import java.util.Collections;
 import org.apache.ignite.IgniteCache;
 import org.apache.ignite.mxbean.CacheMetricsMXBean;
 
@@ -412,4 +413,24 @@ class CacheClusterMetricsMXBeanImpl implements CacheMetricsMXBean {
     @Override public boolean isValidForWriting() {
         return cache.clusterMetrics().isValidForWriting();
     }
+
+    /** {@inheritDoc} */
+    @Override public void enableStatistics() {
+        try {
+            cache.context().shared().cache().enableStatistics(Collections.singleton(cache.name()), true);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void disableStatistics() {
+        try {
+            cache.context().shared().cache().enableStatistics(Collections.singleton(cache.name()), false);
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
index 88cc6db..f62cd15 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheLocalMetricsMXBeanImpl.java
@@ -17,7 +17,9 @@
 
 package org.apache.ignite.internal.processors.cache;
 
+import java.util.Collections;
 import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.mxbean.CacheMetricsMXBean;
 
 /**
@@ -412,4 +414,24 @@ class CacheLocalMetricsMXBeanImpl implements CacheMetricsMXBean {
     @Override public boolean isValidForWriting() {
         return cache.metrics0().isValidForWriting();
     }
+
+    /** {@inheritDoc} */
+    @Override public void enableStatistics() {
+        try {
+            cache.context().shared().cache().enableStatistics(Collections.singleton(cache.name()), true);
+        }
+        catch (IgniteCheckedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override public void disableStatistics() {
+        try {
+            cache.context().shared().cache().enableStatistics(Collections.singleton(cache.name()), false);
+        }
+        catch (IgniteCheckedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
index 78a4f97..8d46a21 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheMetricsImpl.java
@@ -756,9 +756,7 @@ public class CacheMetricsImpl implements CacheMetrics {
 
     /** {@inheritDoc} */
     @Override public boolean isStatisticsEnabled() {
-        CacheConfiguration ccfg = cctx.config();
-
-        return ccfg != null && ccfg.isStatisticsEnabled();
+        return cctx.statisticsEnabled();
     }
 
     /** {@inheritDoc} */

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeMessage.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeMessage.java
new file mode 100644
index 0000000..40bcfaf
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeMessage.java
@@ -0,0 +1,141 @@
+/*
+ * 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;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.UUID;
+import org.apache.ignite.internal.managers.discovery.DiscoCache;
+import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage;
+import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.lang.IgniteUuid;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Cache statistics mode change discovery message.
+ */
+public class CacheStatisticsModeChangeMessage implements DiscoveryCustomMessage {
+    /** */
+    private static final long serialVersionUID = 0L;
+
+    /** Initial message flag mask. */
+    private static final byte INITIAL_MSG_MASK = 0x01;
+
+    /** Statistics enabled flag mask. */
+    private static final byte ENABLED_MASK = 0x02;
+
+    /** Custom message ID. */
+    private final IgniteUuid id = IgniteUuid.randomUuid();
+
+    /** Request id. */
+    private final UUID reqId;
+
+    /** Cache names. */
+    private final Collection<String> caches;
+
+    /** Flags. */
+    private final byte flags;
+
+    /**
+     * Constructor for response.
+     *
+     * @param req Request message.
+     */
+    private CacheStatisticsModeChangeMessage(CacheStatisticsModeChangeMessage req) {
+        reqId = req.reqId;
+        caches = null;
+
+        if (req.enabled())
+            flags = ENABLED_MASK;
+        else
+            flags = 0;
+    }
+
+    /**
+     * Constructor for request.
+     *
+     * @param caches Collection of cache names.
+     */
+    public CacheStatisticsModeChangeMessage(UUID reqId, Collection<String> caches, boolean enabled) {
+        this.reqId = reqId;
+        this.caches = Collections.unmodifiableCollection(caches);
+
+        byte flags = INITIAL_MSG_MASK;
+
+        if (enabled)
+            flags |= ENABLED_MASK;
+
+        this.flags = flags;
+    }
+
+    /** {@inheritDoc} */
+    @Override public IgniteUuid id() {
+        return id;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable @Override public DiscoveryCustomMessage ackMessage() {
+        return initial() ? new CacheStatisticsModeChangeMessage(this) : null;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean isMutable() {
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override public DiscoCache createDiscoCache(GridDiscoveryManager mgr, AffinityTopologyVersion topVer,
+        DiscoCache discoCache) {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @return Cache names.
+     */
+    public Collection<String> caches() {
+        return Collections.unmodifiableCollection(caches);
+    }
+
+    /**
+     * Initial message flag.
+     */
+    public boolean initial() {
+        return (flags & INITIAL_MSG_MASK) != 0;
+    }
+
+    /**
+     * @return Statistic enabled.
+     */
+    public boolean enabled() {
+        return (flags & ENABLED_MASK) != 0;
+    }
+
+    /**
+     * @return Request id.
+     */
+    public UUID requestId() {
+        return reqId;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(CacheStatisticsModeChangeMessage.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeTask.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeTask.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeTask.java
new file mode 100644
index 0000000..063d157
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheStatisticsModeChangeTask.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import org.apache.ignite.internal.util.typedef.internal.S;
+
+/**
+ * Cache statistics mode change task for exchange worker.
+ */
+public class CacheStatisticsModeChangeTask implements CachePartitionExchangeWorkerTask {
+    /** Discovery message. */
+    private final CacheStatisticsModeChangeMessage msg;
+
+    /**
+     * @param msg Message.
+     */
+    public CacheStatisticsModeChangeTask(CacheStatisticsModeChangeMessage msg) {
+        assert msg != null;
+
+        this.msg = msg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean skipForExchangeMerge() {
+        return false;
+    }
+
+    /**
+     * @return Message.
+     */
+    public CacheStatisticsModeChangeMessage message() {
+        return msg;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return S.toString(CacheStatisticsModeChangeTask.class, this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 2c32bf2..0c4fc68 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -1145,6 +1145,8 @@ class ClusterCachesInfo {
                     desc0.receivedFromStartVersion(desc.receivedFromStartVersion());
                     desc0.clientCacheStartVersion(desc.clientCacheStartVersion());
 
+                    desc0.cacheConfiguration().setStatisticsEnabled(cfg.isStatisticsEnabled());
+
                     desc = desc0;
                 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GatewayProtectedCacheProxy.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GatewayProtectedCacheProxy.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GatewayProtectedCacheProxy.java
index 37bf9bb..564b18a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GatewayProtectedCacheProxy.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GatewayProtectedCacheProxy.java
@@ -1618,6 +1618,20 @@ public class GatewayProtectedCacheProxy<K, V> extends AsyncSupportAdapter<Ignite
         }
     }
 
+    /** {@inheritDoc} */
+    @Override public void enableStatistics(boolean enabled) {
+        GridCacheGateway<K, V> gate = gate();
+
+        CacheOperationContext prev = onEnter(gate, opCtx);
+
+        try {
+            delegate.enableStatistics(enabled);
+        }
+        finally {
+            onLeave(gate, prev);
+        }
+    }
+
     /**
      * Safely get CacheGateway.
      *
@@ -1640,11 +1654,11 @@ public class GatewayProtectedCacheProxy<K, V> extends AsyncSupportAdapter<Ignite
 
         if (delegate instanceof IgniteCacheProxyImpl)
             ((IgniteCacheProxyImpl) delegate).checkRestart();
-        
+
         if (gate == null)
             throw new IllegalStateException("Gateway is unavailable. Probably cache has been destroyed, but proxy is not closed.");
     }
-    
+
     /**
      * @param gate Cache gateway.
      * @param opCtx Cache operation context to guard.
@@ -1652,7 +1666,7 @@ public class GatewayProtectedCacheProxy<K, V> extends AsyncSupportAdapter<Ignite
      */
     private CacheOperationContext onEnter(@Nullable GridCacheGateway<K, V> gate, CacheOperationContext opCtx) {
         checkProxyIsValid(gate);
-        
+
         return lock ? gate.enter(opCtx) : gate.enterNoLock(opCtx);
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
index e9c86b7..4370e75 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java
@@ -1331,7 +1331,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Nullable @Override public V get(K key) throws IgniteCheckedException {
         A.notNull(key, "key");
 
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1358,7 +1358,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Nullable @Override public CacheEntry<K, V> getEntry(K key) throws IgniteCheckedException {
         A.notNull(key, "key");
 
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1394,7 +1394,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Override public IgniteInternalFuture<V> getAsync(final K key) {
         A.notNull(key, "key");
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1423,7 +1423,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Override public IgniteInternalFuture<CacheEntry<K, V>> getEntryAsync(final K key) {
         A.notNull(key, "key");
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1470,7 +1470,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Override public final Map<K, V> getAll(@Nullable Collection<? extends K> keys) throws IgniteCheckedException {
         A.notNull(keys, "keys");
 
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1490,7 +1490,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         throws IgniteCheckedException {
         A.notNull(keys, "keys");
 
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1514,7 +1514,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
     @Override public IgniteInternalFuture<Map<K, V>> getAllAsync(@Nullable final Collection<? extends K> keys) {
         A.notNull(keys, "keys");
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1551,7 +1551,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         @Nullable final Collection<? extends K> keys) {
         A.notNull(keys, "keys");
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -1935,7 +1935,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
                                             !deserializeBinary);
                                     }
 
-                                    if (updateMetrics && ctx.cache().configuration().isStatisticsEnabled())
+                                    if (updateMetrics && ctx.statisticsEnabled())
                                         ctx.cache().metrics0().onRead(true);
                                 }
                                 else if (storeEnabled)
@@ -1948,7 +1948,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
                                 entry = entryEx(key);
 
                                 if (entry == null) {
-                                    if (!skipVals && ctx.config().isStatisticsEnabled())
+                                    if (!skipVals && ctx.statisticsEnabled())
                                         ctx.cache().metrics0().onRead(false);
 
                                     break;
@@ -2233,7 +2233,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
      */
     @Nullable public V getAndPut(final K key, final V val, @Nullable final CacheEntryPredicate filter)
         throws IgniteCheckedException {
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2285,7 +2285,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
      * @return Put operation future.
      */
     protected final IgniteInternalFuture<V> getAndPutAsync(K key, V val, @Nullable CacheEntryPredicate filter) {
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2342,7 +2342,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
      */
     public boolean put(final K key, final V val, final CacheEntryPredicate filter)
         throws IgniteCheckedException {
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2682,7 +2682,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         if (keyCheck)
             validateCacheKey(key);
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2783,7 +2783,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         if (F.isEmpty(m))
             return;
 
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2846,7 +2846,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
     /** {@inheritDoc} */
     @Nullable @Override public V getAndRemove(final K key) throws IgniteCheckedException {
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2900,7 +2900,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
     /** {@inheritDoc} */
     @Override public IgniteInternalFuture<V> getAndRemoveAsync(final K key) {
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -2963,7 +2963,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
 
     /** {@inheritDoc} */
     @Override public void removeAll(final Collection<? extends K> keys) throws IgniteCheckedException {
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -3008,7 +3008,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
         if (F.isEmpty(keys))
             return new GridFinishedFuture<Object>();
 
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -3057,7 +3057,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
      * @throws IgniteCheckedException If failed.
      */
     public boolean remove(final K key, @Nullable CacheEntryPredicate filter) throws IgniteCheckedException {
-        boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        boolean statsEnabled = ctx.statisticsEnabled();
 
         long start = statsEnabled ? System.nanoTime() : 0L;
 
@@ -3115,7 +3115,7 @@ public abstract class GridCacheAdapter<K, V> implements IgniteInternalCache<K, V
      * @return Putx operation future.
      */
     public IgniteInternalFuture<Boolean> removeAsync(final K key, @Nullable final CacheEntryPredicate filter) {
-        final boolean statsEnabled = ctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = ctx.statisticsEnabled();
 
         final long start = statsEnabled ? System.nanoTime() : 0L;
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index 3581f9f..3a2e862 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -254,6 +254,9 @@ public class GridCacheContext<K, V> implements Externalizable {
     /** Whether {@link EventType#EVT_CACHE_REBALANCE_STOPPED} was sent (used only for REPLICATED cache). */
     private volatile boolean rebalanceStoppedEvtSent;
 
+    /** Statistics enabled flag. */
+    private volatile boolean statisticsEnabled;
+
     /**
      * Empty constructor required for {@link Externalizable}.
      */
@@ -2127,6 +2130,23 @@ public class GridCacheContext<K, V> implements Externalizable {
         }
     }
 
+    /**
+     * @return Statistics enabled flag.
+     */
+    public boolean statisticsEnabled() {
+        return statisticsEnabled;
+    }
+
+    /**
+     * @param statisticsEnabled Statistics enabled flag.
+     */
+    public void statisticsEnabled(boolean statisticsEnabled) {
+        this.statisticsEnabled = statisticsEnabled;
+
+        if (isNear())
+            near().dht().context().statisticsEnabled = statisticsEnabled;
+    }
+
     /** {@inheritDoc} */
     @Override public void writeExternal(ObjectOutput out) throws IOException {
         U.writeString(out, igniteInstanceName());

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
index 084b235..2c9dec7 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEvictionManager.java
@@ -146,7 +146,7 @@ public class GridCacheEvictionManager extends GridCacheManagerAdapter implements
 
             cache.removeEntry(entry);
 
-            if (cache.configuration().isStatisticsEnabled())
+            if (cctx.statisticsEnabled())
                 cache.metrics0().onEvict();
 
             if (recordable)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
index 79390ed..9439b12 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java
@@ -612,11 +612,11 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             CacheObject ret = val;
 
             if (ret == null) {
-                if (updateMetrics && cctx.cache().configuration().isStatisticsEnabled())
+                if (updateMetrics && cctx.statisticsEnabled())
                     cctx.cache().metrics0().onRead(false);
             }
             else {
-                if (updateMetrics && cctx.cache().configuration().isStatisticsEnabled())
+                if (updateMetrics && cctx.statisticsEnabled())
                     cctx.cache().metrics0().onRead(true);
             }
 
@@ -1002,7 +1002,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
 
             recordNodeId(affNodeId, topVer);
 
-            if (metrics && cctx.cache().configuration().isStatisticsEnabled())
+            if (metrics && cctx.statisticsEnabled())
                 cctx.cache().metrics0().onWrite();
 
             if (evt && newVer != null && cctx.events().isRecordable(EVT_CACHE_OBJECT_PUT)) {
@@ -1177,7 +1177,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
 
             drReplicate(drType, null, newVer, topVer);
 
-            if (metrics && cctx.cache().configuration().isStatisticsEnabled())
+            if (metrics && cctx.statisticsEnabled())
                 cctx.cache().metrics0().onRemove();
 
             if (tx == null)
@@ -1374,7 +1374,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             }
 
             // Apply metrics.
-            if (metrics && cctx.cache().configuration().isStatisticsEnabled() && needVal) {
+            if (metrics && cctx.statisticsEnabled() && needVal) {
                 // PutIfAbsent methods mustn't update hit/miss statistics
                 if (op != GridCacheOperation.UPDATE || F.isEmpty(filter) || !cctx.putIfAbsentFilter(filter))
                     cctx.cache().metrics0().onRead(old != null);
@@ -1704,7 +1704,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
             // Apply metrics.
             if (metrics &&
                 updateRes.outcome().updateReadMetrics() &&
-                cctx.cache().configuration().isStatisticsEnabled() &&
+                cctx.statisticsEnabled() &&
                 needVal) {
                 // PutIfAbsent methods must not update hit/miss statistics.
                 if (op != GridCacheOperation.UPDATE || F.isEmpty(filter) || !cctx.putIfAbsentFilter(filter))
@@ -3000,7 +3000,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
                 cctx.onDeferredDelete(this, ver0);
             }
 
-            if ((obsolete || deferred) && cctx.cache().configuration().isStatisticsEnabled())
+            if ((obsolete || deferred) && cctx.statisticsEnabled())
                 cctx.cache().metrics0().onEvict();
         }
 
@@ -3709,7 +3709,7 @@ public abstract class GridCacheMapEntry extends GridMetadataAwareAdapter impleme
      * @param metrics Update merics flag.
      */
     private void updateMetrics(GridCacheOperation op, boolean metrics) {
-        if (metrics && cctx.cache().configuration().isStatisticsEnabled()) {
+        if (metrics && cctx.statisticsEnabled()) {
             if (op == GridCacheOperation.DELETE)
                 cctx.cache().metrics0().onRemove();
             else

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
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 dcc3d13..30033d3 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
@@ -206,6 +206,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
     /** Template configuration add futures. */
     private ConcurrentMap<String, IgniteInternalFuture> pendingTemplateFuts = new ConcurrentHashMap<>();
 
+    /** Enable/disable cache statistics futures. */
+    private ConcurrentMap<UUID, EnableStatisticsFuture> enableStatisticsFuts = new ConcurrentHashMap<>();
+
     /** */
     private ClusterCachesInfo cachesInfo;
 
@@ -310,6 +313,12 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
             return msg0;
         }
+        else if (msg instanceof CacheStatisticsModeChangeMessage) {
+            CacheStatisticsModeChangeMessage msg0 = (CacheStatisticsModeChangeMessage)msg;
+
+            if (msg0.initial())
+                return new CacheStatisticsModeChangeTask(msg0);
+        }
 
         return null;
     }
@@ -346,6 +355,11 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
             sharedCtx.affinity().sendClientCacheChangesMessage(task0);
         }
+        else if (task instanceof CacheStatisticsModeChangeTask) {
+            CacheStatisticsModeChangeTask task0 = (CacheStatisticsModeChangeTask)task;
+
+            processStatisticsModeChange(task0.message());
+        }
         else
             U.warn(log, "Unsupported custom exchange task: " + task);
     }
@@ -978,6 +992,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
         for (IgniteInternalFuture fut : pendingTemplateFuts.values())
             ((GridFutureAdapter)fut).onDone(err);
 
+        for (EnableStatisticsFuture fut : enableStatisticsFuts.values())
+            fut.onDone(err);
+
         for (CacheGroupContext grp : cacheGrps.values())
             grp.onDisconnected(reconnectFut);
 
@@ -1413,6 +1430,8 @@ public class GridCacheProcessor extends GridProcessorAdapter {
             affMgr
         );
 
+        cacheCtx.statisticsEnabled(desc.cacheConfiguration().isStatisticsEnabled());
+
         cacheCtx.cacheObjectContext(cacheObjCtx);
 
         GridCacheAdapter cache = null;
@@ -1543,6 +1562,8 @@ public class GridCacheProcessor extends GridProcessorAdapter {
                 affMgr
             );
 
+            cacheCtx.statisticsEnabled(desc.cacheConfiguration().isStatisticsEnabled());
+
             cacheCtx.cacheObjectContext(cacheObjCtx);
 
             GridDhtCacheAdapter dht = null;
@@ -2390,6 +2411,71 @@ public class GridCacheProcessor extends GridProcessorAdapter {
     }
 
     /**
+     * Cache statistics flag change message received.
+     *
+     * @param msg Message.
+     */
+    public void onCacheStatisticsModeChange(CacheStatisticsModeChangeMessage msg) {
+        assert msg != null;
+
+        if (msg.initial()) {
+            EnableStatisticsFuture fut = enableStatisticsFuts.get(msg.requestId());
+
+            if (fut != null && !cacheNames().containsAll(msg.caches())) {
+                fut.onDone(new IgniteCheckedException("One or more cache descriptors not found [caches="
+                    + caches + ']'));
+
+                return;
+            }
+
+            for (String cacheName : msg.caches()) {
+                DynamicCacheDescriptor desc = cachesInfo.registeredCaches().get(cacheName);
+
+                if (desc != null) {
+                    if (desc.cacheConfiguration().isStatisticsEnabled() != msg.enabled()) {
+                        desc.cacheConfiguration().setStatisticsEnabled(msg.enabled());
+
+                        try {
+                            ctx.cache().saveCacheConfiguration(desc);
+                        }
+                        catch (IgniteCheckedException e) {
+                            log.error("Error while saving cache configuration to disk, cfg = "
+                                + desc.cacheConfiguration(), e);
+                        }
+                    }
+                }
+                else
+                    log.warning("Failed to change cache descriptor configuration, cache not found [cacheName="
+                        + cacheName + ']');
+            }
+        }
+        else {
+            EnableStatisticsFuture fut = enableStatisticsFuts.get(msg.requestId());
+
+            if (fut != null)
+                fut.onDone();
+        }
+    }
+
+    /**
+     * Cache statistics flag change task processed by exchange worker.
+     *
+     * @param msg Message.
+     */
+    public void processStatisticsModeChange(CacheStatisticsModeChangeMessage msg) {
+        assert msg != null;
+
+        for (String cacheName : msg.caches()) {
+            IgniteInternalCache<Object, Object> cache = cache(cacheName);
+
+            if (cache != null)
+                cache.context().statisticsEnabled(msg.enabled());
+            else
+                log.warning("Failed to change cache configuration, cache not found [cacheName=" + cacheName + ']');
+        }
+    }
+
+    /**
      * @return {@code True} if need locally start all existing caches on client node start.
      */
     private boolean startAllCachesOnClientStart() {
@@ -2916,6 +3002,22 @@ public class GridCacheProcessor extends GridProcessorAdapter {
     }
 
     /**
+     * Save cache configuration to persistent store if necessary.
+     *
+     * @param desc Cache descriptor.
+     */
+    public void saveCacheConfiguration(DynamicCacheDescriptor desc) throws IgniteCheckedException {
+        assert desc != null;
+
+        if (sharedCtx.pageStore() != null && !sharedCtx.kernalContext().clientNode() &&
+            CU.isPersistentCache(desc.cacheConfiguration(), sharedCtx.gridConfig().getDataStorageConfiguration())) {
+            StoredCacheData data = toStoredData(desc);
+
+            sharedCtx.pageStore().storeCacheData(data, true);
+        }
+    }
+
+    /**
      * Form a {@link StoredCacheData} with all data to correctly restore cache params when its configuration
      * is read from page store. Essentially, this method takes from {@link DynamicCacheDescriptor} all that's
      * needed to start cache correctly, leaving out everything else.
@@ -3072,6 +3174,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
         if (msg instanceof ClientCacheChangeDiscoveryMessage)
             cachesInfo.onClientCacheChange((ClientCacheChangeDiscoveryMessage)msg, node);
 
+        if (msg instanceof CacheStatisticsModeChangeMessage)
+            onCacheStatisticsModeChange((CacheStatisticsModeChangeMessage)msg);
+
         return false;
     }
 
@@ -3619,6 +3724,9 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
         for (IgniteInternalFuture fut : pendingTemplateFuts.values())
             ((GridFutureAdapter)fut).onDone(err);
+
+        for (EnableStatisticsFuture fut : enableStatisticsFuts.values())
+            fut.onDone(err);
     }
 
     /**
@@ -4003,6 +4111,48 @@ public class GridCacheProcessor extends GridProcessorAdapter {
     }
 
     /**
+     * Enable/disable statistics globally for the caches
+     *
+     * @param caches Collection of cache names.
+     * @param enabled Statistics enabled flag.
+     */
+    public void enableStatistics(Collection<String> caches, boolean enabled) throws IgniteCheckedException {
+        assert caches != null;
+
+        Collection<String> globalCaches = new ArrayList<>(caches.size());
+
+        if (!cacheNames().containsAll(caches))
+            throw new IgniteCheckedException("One or more cache descriptors not found [caches=" + caches + ']');
+
+        for (String cacheName : caches) {
+            IgniteInternalCache cache = cache(cacheName);
+
+            if (cache == null)
+                throw new IgniteCheckedException("Cache not found [cacheName=" + cacheName + ']');
+
+            cache.context().statisticsEnabled(enabled);
+
+            if (!cache.context().isLocal())
+                globalCaches.add(cacheName);
+        }
+
+        if (globalCaches.isEmpty())
+            return;
+
+        UUID reqId = UUID.randomUUID();
+
+        EnableStatisticsFuture fut = new EnableStatisticsFuture(reqId);
+
+        enableStatisticsFuts.put(reqId, fut);
+
+        CacheStatisticsModeChangeMessage msg = new CacheStatisticsModeChangeMessage(reqId, globalCaches, enabled);
+
+        ctx.grid().context().discovery().sendCustomEvent(msg);
+
+        fut.get();
+    }
+
+    /**
      * @param obj Object to clone.
      * @return Object copy.
      * @throws IgniteCheckedException If failed.
@@ -4207,4 +4357,32 @@ public class GridCacheProcessor extends GridProcessorAdapter {
             }, true);
         }
     }
+
+    /**
+     * Enable statistics future.
+     */
+    private class EnableStatisticsFuture extends GridFutureAdapter<Void> {
+        /** */
+        private UUID id;
+
+        /**
+         * @param id Future ID.
+         */
+        private EnableStatisticsFuture(UUID id) {
+            this.id = id;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean onDone(@Nullable Void res, @Nullable Throwable err) {
+            // Make sure to remove future before completion.
+            enableStatisticsFuts.remove(id, this);
+
+            return super.onDone(res, err);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return S.toString(EnableStatisticsFuture.class, this);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxyImpl.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxyImpl.java
index ae1c6f5..4c638a9 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxyImpl.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheProxyImpl.java
@@ -1696,6 +1696,16 @@ public class IgniteCacheProxyImpl<K, V> extends AsyncSupportAdapter<IgniteCache<
     }
 
     /** {@inheritDoc} */
+    @Override public void enableStatistics(boolean enabled) {
+        try {
+            ctx.kernalContext().cache().enableStatistics(Collections.singleton(getName()), enabled);
+        }
+        catch (IgniteCheckedException e) {
+            throw cacheException(e);
+        }
+    }
+
+    /** {@inheritDoc} */
     @Override public void writeExternal(ObjectOutput out) throws IOException {
         out.writeObject(ctx);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
index 4148ba9..87d615e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedGetFuture.java
@@ -551,7 +551,7 @@ public class GridPartitionedGetFuture<K, V> extends CacheDistributedGetFutureAda
 
                 // Entry not found, do not continue search if topology did not change and there is no store.
                 if (!cctx.readThroughConfigured() && (topStable || partitionOwned(part))) {
-                    if (!skipVals && cctx.config().isStatisticsEnabled())
+                    if (!skipVals && cctx.statisticsEnabled())
                         cache.metrics0().onRead(false);
 
                     return true;

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
index 61c7785..adb634a 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridPartitionedSingleGetFuture.java
@@ -447,7 +447,7 @@ public class GridPartitionedSingleGetFuture extends GridCacheFutureAdapter<Objec
                 }
 
                 if (v != null) {
-                    if (!skipVals && cctx.config().isStatisticsEnabled())
+                    if (!skipVals && cctx.statisticsEnabled())
                         cctx.cache().metrics0().onRead(true);
 
                     if (!skipVals)
@@ -462,7 +462,7 @@ public class GridPartitionedSingleGetFuture extends GridCacheFutureAdapter<Objec
 
                 // Entry not found, complete future with null result if topology did not change and there is no store.
                 if (!cctx.readThroughConfigured() && (topStable || partitionOwned(part))) {
-                    if (!skipVals && cctx.config().isStatisticsEnabled())
+                    if (!skipVals && cctx.statisticsEnabled())
                         colocated.metrics0().onRead(false);
 
                     if (skipVals)

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
index a7dd615..dc21ea8 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicCache.java
@@ -1561,7 +1561,7 @@ public class GridDhtAtomicCache<K, V> extends GridDhtCacheAdapter<K, V> {
 
                     if (!success)
                         break;
-                    else if (!skipVals && ctx.config().isStatisticsEnabled())
+                    else if (!skipVals && ctx.statisticsEnabled())
                         metrics0().onRead(true);
                 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
index edb4278..607f363 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedCache.java
@@ -569,7 +569,7 @@ public class GridDhtColocatedCache<K, V> extends GridDhtTransactionalCacheAdapte
 
                     if (!success)
                         break;
-                    else if (!skipVals && ctx.config().isStatisticsEnabled())
+                    else if (!skipVals && ctx.statisticsEnabled())
                         ctx.cache().metrics0().onRead(true);
                 }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
index ed296cd..8859950 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionDemander.java
@@ -292,7 +292,7 @@ public class GridDhtPartitionDemander {
             rebalanceFut = fut;
 
             for (final GridCacheContext cctx : grp.caches()) {
-                if (cctx.config().isStatisticsEnabled()) {
+                if (cctx.statisticsEnabled()) {
                     final CacheMetricsImpl metrics = cctx.cache().metrics0();
 
                     metrics.clearRebalanceCounters();
@@ -355,7 +355,7 @@ public class GridDhtPartitionDemander {
         }
         else if (delay > 0) {
             for (GridCacheContext cctx : grp.caches()) {
-                if (cctx.config().isStatisticsEnabled()) {
+                if (cctx.statisticsEnabled()) {
                     final CacheMetricsImpl metrics = cctx.cache().metrics0();
 
                     metrics.startRebalance(delay);
@@ -625,7 +625,7 @@ public class GridDhtPartitionDemander {
 
         if (grp.sharedGroup()) {
             for (GridCacheContext cctx : grp.caches()) {
-                if (cctx.config().isStatisticsEnabled()) {
+                if (cctx.statisticsEnabled()) {
                     long keysCnt = supply.keysForCache(cctx.cacheId());
 
                     if (keysCnt != -1)
@@ -639,7 +639,7 @@ public class GridDhtPartitionDemander {
         else {
             GridCacheContext cctx = grp.singleCacheContext();
 
-            if (cctx.config().isStatisticsEnabled()) {
+            if (cctx.statisticsEnabled()) {
                 if (supply.estimatedKeysCount() != -1)
                     cctx.cache().metrics0().onRebalancingKeysCountEstimateReceived(supply.estimatedKeysCount());
 
@@ -685,7 +685,7 @@ public class GridDhtPartitionDemander {
                                 if (grp.sharedGroup() && (cctx == null || cctx.cacheId() != entry.cacheId()))
                                     cctx = ctx.cacheContext(entry.cacheId());
 
-                                if(cctx != null && cctx.config().isStatisticsEnabled())
+                                if(cctx != null && cctx.statisticsEnabled())
                                     cctx.cache().metrics0().onRebalanceKeyReceived();
                             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
index baf117b..82de0a3 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearCacheEntry.java
@@ -371,7 +371,7 @@ public class GridNearCacheEntry extends GridDistributedCacheEntry {
             synchronized (this) {
                 checkObsolete();
 
-                if (cctx.cache().configuration().isStatisticsEnabled())
+                if (cctx.statisticsEnabled())
                     cctx.cache().metrics0().onRead(false);
 
                 boolean ret = false;

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
index a1a3917..b175018 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java
@@ -491,7 +491,7 @@ public final class GridNearGetFuture<K, V> extends CacheDistributedGetFutureAdap
                         return saved;
                     }
 
-                    if (cctx.cache().configuration().isStatisticsEnabled() && !skipVals && !affNode.isLocal())
+                    if (cctx.statisticsEnabled() && !skipVals && !affNode.isLocal())
                         cache().metrics0().onRead(false);
 
                     LinkedHashMap<KeyCacheObject, Boolean> keys = mapped.get(affNode);
@@ -619,7 +619,7 @@ public final class GridNearGetFuture<K, V> extends CacheDistributedGetFutureAdap
                 }
 
                 if (v != null) {
-                    if (cctx.cache().configuration().isStatisticsEnabled() && !skipVals)
+                    if (cctx.statisticsEnabled() && !skipVals)
                         cache().metrics0().onRead(true);
 
                     addResult(key, v, ver);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
index 3d9989d..70912de 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearLockFuture.java
@@ -1315,7 +1315,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
                                                     inTx() ? tx.resolveTaskName() : null,
                                                     keepBinary);
 
-                                            if (cctx.cache().configuration().isStatisticsEnabled())
+                                            if (cctx.statisticsEnabled())
                                                 cctx.cache().metrics0().onRead(oldVal != null);
                                         }
 
@@ -1739,7 +1739,7 @@ public final class GridNearLockFuture extends GridCacheCompoundIdentityFuture<Bo
                                         inTx() ? tx.resolveTaskName() : null,
                                         keepBinary);
 
-                                if (cctx.cache().configuration().isStatisticsEnabled())
+                                if (cctx.statisticsEnabled())
                                     cctx.cache().metrics0().onRead(false);
                             }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/atomic/GridLocalAtomicCache.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/atomic/GridLocalAtomicCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/atomic/GridLocalAtomicCache.java
index 1454e96..875d97d 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/atomic/GridLocalAtomicCache.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/local/atomic/GridLocalAtomicCache.java
@@ -421,7 +421,7 @@ public class GridLocalAtomicCache<K, V> extends GridLocalCache<K, V> {
                             0,
                             needVer);
 
-                        if (configuration().isStatisticsEnabled() && !skipVals)
+                        if (ctx.statisticsEnabled() && !skipVals)
                             metrics0().onRead(true);
 
                         if (evt) {
@@ -522,7 +522,7 @@ public class GridLocalAtomicCache<K, V> extends GridLocalCache<K, V> {
                 }
             }
             if (!success) {
-                if (!storeEnabled && configuration().isStatisticsEnabled() && !skipVals)
+                if (!storeEnabled && ctx.statisticsEnabled() && !skipVals)
                     metrics0().onRead(false);
             }
         }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
index 063f096..fe8e054 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryManager.java
@@ -910,7 +910,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
 
             FieldsResult res = null;
 
-            final boolean statsEnabled = cctx.config().isStatisticsEnabled();
+            final boolean statsEnabled = cctx.statisticsEnabled();
 
             final boolean readEvt = cctx.gridEvents().isRecordable(EVT_CACHE_QUERY_OBJECT_READ);
 
@@ -1152,7 +1152,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
 
                 AffinityTopologyVersion topVer = cctx.affinity().affinityTopologyVersion();
 
-                final boolean statsEnabled = cctx.config().isStatisticsEnabled();
+                final boolean statsEnabled = cctx.statisticsEnabled();
 
                 final boolean readEvt = cctx.gridEvents().isRecordable(EVT_CACHE_QUERY_OBJECT_READ);
 
@@ -1404,7 +1404,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
         if (!enterBusy())
             throw new IllegalStateException("Failed to process query request (grid is stopping).");
 
-        final boolean statsEnabled = cctx.config().isStatisticsEnabled();
+        final boolean statsEnabled = cctx.statisticsEnabled();
 
         updateStatistics &= statsEnabled;
 
@@ -2955,7 +2955,7 @@ public abstract class GridCacheQueryManager<K, V> extends GridCacheManagerAdapte
             this.cctx = cctx;
             this.log = log;
 
-            statsEnabled = locNode && cctx.config().isStatisticsEnabled();
+            statsEnabled = locNode && cctx.statisticsEnabled();
 
             readEvt = locNode && cctx.gridEvents().isRecordable(EVT_CACHE_QUERY_OBJECT_READ);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalStateAdapter.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalStateAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalStateAdapter.java
index cde5203..d823558 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalStateAdapter.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalStateAdapter.java
@@ -30,7 +30,7 @@ public abstract class IgniteTxLocalStateAdapter implements IgniteTxLocalState {
      * @param commit {@code False} if transaction rolled back.
      */
     protected final void onTxEnd(GridCacheContext cacheCtx, IgniteInternalTx tx, boolean commit) {
-        if (cacheCtx.cache().configuration().isStatisticsEnabled()) {
+        if (cacheCtx.statisticsEnabled()) {
             // Convert start time from ms to ns.
             if (commit)
                 cacheCtx.cache().metrics0().onTxCommit((U.currentTimeMillis() - tx.startTime()) * 1000);

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
index e52a1dd..2d1e392 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java
@@ -515,7 +515,13 @@ public class GridQueryProcessor extends GridProcessorAdapter {
                 if (cacheDesc != null && F.eq(cacheDesc.deploymentId(), proposeMsg.deploymentId())) {
                     cacheDesc.schemaChangeFinish(msg);
 
-                    saveCacheConfiguration(cacheDesc);
+                    try {
+                        ctx.cache().saveCacheConfiguration(cacheDesc);
+                    }
+                    catch (IgniteCheckedException e) {
+                        U.error(log, "Error while saving cache configuration on disk, cfg = "
+                            + cacheDesc.cacheConfiguration(), e);
+                    }
                 }
             }
 
@@ -2574,32 +2580,6 @@ public class GridQueryProcessor extends GridProcessorAdapter {
                     ", sndNodeId=" + msg.senderNodeId() + ']');
         }
     }
-    /**
-     * @param desc cache descriptor.
-     */
-    private void saveCacheConfiguration(DynamicCacheDescriptor desc) {
-        GridCacheSharedContext cctx = ctx.cache().context();
-
-        if (cctx.pageStore() != null && !cctx.kernalContext().clientNode() &&
-            CU.isPersistentCache(desc.cacheConfiguration(), cctx.gridConfig().getDataStorageConfiguration())) {
-            CacheConfiguration cfg = desc.cacheConfiguration();
-
-            try {
-                StoredCacheData data = new StoredCacheData(cfg);
-
-                if (desc.schema() != null)
-                    data.queryEntities(desc.schema().entities());
-
-                data.sql(desc.sql());
-
-                cctx.pageStore().storeCacheData(data, true);
-            }
-            catch (IgniteCheckedException e) {
-                U.error(log, "Error while saving cache configuration on disk, cfg = " + cfg, e);
-            }
-        }
-    }
-
 
     /**
      * Unwind pending messages for particular operation.

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/main/java/org/apache/ignite/mxbean/CacheMetricsMXBean.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/mxbean/CacheMetricsMXBean.java b/modules/core/src/main/java/org/apache/ignite/mxbean/CacheMetricsMXBean.java
index f7bd8bd..ae03a5a 100644
--- a/modules/core/src/main/java/org/apache/ignite/mxbean/CacheMetricsMXBean.java
+++ b/modules/core/src/main/java/org/apache/ignite/mxbean/CacheMetricsMXBean.java
@@ -290,4 +290,16 @@ public interface CacheMetricsMXBean extends CacheStatisticsMXBean, CacheMXBean,
     /** {@inheritDoc} */
     @MXBeanDescription("True when a cache topology is valid for write operations.")
     public boolean isValidForWriting();
+
+    /**
+     * Enable statistic collection for the cache.
+     */
+    @MXBeanDescription("Enable statistic collection for the cache.")
+    public void enableStatistics();
+
+    /**
+     * Disable statistic collection for the cache.
+     */
+    @MXBeanDescription("Disable statistic collection for the cache.")
+    public void disableStatistics();
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/e70b01d0/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsEnableRuntimeTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsEnableRuntimeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsEnableRuntimeTest.java
new file mode 100644
index 0000000..0cf1b43
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsEnableRuntimeTest.java
@@ -0,0 +1,401 @@
+/*
+ * 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;
+
+import java.lang.management.ManagementFactory;
+import java.util.Arrays;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.cache.CacheManager;
+import javax.cache.Caching;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteCheckedException;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMetrics;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.WALMode;
+import org.apache.ignite.internal.IgniteInternalFuture;
+import org.apache.ignite.internal.IgniteInterruptedCheckedException;
+import org.apache.ignite.internal.util.lang.GridAbsPredicate;
+import org.apache.ignite.internal.util.typedef.G;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.mxbean.CacheMetricsMXBean;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+/**
+ *
+ */
+public class CacheMetricsEnableRuntimeTest extends GridCommonAbstractTest {
+    /** */
+    private static final TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true);
+
+    /** */
+    private static final String CACHE1 = "cache1";
+
+    /** */
+    private static final String CACHE2 = "cache2";
+
+    /** */
+    private static final String GROUP = "group1";
+
+    /** Wait condition timeout. */
+    private static final long WAIT_CONDITION_TIMEOUT = 3_000L;
+
+    /** Persistence. */
+    private boolean persistence = false;
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testJmxNoPdsStatisticsEnable() throws Exception {
+        testJmxStatisticsEnable(false);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testJmxPdsStatisticsEnable() throws Exception {
+        testJmxStatisticsEnable(true);
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testCacheManagerStatisticsEnable() throws Exception {
+        final CacheManager mgr1 = Caching.getCachingProvider().getCacheManager();
+        final CacheManager mgr2 = Caching.getCachingProvider().getCacheManager();
+
+        CacheConfiguration cfg1 = new CacheConfiguration()
+            .setName(CACHE1)
+            .setGroupName(GROUP)
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setAtomicityMode(CacheAtomicityMode.ATOMIC);
+
+        mgr1.createCache(CACHE1, cfg1);
+
+        CacheConfiguration cfg2 = new CacheConfiguration(cfg1)
+            .setName(CACHE2)
+            .setStatisticsEnabled(true);
+
+        mgr1.createCache(CACHE2, cfg2);
+
+        assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return !isStatisticsEnabled(mgr1, CACHE1) && !isStatisticsEnabled(mgr2, CACHE1)
+                    && isStatisticsEnabled(mgr1, CACHE2) && isStatisticsEnabled(mgr2, CACHE2);
+            }
+        }, WAIT_CONDITION_TIMEOUT));
+
+        mgr1.enableStatistics(CACHE1, true);
+        mgr2.enableStatistics(CACHE2, false);
+
+        assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return isStatisticsEnabled(mgr1, CACHE1) && isStatisticsEnabled(mgr2, CACHE1)
+                    && !isStatisticsEnabled(mgr1, CACHE2) && !isStatisticsEnabled(mgr2, CACHE2);
+            }
+        }, WAIT_CONDITION_TIMEOUT));
+    }
+
+    /**
+     *
+     */
+    public void testPublicApiStatisticsEnable() throws Exception {
+        Ignite ig1 = startGrid(1);
+        startGrid(2);
+
+        IgniteCache<?, ?> cache1 = ig1.cache(CACHE1);
+
+        CacheConfiguration cacheCfg2 = new CacheConfiguration(cache1.getConfiguration(CacheConfiguration.class));
+
+        cacheCfg2.setName(CACHE2);
+        cacheCfg2.setStatisticsEnabled(true);
+
+        ig1.getOrCreateCache(cacheCfg2);
+
+        assertCachesStatisticsMode(false, true);
+
+        cache1.enableStatistics(true);
+
+        assertCachesStatisticsMode(true, true);
+
+        ig1.cluster().enableStatistics(Arrays.asList(CACHE1, CACHE2), false);
+
+        assertCachesStatisticsMode(false, false);
+    }
+
+    /**
+     *
+     */
+    public void testMultiThreadStatisticsEnable() throws Exception {
+        startGrids(5);
+
+        IgniteCache<?, ?> cache1 = grid(0).cache(CACHE1);
+
+        CacheConfiguration cacheCfg2 = new CacheConfiguration(cache1.getConfiguration(CacheConfiguration.class));
+
+        cacheCfg2.setName(CACHE2);
+
+        grid(0).getOrCreateCache(cacheCfg2);
+
+        final CyclicBarrier barrier = new CyclicBarrier(10);
+
+        final AtomicInteger gridIdx = new AtomicInteger(-1);
+
+        IgniteInternalFuture<?> fut = multithreadedAsync(new Runnable() {
+            @Override public void run() {
+                try {
+                    Ignite ignite = grid(gridIdx.incrementAndGet() % 5);
+
+                    barrier.await();
+
+                    ignite.cluster().enableStatistics(Arrays.asList(CACHE1, CACHE2), true);
+
+                    assertCachesStatisticsMode(true, true);
+
+                    barrier.await();
+
+                    ignite.cluster().enableStatistics(Arrays.asList(CACHE1, CACHE2), false);
+
+                    assertCachesStatisticsMode(false, false);
+
+                    barrier.await();
+
+                    ignite.cluster().enableStatistics(Arrays.asList(CACHE1), true);
+
+                    assertCachesStatisticsMode(true, false);
+                }
+                catch (InterruptedException | BrokenBarrierException | IgniteCheckedException e) {
+                    fail("Unexpected exception: " + e);
+                }
+            }
+        }, 10);
+
+        fut.get();
+
+        startGrid(5);
+
+        assertCachesStatisticsMode(true, false);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        super.afterTest();
+
+        stopAllGrids();
+
+        persistence = false;
+    }
+
+    /**
+     * @param persistence Persistence.
+     */
+    private void testJmxStatisticsEnable(boolean persistence) throws Exception {
+        this.persistence = persistence;
+
+        Ignite ig1 = startGrid(1);
+        Ignite ig2 = startGrid(2);
+
+        ig1.active(true);
+
+        CacheConfiguration ccfg = ig1.cache(CACHE1).getConfiguration(CacheConfiguration.class);
+        CacheConfiguration cacheCfg2 = new CacheConfiguration(ccfg);
+
+        cacheCfg2.setName(CACHE2);
+        cacheCfg2.setStatisticsEnabled(true);
+
+        ig2.getOrCreateCache(cacheCfg2);
+
+        CacheMetricsMXBean mxBeanCache1 = mxBean(2, CACHE1, CacheClusterMetricsMXBeanImpl.class);
+        CacheMetricsMXBean mxBeanCache2 = mxBean(2, CACHE2, CacheClusterMetricsMXBeanImpl.class);
+        CacheMetricsMXBean mxBeanCache1loc = mxBean(2, CACHE1, CacheLocalMetricsMXBeanImpl.class);
+
+        mxBeanCache1.enableStatistics();
+        mxBeanCache2.disableStatistics();
+
+        assertCachesStatisticsMode(true, false);
+
+        stopGrid(1);
+
+        startGrid(3);
+
+        assertCachesStatisticsMode(true, false);
+
+        mxBeanCache1loc.disableStatistics();
+
+        assertCachesStatisticsMode(false, false);
+
+        mxBeanCache1.enableStatistics();
+        mxBeanCache2.enableStatistics();
+
+        // Start node 1 again.
+        startGrid(1);
+
+        assertCachesStatisticsMode(true, true);
+
+        int gridIdx = 0;
+
+        for (Ignite ignite : G.allGrids()) {
+            gridIdx++;
+
+            ignite.cache(CACHE1).put(gridIdx, gridIdx);
+            ignite.cache(CACHE2).put(gridIdx, gridIdx);
+
+            ignite.cache(CACHE1).get(gridIdx);
+            ignite.cache(CACHE2).get(gridIdx);
+        }
+
+        assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                int cnt = G.allGrids().size();
+
+                for (Ignite ignite : G.allGrids()) {
+                    CacheMetrics metrics1 = ignite.cache(CACHE1).metrics();
+                    CacheMetrics metrics2 = ignite.cache(CACHE2).metrics();
+
+                    if (metrics1.getCacheGets() < cnt || metrics2.getCacheGets() < cnt
+                        || metrics1.getCachePuts() < cnt || metrics2.getCachePuts() < cnt)
+                        return false;
+                }
+
+                return true;
+            }
+        }, 10_000L));
+
+        stopAllGrids();
+
+        ig1 = startGrid(1);
+
+        ig1.active(true);
+
+        ig1.getOrCreateCache(cacheCfg2.setStatisticsEnabled(false));
+
+        if (persistence)
+            // cache1 - from local configuration, cache2 - restored from pds
+            assertCachesStatisticsMode(false, true);
+        else
+            assertCachesStatisticsMode(false, false);
+
+        mxBeanCache1 = mxBean(1, CACHE1, CacheLocalMetricsMXBeanImpl.class);
+        mxBeanCache2 = mxBean(1, CACHE2, CacheLocalMetricsMXBeanImpl.class);
+
+        mxBeanCache1.enableStatistics();
+        mxBeanCache2.disableStatistics();
+
+        startGrid(2);
+
+        assertCachesStatisticsMode(true, false);
+    }
+
+    /**
+     * Gets CacheGroupMetricsMXBean for given node and group name.
+     *
+     * @param nodeIdx Node index.
+     * @param cacheName Cache name.
+     * @return MBean instance.
+     */
+    private CacheMetricsMXBean mxBean(int nodeIdx, String cacheName, Class<? extends CacheMetricsMXBean> clazz)
+        throws MalformedObjectNameException {
+        ObjectName mbeanName = U.makeCacheMBeanName(getTestIgniteInstanceName(nodeIdx), cacheName,
+            clazz.getName());
+
+        MBeanServer mbeanSrv = ManagementFactory.getPlatformMBeanServer();
+
+        if (!mbeanSrv.isRegistered(mbeanName))
+            fail("MBean is not registered: " + mbeanName.getCanonicalName());
+
+        return MBeanServerInvocationHandler.newProxyInstance(mbeanSrv, mbeanName, CacheMetricsMXBean.class,
+            true);
+    }
+
+    /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder);
+
+        CacheConfiguration cacheCfg = new CacheConfiguration()
+            .setName(CACHE1)
+            .setGroupName(GROUP)
+            .setCacheMode(CacheMode.PARTITIONED)
+            .setAtomicityMode(CacheAtomicityMode.ATOMIC);
+
+        cfg.setCacheConfiguration(cacheCfg);
+
+        if (persistence)
+            cfg.setDataStorageConfiguration(new DataStorageConfiguration()
+                .setDefaultDataRegionConfiguration(new DataRegionConfiguration().setPersistenceEnabled(true))
+                .setWalMode(WALMode.LOG_ONLY)
+            );
+
+        return cfg;
+    }
+
+    /**
+     * Check cache statistics enabled/disabled flag for all nodes
+     *
+     * @param cacheName Cache name.
+     * @param enabled Enabled.
+     */
+    private boolean checkStatisticsMode(String cacheName, boolean enabled) {
+        for (Ignite ignite : G.allGrids())
+            if (ignite.cache(cacheName).metrics().isStatisticsEnabled() != enabled) {
+                log.warning("Wrong cache statistics mode [grid=" + ignite.name() + ", cache=" + cacheName
+                    + ", expected=" + enabled);
+
+                return false;
+            }
+
+        return true;
+    }
+
+    /**
+     * @param enabled1 Statistics enabled for cache 1.
+     * @param enabled2 Statistics enabled for cache 2.
+     */
+    private void assertCachesStatisticsMode(final boolean enabled1, final boolean enabled2) throws IgniteInterruptedCheckedException {
+        assertTrue(GridTestUtils.waitForCondition(new GridAbsPredicate() {
+            @Override public boolean apply() {
+                return checkStatisticsMode(CACHE1, enabled1) && checkStatisticsMode(CACHE2, enabled2);
+            }
+        }, WAIT_CONDITION_TIMEOUT));
+    }
+
+    /**
+     * @param cacheMgr Cache manager.
+     * @param cacheName Cache name.
+     */
+    private boolean isStatisticsEnabled(CacheManager cacheMgr, String cacheName) {
+        return ((IgniteCache)cacheMgr.getCache(cacheName)).metrics().isStatisticsEnabled();
+    }
+}