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

mmuzaf pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 8619010cdc Reduce heap usage occupied by the metrics
8619010cdc is described below

commit 8619010cdca8bce471754e4fbeb861f036535007
Author: Maxim Muzafarov <maxmu...@gmail.com>
AuthorDate: Tue Apr 30 22:15:52 2024 +0200

    Reduce heap usage occupied by the metrics
    
    patch by Maxim Muzafarov; reviewed by Caleb Rackliffe for CASSANDRA-19567
---
 CHANGES.txt                                        |   1 +
 .../org/apache/cassandra/db/ColumnFamilyStore.java |  25 +-
 .../org/apache/cassandra/db/memtable/Memtable.java |  23 +-
 .../apache/cassandra/db/memtable/TrieMemtable.java |   7 +-
 .../db/virtual/walker/CounterMetricRowWalker.java  |  15 +-
 .../db/virtual/walker/GaugeMetricRowWalker.java    |  15 +-
 .../virtual/walker/HistogramMetricRowWalker.java   |  15 +-
 .../db/virtual/walker/MeterMetricRowWalker.java    |  15 +-
 .../db/virtual/walker/MetricGroupRowWalker.java    |  15 +-
 .../db/virtual/walker/MetricRowWalker.java         |  15 +-
 .../db/virtual/walker/ThreadPoolRowWalker.java     |  15 +-
 .../db/virtual/walker/TimerMetricRowWalker.java    |  15 +-
 .../index/sai/metrics/AbstractMetrics.java         |  27 +-
 .../index/sai/metrics/ColumnQueryMetrics.java      |  24 +-
 .../metrics/CassandraMetricsRegistry.java          | 272 +++++++--------------
 .../apache/cassandra/metrics/ClientMetrics.java    |   9 +-
 .../apache/cassandra/metrics/KeyspaceMetrics.java  |  55 ++---
 .../org/apache/cassandra/metrics/TableMetrics.java | 108 ++++----
 .../cassandra/metrics/TrieMemtableMetricsView.java |  42 ++--
 .../cassandra/service/NativeTransportService.java  |   1 +
 .../walker/CollectionEntryTestRowWalker.java       |  15 +-
 .../walker/PartitionEntryTestRowWalker.java        |  15 +-
 .../metrics/CassandraMetricsRegistryTest.java      |  48 ++--
 23 files changed, 349 insertions(+), 443 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index ed314c60d3..02509ad4dd 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Reduce heap usage occupied by the metrics (CASSANDRA-19567)
  * Improve handling of transient replicas during range movements 
(CASSANDRA-19344)
  * Enable debounced internode log requests to be cancelled at shutdown 
(CASSANDRA-19514)
  * Correctly set last modified epoch when combining multistep operations into 
a single step (CASSANDRA-19538)
diff --git a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java 
b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
index be6136dd4a..67ab079a1e 100644
--- a/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
+++ b/src/java/org/apache/cassandra/db/ColumnFamilyStore.java
@@ -90,14 +90,14 @@ import 
org.apache.cassandra.db.compaction.CompactionStrategyManager;
 import org.apache.cassandra.db.compaction.OperationType;
 import org.apache.cassandra.db.filter.ClusteringIndexFilter;
 import org.apache.cassandra.db.filter.DataLimits;
-import org.apache.cassandra.db.memtable.Flushing;
-import org.apache.cassandra.db.memtable.Memtable;
-import org.apache.cassandra.db.memtable.ShardBoundaries;
 import org.apache.cassandra.db.lifecycle.LifecycleNewTracker;
 import org.apache.cassandra.db.lifecycle.LifecycleTransaction;
 import org.apache.cassandra.db.lifecycle.SSTableSet;
 import org.apache.cassandra.db.lifecycle.Tracker;
 import org.apache.cassandra.db.lifecycle.View;
+import org.apache.cassandra.db.memtable.Flushing;
+import org.apache.cassandra.db.memtable.Memtable;
+import org.apache.cassandra.db.memtable.ShardBoundaries;
 import org.apache.cassandra.db.partitions.CachedPartition;
 import org.apache.cassandra.db.partitions.PartitionUpdate;
 import org.apache.cassandra.db.repair.CassandraTableRepairManager;
@@ -320,6 +320,7 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
     private final Directories directories;
 
     public final TableMetrics metric;
+    private final Runnable memtableMetricsReleaser;
     public volatile long sampleReadLatencyMicros;
     public volatile long additionalWriteLatencyMicros;
 
@@ -506,14 +507,11 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
 
         logger.info("Initializing {}.{}", getKeyspaceName(), name);
 
-        // Create Memtable and its metrics object only on online
-        Memtable initialMemtable = null;
-        TableMetrics.ReleasableMetric memtableMetrics = null;
-        if (DatabaseDescriptor.isDaemonInitialized())
-        {
-            initialMemtable = createMemtable(new 
AtomicReference<>(CommitLog.instance.getCurrentPosition()));
-            memtableMetrics = memtableFactory.createMemtableMetrics(metadata);
-        }
+        Memtable initialMemtable = DatabaseDescriptor.isDaemonInitialized() ?
+                                   createMemtable(new 
AtomicReference<>(CommitLog.instance.getCurrentPosition())) :
+                                   null;
+        memtableMetricsReleaser = 
memtableFactory.createMemtableMetricsReleaser(metadata);
+
         data = new Tracker(this, initialMemtable, loadSSTables);
 
         // Note that this needs to happen before we load the first sstables, 
or the global sstable tracker will not
@@ -545,7 +543,9 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
             indexManager.addIndex(info, true);
         }
 
-        metric = new TableMetrics(this, memtableMetrics);
+        // See CASSANDRA-16228. We need to ensure that metrics are exposed 
after the CFS is initialized,
+        // so the order of the following line is important and should not be 
moved.
+        metric = new TableMetrics(this);
 
         if (data.loadsstables)
         {
@@ -749,6 +749,7 @@ public class ColumnFamilyStore implements 
ColumnFamilyStoreMBean, Memtable.Owner
         }
 
         // unregister metrics
+        memtableMetricsReleaser.run();
         metric.release();
     }
 
diff --git a/src/java/org/apache/cassandra/db/memtable/Memtable.java 
b/src/java/org/apache/cassandra/db/memtable/Memtable.java
index 06dfe19976..f722ec20a9 100644
--- a/src/java/org/apache/cassandra/db/memtable/Memtable.java
+++ b/src/java/org/apache/cassandra/db/memtable/Memtable.java
@@ -19,7 +19,6 @@
 package org.apache.cassandra.db.memtable;
 
 import java.util.concurrent.atomic.AtomicReference;
-
 import javax.annotation.concurrent.NotThreadSafe;
 
 import org.apache.cassandra.db.ColumnFamilyStore;
@@ -33,7 +32,6 @@ import org.apache.cassandra.db.rows.EncodingStats;
 import org.apache.cassandra.db.rows.UnfilteredSource;
 import org.apache.cassandra.index.transactions.UpdateTransaction;
 import org.apache.cassandra.io.sstable.format.SSTableWriter;
-import org.apache.cassandra.metrics.TableMetrics;
 import org.apache.cassandra.schema.TableMetadata;
 import org.apache.cassandra.schema.TableMetadataRef;
 import org.apache.cassandra.utils.FBUtilities;
@@ -84,6 +82,16 @@ public interface Memtable extends Comparable<Memtable>, 
UnfilteredSource
          */
         Memtable create(AtomicReference<CommitLogPosition> 
commitLogLowerBound, TableMetadataRef metadaRef, Owner owner);
 
+        /**
+         * Create a release action for the memtable's metrics. This is used to 
release any resources that are not needed.
+         * @param metadataRef Pointer to the up-to-date table metadata.
+         * @return Runnable that releases the metrics resources.
+         */
+        default Runnable createMemtableMetricsReleaser(TableMetadataRef 
metadataRef)
+        {
+            return () -> {};
+        }
+
         /**
          * If the memtable can achieve write durability directly (i.e. using 
some feature other than the commitlog, e.g.
          * persistent memory), it can return true here, in which case the 
commit log will not store mutations in this
@@ -137,17 +145,6 @@ public interface Memtable extends Comparable<Memtable>, 
UnfilteredSource
         {
             return false;
         }
-
-        /**
-         * Override this method to include implementation-specific memtable 
metrics in the table metrics.
-         *
-         * Memtable metrics lifecycle matches table lifecycle. It is the table 
that owns the metrics and
-         * decides when to release them.
-         */
-        default TableMetrics.ReleasableMetric 
createMemtableMetrics(TableMetadataRef metadataRef)
-        {
-            return null;
-        }
     }
 
     /**
diff --git a/src/java/org/apache/cassandra/db/memtable/TrieMemtable.java 
b/src/java/org/apache/cassandra/db/memtable/TrieMemtable.java
index 83b02db06a..a8fc54b891 100644
--- a/src/java/org/apache/cassandra/db/memtable/TrieMemtable.java
+++ b/src/java/org/apache/cassandra/db/memtable/TrieMemtable.java
@@ -64,7 +64,6 @@ import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.index.transactions.UpdateTransaction;
 import org.apache.cassandra.io.compress.BufferType;
 import org.apache.cassandra.io.sstable.SSTableReadsListener;
-import org.apache.cassandra.metrics.TableMetrics;
 import org.apache.cassandra.metrics.TrieMemtableMetricsView;
 import org.apache.cassandra.schema.TableMetadata;
 import org.apache.cassandra.schema.TableMetadataRef;
@@ -679,10 +678,10 @@ public class TrieMemtable extends AbstractShardedMemtable
         }
 
         @Override
-        public TableMetrics.ReleasableMetric 
createMemtableMetrics(TableMetadataRef metadataRef)
+        public Runnable createMemtableMetricsReleaser(TableMetadataRef 
metadataRef)
         {
-            TrieMemtableMetricsView metrics = new 
TrieMemtableMetricsView(metadataRef.keyspace, metadataRef.name);
-            return metrics::release;
+            // Metrics are the same for all shards, so we can release them all 
at once.
+            return () -> TrieMemtableMetricsView.release(metadataRef.keyspace, 
metadataRef.name);
         }
 
         public boolean equals(Object o)
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/CounterMetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/CounterMetricRowWalker.java
index 8f6876afa3..7b8133eac2 100644
--- 
a/src/java/org/apache/cassandra/db/virtual/walker/CounterMetricRowWalker.java
+++ 
b/src/java/org/apache/cassandra/db/virtual/walker/CounterMetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/GaugeMetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/GaugeMetricRowWalker.java
index e510f33b5d..5d4b5da29a 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/GaugeMetricRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/GaugeMetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/HistogramMetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/HistogramMetricRowWalker.java
index 9347a0a715..3efafd99a9 100644
--- 
a/src/java/org/apache/cassandra/db/virtual/walker/HistogramMetricRowWalker.java
+++ 
b/src/java/org/apache/cassandra/db/virtual/walker/HistogramMetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/MeterMetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/MeterMetricRowWalker.java
index 3039bb924b..f5aeaa68ce 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/MeterMetricRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/MeterMetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/MetricGroupRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/MetricGroupRowWalker.java
index 0cb7c6f345..4327df7d22 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/MetricGroupRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/MetricGroupRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/MetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/MetricRowWalker.java
index f5e46c021b..84cda02398 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/MetricRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/MetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/ThreadPoolRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/ThreadPoolRowWalker.java
index 68cbc8c693..5435df9747 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/ThreadPoolRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/ThreadPoolRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/db/virtual/walker/TimerMetricRowWalker.java 
b/src/java/org/apache/cassandra/db/virtual/walker/TimerMetricRowWalker.java
index 418495e24b..e4e15ffe67 100644
--- a/src/java/org/apache/cassandra/db/virtual/walker/TimerMetricRowWalker.java
+++ b/src/java/org/apache/cassandra/db/virtual/walker/TimerMetricRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/src/java/org/apache/cassandra/index/sai/metrics/AbstractMetrics.java 
b/src/java/org/apache/cassandra/index/sai/metrics/AbstractMetrics.java
index b305720ebb..17fd99291c 100644
--- a/src/java/org/apache/cassandra/index/sai/metrics/AbstractMetrics.java
+++ b/src/java/org/apache/cassandra/index/sai/metrics/AbstractMetrics.java
@@ -17,14 +17,13 @@
  */
 package org.apache.cassandra.index.sai.metrics;
 
-import java.util.ArrayList;
-import java.util.List;
-
+import com.codahale.metrics.MetricRegistry;
 import org.apache.cassandra.index.sai.utils.IndexIdentifier;
 import org.apache.cassandra.metrics.CassandraMetricsRegistry;
 import org.apache.cassandra.metrics.DefaultNameFactory;
 
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 
 public abstract class AbstractMetrics
 {
@@ -34,7 +33,6 @@ public abstract class AbstractMetrics
     protected final String table;
     private final String index;
     private final String scope;
-    protected final List<String> tracked = new ArrayList<>();
 
     AbstractMetrics(IndexIdentifier indexIdentifier, String scope)
     {
@@ -57,8 +55,8 @@ public abstract class AbstractMetrics
 
     public void release()
     {
-        tracked.forEach(Metrics::remove);
-        tracked.clear();
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName,  
DefaultNameFactory.GROUP_NAME, TYPE, null),
+                              this::createMetricName, m -> {});
     }
 
     protected CassandraMetricsRegistry.MetricName createMetricName(String name)
@@ -68,17 +66,12 @@ public abstract class AbstractMetrics
 
     protected CassandraMetricsRegistry.MetricName createMetricName(String 
name, String scope)
     {
-        String metricScope = keyspace + '.' + table;
-        if (index != null)
-        {
-            metricScope += '.' + index;
-        }
-        metricScope += '.' + scope + '.' + name;
-
-        CassandraMetricsRegistry.MetricName metricName = new 
CassandraMetricsRegistry.MetricName(DefaultNameFactory.GROUP_NAME,
-                                                                               
                  TYPE, name, metricScope, createMBeanName(name, scope));
-        tracked.add(metricName.getMetricName());
-        return metricName;
+        assert name.indexOf('.') == -1 : String.format("Metric name '%s' 
should not contain '.'", name);
+        return new 
CassandraMetricsRegistry.MetricName(DefaultNameFactory.GROUP_NAME,
+                                                       TYPE,
+                                                       name,
+                                                       
MetricRegistry.name(keyspace, table, index, scope, name),
+                                                       createMBeanName(name, 
scope));
     }
 
     private String createMBeanName(String name, String scope)
diff --git 
a/src/java/org/apache/cassandra/index/sai/metrics/ColumnQueryMetrics.java 
b/src/java/org/apache/cassandra/index/sai/metrics/ColumnQueryMetrics.java
index f922231d0b..d2438510d9 100644
--- a/src/java/org/apache/cassandra/index/sai/metrics/ColumnQueryMetrics.java
+++ b/src/java/org/apache/cassandra/index/sai/metrics/ColumnQueryMetrics.java
@@ -27,6 +27,9 @@ import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
 
 public abstract class ColumnQueryMetrics extends AbstractMetrics
 {
+    private static final String POSTING_DECODES = "PostingDecodes";
+    private static final String NUM_POSTINGS = "NumPostings";
+
     protected ColumnQueryMetrics(IndexIdentifier indexIdentifier)
     {
         super(indexIdentifier, "ColumnQueryMetrics");
@@ -49,11 +52,18 @@ public abstract class ColumnQueryMetrics extends 
AbstractMetrics
 
             termsTraversalTotalTime = 
Metrics.timer(createMetricName("TermsLookupLatency"));
 
-            Meter postingDecodes = 
Metrics.meter(createMetricName("PostingDecodes", TRIE_POSTINGS_TYPE));
+            Meter postingDecodes = 
Metrics.meter(createMetricName(POSTING_DECODES, TRIE_POSTINGS_TYPE));
 
             postingsListener = new PostingListEventsMetrics(postingDecodes);
         }
 
+        @Override
+        public void release()
+        {
+            super.release();
+            Metrics.remove(createMetricName(POSTING_DECODES, 
TRIE_POSTINGS_TYPE));
+        }
+
         @Override
         public void onSegmentHit() { }
 
@@ -90,13 +100,21 @@ public abstract class ColumnQueryMetrics extends 
AbstractMetrics
             intersectionLatency = 
Metrics.timer(createMetricName("BalancedTreeIntersectionLatency"));
             intersectionEarlyExits = 
Metrics.meter(createMetricName("BalancedTreeIntersectionEarlyExits"));
 
-            postingsNumPostings = 
Metrics.meter(createMetricName("NumPostings", BALANCED_TREE_POSTINGS_TYPE));
+            postingsNumPostings = Metrics.meter(createMetricName(NUM_POSTINGS, 
BALANCED_TREE_POSTINGS_TYPE));
 
-            Meter postingDecodes = 
Metrics.meter(createMetricName("PostingDecodes", BALANCED_TREE_POSTINGS_TYPE));
+            Meter postingDecodes = 
Metrics.meter(createMetricName(POSTING_DECODES, BALANCED_TREE_POSTINGS_TYPE));
 
             postingsListener = new PostingListEventsMetrics(postingDecodes);
         }
 
+        @Override
+        public void release()
+        {
+            super.release();
+            Metrics.remove(createMetricName(NUM_POSTINGS, 
BALANCED_TREE_POSTINGS_TYPE));
+            Metrics.remove(createMetricName(POSTING_DECODES, 
BALANCED_TREE_POSTINGS_TYPE));
+        }
+
         @Override
         public void onIntersectionComplete(long intersectionTotalTime, 
TimeUnit unit)
         {
diff --git 
a/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java 
b/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java
index a687ff997e..2464533c99 100644
--- a/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java
+++ b/src/java/org/apache/cassandra/metrics/CassandraMetricsRegistry.java
@@ -21,27 +21,24 @@ import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import javax.annotation.Nullable;
 import javax.management.MalformedObjectNameException;
 import javax.management.ObjectName;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
-import org.apache.commons.lang3.ArrayUtils;
 
 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Gauge;
@@ -50,7 +47,6 @@ import com.codahale.metrics.Meter;
 import com.codahale.metrics.Metered;
 import com.codahale.metrics.Metric;
 import com.codahale.metrics.MetricRegistry;
-import com.codahale.metrics.MetricRegistryListener;
 import com.codahale.metrics.MetricSet;
 import com.codahale.metrics.Timer;
 import org.apache.cassandra.db.virtual.CollectionVirtualTableAdapter;
@@ -93,34 +89,14 @@ public class CassandraMetricsRegistry extends MetricRegistry
 {
     public static final UnaryOperator<String> METRICS_GROUP_POSTFIX = name -> 
name + "_group";
 
-    /**
-     * A map of metric name constructed by {@link 
com.codahale.metrics.MetricRegistry#name(String, String...)} and
-     * its full name in the way how it is represented in JMX. The map is used 
by {@link CassandraJmxMetricsExporter}
-     * to export metrics to JMX.
-     */
-    private static final ConcurrentMap<String, Deque<MetricName>> ALIASES = 
new ConcurrentHashMap<>();
-
     /** A set of all known metric groups, used to validate metric groups that 
are statically defined in Cassandra. */
     static final Set<String> metricGroups;
 
     /**
      * Root metrics registry that is used by Cassandra to store all metrics.
      * All modifications to the registry are delegated to the corresponding 
listeners as well.
-     * Metrics from the root registry are exported to JMX by {@link 
CassandraJmxMetricsExporter} and to virtual tables
-     * via {@link #createMetricsKeyspaceTables()}.
      */
-    public static final CassandraMetricsRegistry Metrics = init();
-    private final MetricRegistryListener jmxExporter = new 
CassandraJmxMetricsExporter(ALIASES);
-
-    /** We have to make sure that this metrics listener is called the last, so 
that it can clean up aliases. */
-    private final MetricRegistryListener housekeepingListener = new 
BaseMetricRegistryListener()
-    {
-        @Override
-        protected void onMetricRemove(String name)
-        {
-            ALIASES.remove(name);
-        }
-    };
+    public static final CassandraMetricsRegistry Metrics = new 
CassandraMetricsRegistry();
 
     private final Map<String, ThreadPoolMetrics> threadPoolMetrics = new 
ConcurrentHashMap<>();
     public static final String METRIC_SCOPE_UNDEFINED = "undefined";
@@ -181,15 +157,6 @@ public class CassandraMetricsRegistry extends 
MetricRegistry
     {
     }
 
-    private static CassandraMetricsRegistry init()
-    {
-        CassandraMetricsRegistry registry = new CassandraMetricsRegistry();
-        // Adding listeners to the root registry, so that they can be notified 
about all metrics changes.
-        registry.addListener(registry.jmxExporter);
-        registry.addListener(registry.housekeepingListener);
-        return registry;
-    }
-
     @SuppressWarnings("rawtypes")
     public static String getValueAsString(Metric metric)
     {
@@ -292,7 +259,7 @@ public class CassandraMetricsRegistry extends MetricRegistry
         return builder.build();
     }
 
-    private static void addUnknownMetric(MetricName newMetricName)
+    private static void verifyUnknownMetric(MetricName newMetricName)
     {
         String type = newMetricName.getType();
         if (type.indexOf('.') >= 0)
@@ -303,38 +270,39 @@ public class CassandraMetricsRegistry extends 
MetricRegistry
         if (!metricGroups.contains(newMetricName.getSystemViewName()))
             throw new IllegalStateException("Metric view name must match 
statically registered groups: " +
                                             newMetricName.getSystemViewName());
-
-        // We have to be sure that aliases are registered the same order as 
they are added to the registry.
-        ALIASES.computeIfAbsent(newMetricName.getMetricName(), k -> new 
LinkedList<>())
-               .add(newMetricName);
     }
 
-    private static void setAliases(MetricName... names)
+    public String getMetricScope(String metricName)
     {
-        
Arrays.asList(names).forEach(CassandraMetricsRegistry::addUnknownMetric);
-        ALIASES.get(names[0].getMetricName()).addAll(Arrays.asList(names));
+        int groupLen = DefaultNameFactory.GROUP_NAME.length();
+        int lastIndex = findNthIndexOf(metricName, groupLen, 2);
+        return metricName.length() <= groupLen || lastIndex == -1 ? 
METRIC_SCOPE_UNDEFINED :
+               metricName.substring(lastIndex + 1);
     }
 
-    public String getMetricScope(String metricName)
+    // Helper method to find the index of the nth occurrence of a specified 
character
+    private static int findNthIndexOf(String str, int start, int n)
     {
-        Deque<MetricName> deque = ALIASES.get(metricName);
-        return deque == null ? METRIC_SCOPE_UNDEFINED :
-               
deque.stream().findFirst().map(MetricName::getScope).orElse(METRIC_SCOPE_UNDEFINED);
+        int index = start;
+        while (n-- > 0)
+        {
+            index = str.indexOf('.', index + 1);
+            if (index == -1) break;
+        }
+        return index;
     }
 
     public Counter counter(MetricName... name)
     {
-        setAliases(name);
         Counter counter = super.counter(name[0].getMetricName());
-        Stream.of(name).skip(1).forEach(n -> register(n, counter));
+        Stream.of(name).forEach(n -> register(n, counter));
         return counter;
     }
 
     public Meter meter(MetricName... name)
     {
-        setAliases(name);
         Meter meter = super.meter(name[0].getMetricName());
-        Stream.of(name).skip(1).forEach(n -> register(n, meter));
+        Stream.of(name).forEach(n -> register(n, meter));
         return meter;
     }
 
@@ -345,19 +313,16 @@ public class CassandraMetricsRegistry extends 
MetricRegistry
 
     public Histogram histogram(MetricName name, MetricName alias, boolean 
considerZeroes)
     {
-        setAliases(name, alias);
         Histogram histogram = histogram(name, considerZeroes);
         register(alias, histogram);
         return histogram;
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    public <T extends Gauge> T gauge(MetricName name, MetricName alias, 
MetricSupplier<T> gauge)
+    public <T extends Gauge<?>> T gauge(MetricName name, MetricName alias, T 
gauge)
     {
-        setAliases(name, alias);
-        Gauge gaugeLoc = super.gauge(name.getMetricName(), gauge);
+        T gaugeLoc = register(name, gauge);
         register(alias, gaugeLoc);
-        return (T) gaugeLoc;
+        return gaugeLoc;
     }
 
     public Timer timer(MetricName name)
@@ -377,7 +342,6 @@ public class CassandraMetricsRegistry extends MetricRegistry
 
     public SnapshottingTimer timer(MetricName name, MetricName alias, TimeUnit 
durationUnit)
     {
-        setAliases(name, alias);
         SnapshottingTimer timer = timer(name, durationUnit);
         register(alias, timer);
         return timer;
@@ -411,7 +375,8 @@ public class CassandraMetricsRegistry extends MetricRegistry
 
         try
         {
-            addUnknownMetric(name);
+            verifyUnknownMetric(name);
+            registerMBean(metric, name.getMBeanName(), MBeanWrapper.instance);
             return super.register(name.getMetricName(), metric);
         }
         catch (IllegalArgumentException e)
@@ -444,30 +409,85 @@ public class CassandraMetricsRegistry extends 
MetricRegistry
 
     public <T extends Metric> T register(MetricName name, T metric, 
MetricName... aliases)
     {
-        setAliases(ArrayUtils.addAll(new MetricName[]{name}, aliases));
         T metricLoc = register(name, metric);
         Stream.of(aliases).forEach(n -> register(n, metricLoc));
         return metricLoc;
     }
 
+    /**
+     * Removes all metrics that match the given predicate.
+     *
+     * @param resolver a function that resolves a short metric name from a 
full metric name,
+     * or @{code null} if the metric should not be removed
+     * @param factory a function that creates a metric name from a short 
metric name.
+     * @param onRemoved a callback that is called for each removed metric.
+     */
+    public void removeIfMatch(MetricNameResolver resolver,
+                              Function<String, MetricName> factory,
+                              Consumer<MetricName> onRemoved)
+    {
+        removeMatching((full, metric) -> {
+            String shortName = resolver.resolve(full);
+            if (shortName == null)
+                return false;
+
+            MetricName metricName = factory.apply(shortName);
+            boolean remove = metricName.getMetricName().equals(full);
+
+            if (remove)
+            {
+                unregisterMBean(metricName.getMBeanName(), 
MBeanWrapper.instance);
+                onRemoved.accept(metricName);
+            }
+            return remove;
+        });
+    }
+
+    /**
+     * Default implementation of the {@link MetricNameResolver} that resolves 
a short metric name from a full metric name,
+     * assuming that the full metric name doesn't contain dots. Returns {@code 
null} if the full metric name doesn't match
+     * the provided group and type.
+     * <p>
+     * The {@code scope} is the last part of the full metric name. Can be 
{@code null} and it's used for search efficiency.
+     *
+     * @param fullName full metric name
+     * @param group metric group
+     * @param type metric type
+     * @param scope metric scope, which is the last part of the full metric 
name and used for search efficiency.
+     * @return short metric name or {@code null} if the full metric name 
doesn't match the group, type, and scope.
+     */
+    public static @Nullable String resolveShortMetricName(String fullName, 
String group, String type, @Nullable String scope)
+    {
+        String prefix = name(group, type);
+        if (fullName.startsWith(prefix))
+        {
+            int lastDot = fullName.indexOf('.', prefix.length() + 1);
+            // If a metric scope is null (dots not found), the metric name is 
the last part of the full metric name.
+            if (lastDot == -1)
+                return fullName.substring(prefix.length() + 1);
+
+            if (scope == null)
+                return fullName.substring(prefix.length() + 1, lastDot);
+
+            return fullName.substring(lastDot + 1).equals(scope) ?
+                   fullName.substring(prefix.length() + 1, lastDot) :
+                   null;
+        }
+
+        return null;
+    }
+
     public void remove(MetricName name)
     {
-        // Aliases are removed in onMetricRemoved by metrics listener.
-        remove(name.getMetricName());
+        boolean success = remove(name.getMetricName());
+        if (success)
+            unregisterMBean(name.getMBeanName(), MBeanWrapper.instance);
     }
 
-    public boolean remove(String name)
+    @FunctionalInterface
+    public interface MetricNameResolver
     {
-        LinkedList<String> delete = ofNullable(ALIASES.get(name))
-                                        .map(s -> 
s.stream().map(MetricName::getMetricName)
-                                                   
.collect(Collectors.toCollection(LinkedList::new)))
-                                        .orElse(new 
LinkedList<>(Collections.singletonList(name)));
-        // Aliases are removed in onMetricRemoved by metrics listener.
-        Iterator<String> iter = delete.descendingIterator();
-        boolean removed = true;
-        while (iter.hasNext())
-            removed &= super.remove(iter.next());
-        return removed;
+        @Nullable String resolve(String fullName);
     }
 
     private void registerMBean(Metric metric, ObjectName name, MBeanWrapper 
mBeanServer)
@@ -1244,106 +1264,4 @@ public class CassandraMetricsRegistry extends 
MetricRegistry
             return name;
         }
     }
-
-    private static class CassandraJmxMetricsExporter extends 
BaseMetricRegistryListener
-    {
-        private final MBeanWrapper mBeanWrapper = MBeanWrapper.instance;
-        private final Map<String, Deque<MetricName>> aliases;
-
-        public CassandraJmxMetricsExporter(Map<String, Deque<MetricName>> 
aliases)
-        {
-            this.aliases = aliases;
-        }
-
-        protected void onMetricAdded(String name, Metric metric)
-        {
-            Deque<MetricName> deque = aliases.get(name);
-            if (deque == null)
-                return;
-
-            assert deque.getFirst().getMetricName().equals(name);
-            Metrics.registerMBean(metric, deque.getFirst().getMBeanName(), 
mBeanWrapper);
-        }
-
-        protected void onMetricRemove(String name)
-        {
-            Deque<MetricName> deque = aliases.get(name);
-            if (deque == null)
-                return;
-
-            assert deque.getFirst().getMetricName().equals(name);
-            Metrics.unregisterMBean(deque.getFirst().getMBeanName(), 
mBeanWrapper);
-        }
-    }
-
-    private static abstract class BaseMetricRegistryListener implements 
MetricRegistryListener
-    {
-        protected void onMetricAdded(String name, Metric metric)
-        {
-        }
-
-        protected void onMetricRemove(String name)
-        {
-        }
-
-        @Override
-        public void onGaugeAdded(String metricName, Gauge<?> gauge)
-        {
-            onMetricAdded(metricName, gauge);
-        }
-
-        @Override
-        public void onGaugeRemoved(String metricName)
-        {
-            onMetricRemove(metricName);
-        }
-
-        @Override
-        public void onCounterAdded(String metricName, Counter counter)
-        {
-            onMetricAdded(metricName, counter);
-        }
-
-        @Override
-        public void onCounterRemoved(String metricName)
-        {
-            onMetricRemove(metricName);
-        }
-
-        @Override
-        public void onHistogramAdded(String metricName, Histogram histogram)
-        {
-            onMetricAdded(metricName, histogram);
-        }
-
-        @Override
-        public void onHistogramRemoved(String metricName)
-        {
-            onMetricRemove(metricName);
-        }
-
-        @Override
-        public void onMeterAdded(String metricName, Meter meter)
-        {
-            onMetricAdded(metricName, meter);
-        }
-
-        @Override
-        public void onMeterRemoved(String metricName)
-        {
-            onMetricRemove(metricName);
-        }
-
-        @Override
-        public void onTimerAdded(String metricName, Timer timer)
-        {
-            onMetricAdded(metricName, timer);
-        }
-
-        @Override
-        public void onTimerRemoved(String metricName)
-        {
-            onMetricRemove(metricName);
-        }
-    }
 }
diff --git a/src/java/org/apache/cassandra/metrics/ClientMetrics.java 
b/src/java/org/apache/cassandra/metrics/ClientMetrics.java
index 1a465506a6..4e7f5a1b06 100644
--- a/src/java/org/apache/cassandra/metrics/ClientMetrics.java
+++ b/src/java/org/apache/cassandra/metrics/ClientMetrics.java
@@ -44,6 +44,7 @@ import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.transport.ServerConnection;
 
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 
 public final class ClientMetrics
 {
@@ -283,7 +284,7 @@ public final class ClientMetrics
 
     private <T> Gauge<T> registerGauge(String name, String deprecated, 
Gauge<T> gauge)
     {
-        return Metrics.gauge(factory.createMetricName(name), 
factory.createMetricName(deprecated), () -> gauge);
+        return Metrics.gauge(factory.createMetricName(name), 
factory.createMetricName(deprecated), gauge);
     }
 
     private Meter registerMeter(String name)
@@ -295,4 +296,10 @@ public final class ClientMetrics
     {
         return Metrics.meter(metricNameFactory.createMetricName(name));
     }
+
+    public void release()
+    {
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName, 
DefaultNameFactory.GROUP_NAME, TYPE_NAME, null),
+                              factory::createMetricName, m -> {});
+    }
 }
diff --git a/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java 
b/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java
index 83a1651fa7..237fd03e2d 100644
--- a/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java
+++ b/src/java/org/apache/cassandra/metrics/KeyspaceMetrics.java
@@ -17,11 +17,9 @@
  */
 package org.apache.cassandra.metrics;
 
-import java.util.Set;
 import java.util.function.ToLongFunction;
 
 import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Sets;
 
 import com.codahale.metrics.Counter;
 import com.codahale.metrics.Gauge;
@@ -34,9 +32,9 @@ import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.io.sstable.GaugeProvider;
 import org.apache.cassandra.io.sstable.format.SSTableFormat;
 import org.apache.cassandra.metrics.CassandraMetricsRegistry.MetricName;
-import org.apache.cassandra.metrics.TableMetrics.ReleasableMetric;
 
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 
 /**
  * Metrics for {@link ColumnFamilyStore}.
@@ -185,12 +183,9 @@ public class KeyspaceMetrics
 
     public final ImmutableMap<SSTableFormat<?, ?>, ImmutableMap<String, 
Gauge<? extends Number>>> formatSpecificGauges;
 
-    public final MetricNameFactory factory;
+    private final KeyspaceMetricNameFactory factory;
     private final Keyspace keyspace;
 
-    /** set containing names of all the metrics stored here, for releasing 
later */
-    private Set<ReleasableMetric> allMetrics = Sets.newHashSet();
-
     /**
      * Creates metrics for given {@link ColumnFamilyStore}.
      *
@@ -300,10 +295,11 @@ public class KeyspaceMetrics
      */
     public void release()
     {
-        for (ReleasableMetric metric : allMetrics)
-        {
-            metric.release();
-        }
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName,
+                                                                 
KeyspaceMetricNameFactory.GROUP_NAME,
+                                                                 TYPE_NAME,
+                                                                 
factory.scope()),
+                              factory::createMetricName, m -> {});
     }
 
     private ImmutableMap<SSTableFormat<?, ?>, ImmutableMap<String, Gauge<? 
extends Number>>> createFormatSpecificGauges(Keyspace keyspace)
@@ -315,7 +311,6 @@ public class KeyspaceMetrics
             for (GaugeProvider<?> gaugeProvider : 
format.getFormatSpecificMetricsProviders().getGaugeProviders())
             {
                 String finalName = gaugeProvider.name;
-                allMetrics.add(() -> releaseMetric(finalName));
                 Gauge<? extends Number> gauge = 
Metrics.register(factory.createMetricName(finalName), 
gaugeProvider.getKeyspaceGauge(keyspace));
                 gauges.put(gaugeProvider.name, gauge);
             }
@@ -334,7 +329,6 @@ public class KeyspaceMetrics
      */
     private Gauge<Long> createKeyspaceGauge(String name, final 
ToLongFunction<TableMetrics> extractor)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.register(factory.createMetricName(name), new 
Gauge<Long>()
         {
             public Long getValue()
@@ -357,7 +351,6 @@ public class KeyspaceMetrics
      */
     private Counter createKeyspaceCounter(String name, final 
ToLongFunction<TableMetrics> extractor)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.register(factory.createMetricName(name), new Counter()
         {
             @Override
@@ -375,42 +368,32 @@ public class KeyspaceMetrics
 
     protected Counter createKeyspaceCounter(String name)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.counter(factory.createMetricName(name));
     }
 
     protected Histogram createKeyspaceHistogram(String name, boolean 
considerZeroes)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.histogram(factory.createMetricName(name), 
considerZeroes);
     }
 
     protected Timer createKeyspaceTimer(String name)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.timer(factory.createMetricName(name));
     }
 
     protected Meter createKeyspaceMeter(String name)
     {
-        allMetrics.add(() -> releaseMetric(name));
         return Metrics.meter(factory.createMetricName(name));
     }
 
     private LatencyMetrics createLatencyMetrics(String name)
     {
-        LatencyMetrics metric = new LatencyMetrics(factory, name);
-        allMetrics.add(() -> metric.release());
-        return metric;
-    }
-
-    private void releaseMetric(String name)
-    {
-        Metrics.remove(factory.createMetricName(name));
+        return new LatencyMetrics(factory, name);
     }
 
     static class KeyspaceMetricNameFactory implements MetricNameFactory
     {
+        public static final String GROUP_NAME = 
TableMetrics.class.getPackage().getName();
         private final String keyspaceName;
 
         KeyspaceMetricNameFactory(Keyspace ks)
@@ -418,18 +401,20 @@ public class KeyspaceMetrics
             this.keyspaceName = ks.getName();
         }
 
+        public String scope()
+        {
+            return keyspaceName;
+        }
+
         @Override
         public MetricName createMetricName(String metricName)
         {
-            String groupName = TableMetrics.class.getPackage().getName();
-
-            StringBuilder mbeanName = new StringBuilder();
-            mbeanName.append(groupName).append(":");
-            mbeanName.append("type=").append("Keyspace");
-            mbeanName.append(",keyspace=").append(keyspaceName);
-            mbeanName.append(",name=").append(metricName);
-
-            return new MetricName(groupName, TYPE_NAME, metricName, 
keyspaceName, mbeanName.toString());
+            assert metricName.indexOf('.') == -1 : String.format("Metric name 
'%s' should not contain '.'", metricName);
+            return new MetricName(GROUP_NAME, TYPE_NAME, metricName, scope(),
+                                  GROUP_NAME + ':' +
+                                  "type=" + "Keyspace" +
+                                  ",keyspace=" + scope() +
+                                  ",name=" + metricName);
         }
     }
 }
diff --git a/src/java/org/apache/cassandra/metrics/TableMetrics.java 
b/src/java/org/apache/cassandra/metrics/TableMetrics.java
index 7ab1cbbfbf..ab1ab6eb73 100644
--- a/src/java/org/apache/cassandra/metrics/TableMetrics.java
+++ b/src/java/org/apache/cassandra/metrics/TableMetrics.java
@@ -23,6 +23,7 @@ import java.util.Arrays;
 import java.util.EnumMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -33,7 +34,6 @@ import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.apache.commons.lang3.ArrayUtils;
 
 import com.codahale.metrics.Counter;
@@ -64,6 +64,7 @@ import org.apache.cassandra.utils.Pair;
 
 import static java.util.concurrent.TimeUnit.MICROSECONDS;
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 import static org.apache.cassandra.utils.Clock.Global.nanoTime;
 
 /**
@@ -216,8 +217,8 @@ public class TableMetrics
     public final Timer coordinatorScanLatency;
     public final SnapshottingTimer coordinatorWriteLatency;
 
-    private final MetricNameFactory factory;
-    private final MetricNameFactory aliasFactory;
+    private final TableMetricNameFactory factory;
+    private final TableMetricNameFactory aliasFactory;
 
     public final Counter speculativeRetries;
     public final Counter speculativeFailedRetries;
@@ -357,11 +358,6 @@ public class TableMetrics
 
     public final EnumMap<SamplerType, Sampler<?>> samplers;
 
-    /**
-     * Stores all metrics created that can be used when unregistering
-     */
-    private final Set<ReleasableMetric> all = Sets.newHashSet();
-
     private interface GetHistogram
     {
         EstimatedHistogram getHistogram(SSTableReader reader);
@@ -405,16 +401,11 @@ public class TableMetrics
      *
      * @param cfs ColumnFamilyStore to measure metrics
      */
-    public TableMetrics(final ColumnFamilyStore cfs, ReleasableMetric 
memtableMetrics)
+    public TableMetrics(final ColumnFamilyStore cfs)
     {
         factory = new TableMetricNameFactory(cfs, cfs.isIndex() ? 
INDEX_TYPE_NAME : TYPE_NAME);
         aliasFactory = new TableMetricNameFactory(cfs, cfs.isIndex() ? 
INDEX_ALIAS_TYPE_NAME : ALIAS_TYPE_NAME);
 
-        if (memtableMetrics != null)
-        {
-            all.add(memtableMetrics);
-        }
-
         samplers = new EnumMap<>(SamplerType.class);
         topReadPartitionFrequency = new FrequencySampler<ByteBuffer>()
         {
@@ -894,10 +885,14 @@ public class TableMetrics
      */
     public void release()
     {
-        for (ReleasableMetric entry : all)
-        {
-            entry.release();
-        }
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName, 
TableMetricNameFactory.GROUP_NAME,
+                                                                 
factory.type(),
+                                                                 
factory.scope()),
+                              factory::createMetricName, this::releaseMetric);
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName, 
TableMetricNameFactory.GROUP_NAME,
+                                                                 
aliasFactory.type(),
+                                                                 
aliasFactory.scope()),
+                              aliasFactory::createMetricName, 
this::releaseMetric);
     }
 
     private ImmutableMap<SSTableFormat<?, ?>, ImmutableMap<String, Gauge<? 
extends Number>>> createFormatSpecificGauges(ColumnFamilyStore cfs)
@@ -1065,18 +1060,6 @@ public class TableMetrics
                                                     considerZeroes));
     }
 
-    protected Histogram createTableHistogram(String name, boolean 
considerZeroes)
-    {
-        return createTableHistogram(name, name, considerZeroes);
-    }
-
-    protected Histogram createTableHistogram(String name, String alias, 
boolean considerZeroes)
-    {
-        Histogram tableHistogram = 
Metrics.histogram(factory.createMetricName(name), 
aliasFactory.createMetricName(alias), considerZeroes);
-        register(name, alias, tableHistogram);
-        return tableHistogram;
-    }
-
     protected TableTimer createTableTimer(String name, Timer keyspaceTimer)
     {
         Timer cfTimer = Metrics.timer(factory.createMetricName(name), 
aliasFactory.createMetricName(name));
@@ -1110,9 +1093,8 @@ public class TableMetrics
 
     private LatencyMetrics createLatencyMetrics(String namePrefix, 
LatencyMetrics ... parents)
     {
-        LatencyMetrics metric = new LatencyMetrics(factory, namePrefix, 
parents);
-        all.add(metric::release);
-        return metric;
+        // All metrics which are registered with the same factory type will be 
removed when release() is called.
+        return new LatencyMetrics(factory, namePrefix, parents);
     }
 
     /**
@@ -1137,22 +1119,16 @@ public class TableMetrics
     {
         boolean ret = ALL_TABLE_METRICS.putIfAbsent(name, 
ConcurrentHashMap.newKeySet()) == null;
         ALL_TABLE_METRICS.get(name).add(metric);
-        all.add(() -> releaseMetric(name, alias, deprecated));
         return ret;
     }
 
-    private void releaseMetric(String tableMetricName, String cfMetricName, 
String tableMetricAlias)
+    private void releaseMetric(CassandraMetricsRegistry.MetricName name)
     {
-        CassandraMetricsRegistry.MetricName name = 
factory.createMetricName(tableMetricName);
+        Metric metric = Metrics.getMetrics().get(name.getMetricName());
+        if (metric == null)
+            return;
 
-        final Metric metric = Metrics.getMetrics().get(name.getMetricName());
-        if (metric != null)
-        {
-            // Metric will be null if we are releasing a view metric.  Views 
have null for ViewLockAcquireTime and ViewLockReadTime
-            ALL_TABLE_METRICS.get(tableMetricName).remove(metric);
-            // Aliases are already known to the parent metrics, so we don't 
need to remove them here.
-            Metrics.remove(name);
-        }
+        
Optional.ofNullable(ALL_TABLE_METRICS.get(name.getName())).ifPresent(set -> 
set.remove(metric));
     }
 
     public static class TableMeter
@@ -1247,6 +1223,7 @@ public class TableMetrics
 
     static class TableMetricNameFactory implements MetricNameFactory
     {
+        public static final String GROUP_NAME = 
TableMetrics.class.getPackage().getName();
         private final String keyspaceName;
         private final String tableName;
         private final String type;
@@ -1258,23 +1235,31 @@ public class TableMetrics
             this.type = type;
         }
 
-        public CassandraMetricsRegistry.MetricName createMetricName(String 
metricName)
+        public String type()
         {
-            String groupName = TableMetrics.class.getPackage().getName();
+            return type;
+        }
 
-            StringBuilder mbeanName = new StringBuilder();
-            mbeanName.append(groupName).append(":");
-            mbeanName.append("type=").append(type);
-            mbeanName.append(",keyspace=").append(keyspaceName);
-            mbeanName.append(",scope=").append(tableName);
-            mbeanName.append(",name=").append(metricName);
+        public String scope()
+        {
+            return keyspaceName + '.' + tableName;
+        }
 
-            return new CassandraMetricsRegistry.MetricName(groupName, type, 
metricName, keyspaceName + "." + tableName, mbeanName.toString());
+        public CassandraMetricsRegistry.MetricName createMetricName(String 
metricName)
+        {
+            assert metricName.indexOf('.') == -1 : String.format("Metric name 
must not contain '.' character (got '%s')", metricName);
+            return new CassandraMetricsRegistry.MetricName(GROUP_NAME, type, 
metricName, scope(),
+                                                           GROUP_NAME + ':' +
+                                                           "type=" + type +
+                                                           ",keyspace=" + 
keyspaceName +
+                                                           ",scope=" + 
tableName +
+                                                           ",name=" + 
metricName);
         }
     }
 
     static class AllTableMetricNameFactory implements MetricNameFactory
     {
+        private static final String GROUP_NAME = 
TableMetrics.class.getPackage().getName();
         private final String type;
         public AllTableMetricNameFactory(String type)
         {
@@ -1283,21 +1268,14 @@ public class TableMetrics
 
         public CassandraMetricsRegistry.MetricName createMetricName(String 
metricName)
         {
-            String groupName = TableMetrics.class.getPackage().getName();
-            StringBuilder mbeanName = new StringBuilder();
-            mbeanName.append(groupName).append(":");
-            mbeanName.append("type=").append(type);
-            mbeanName.append(",name=").append(metricName);
-            return new CassandraMetricsRegistry.MetricName(groupName, type, 
metricName, "all", mbeanName.toString());
+            assert metricName.indexOf('.') == -1 : String.format("Metric name 
must not contain '.' character (got '%s')", metricName);
+            return new CassandraMetricsRegistry.MetricName(GROUP_NAME, type, 
metricName, "all",
+                                                           GROUP_NAME + ':' +
+                                                           "type=" + type +
+                                                           ",name=" + 
metricName);
         }
     }
 
-    @FunctionalInterface
-    public interface ReleasableMetric
-    {
-        void release();
-    }
-
     private static class GlobalTableGauge implements Gauge<Long>
     {
         private final String name;
diff --git a/src/java/org/apache/cassandra/metrics/TrieMemtableMetricsView.java 
b/src/java/org/apache/cassandra/metrics/TrieMemtableMetricsView.java
index a308fbbab8..e012540439 100644
--- a/src/java/org/apache/cassandra/metrics/TrieMemtableMetricsView.java
+++ b/src/java/org/apache/cassandra/metrics/TrieMemtableMetricsView.java
@@ -20,9 +20,15 @@ package org.apache.cassandra.metrics;
 
 import com.codahale.metrics.Counter;
 
+import static com.codahale.metrics.MetricRegistry.name;
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 import static org.apache.cassandra.metrics.DefaultNameFactory.GROUP_NAME;
 
+/**
+ * Metrics for TrieMemtable, the metrics are shared across all memtables in a 
single column family and
+ * are updated by all memtables in the column family.
+ */
 public class TrieMemtableMetricsView
 {
     public static final String TYPE_NAME = "TrieMemtable";
@@ -43,11 +49,9 @@ public class TrieMemtableMetricsView
     // shard sizes distribution
     public final MinMaxAvgMetric lastFlushShardDataSizes;
 
-    private final TrieMemtableMetricNameFactory factory;
-
     public TrieMemtableMetricsView(String keyspace, String table)
     {
-        factory = new TrieMemtableMetricNameFactory(keyspace, table);
+        MetricNameFactory factory = new 
TrieMemtableMetricNameFactory(keyspace, table);
         
         uncontendedPuts = 
Metrics.counter(factory.createMetricName(UNCONTENDED_PUTS));
         contendedPuts = 
Metrics.counter(factory.createMetricName(CONTENDED_PUTS));
@@ -55,15 +59,15 @@ public class TrieMemtableMetricsView
         lastFlushShardDataSizes = new MinMaxAvgMetric(factory, 
LAST_FLUSH_SHARD_SIZES);
     }
 
-    public void release()
+    public static void release(String keyspace, String table)
     {
-        Metrics.remove(factory.createMetricName(UNCONTENDED_PUTS));
-        Metrics.remove(factory.createMetricName(CONTENDED_PUTS));
-        contentionTime.release();
-        lastFlushShardDataSizes.release();
+        TrieMemtableMetricNameFactory factory = new 
TrieMemtableMetricNameFactory(keyspace, table);
+        Metrics.removeIfMatch(fullName -> resolveShortMetricName(fullName, 
GROUP_NAME, TYPE_NAME, factory.scope()),
+                              factory::createMetricName,
+                              m -> {});
     }
 
-    static class TrieMemtableMetricNameFactory implements MetricNameFactory
+    private static class TrieMemtableMetricNameFactory implements 
MetricNameFactory
     {
         private final String keyspace;
         private final String table;
@@ -74,16 +78,20 @@ public class TrieMemtableMetricsView
             this.table = table;
         }
 
-        public CassandraMetricsRegistry.MetricName createMetricName(String 
metricName)
+        public String scope()
         {
-            StringBuilder mbeanName = new StringBuilder();
-            mbeanName.append(GROUP_NAME).append(":");
-            mbeanName.append("type=").append(TYPE_NAME);
-            mbeanName.append(",keyspace=").append(keyspace);
-            mbeanName.append(",scope=").append(table);
-            mbeanName.append(",name=").append(metricName);
+            return name(keyspace, table);
+        }
 
-            return new CassandraMetricsRegistry.MetricName(GROUP_NAME, 
TYPE_NAME, metricName, keyspace + '.' + table, mbeanName.toString());
+        public CassandraMetricsRegistry.MetricName createMetricName(String 
metricName)
+        {
+            assert metricName.indexOf('.') == -1 : "metricName should not 
contain '.'; got " + metricName;
+            return new CassandraMetricsRegistry.MetricName(GROUP_NAME, 
TYPE_NAME, metricName, scope(),
+                                                           GROUP_NAME + ':' +
+                                                           "type=" + TYPE_NAME 
+
+                                                           ",keyspace=" + 
keyspace +
+                                                           ",scope=" + table +
+                                                           ",name=" + 
metricName);
         }
     }
 }
diff --git a/src/java/org/apache/cassandra/service/NativeTransportService.java 
b/src/java/org/apache/cassandra/service/NativeTransportService.java
index cfbc638afe..6fa89bab39 100644
--- a/src/java/org/apache/cassandra/service/NativeTransportService.java
+++ b/src/java/org/apache/cassandra/service/NativeTransportService.java
@@ -112,6 +112,7 @@ public class NativeTransportService
     public void destroy()
     {
         stop();
+        ClientMetrics.instance.release();
         server = null;
 
         // shutdown executors used by netty for native transport server
diff --git 
a/test/unit/org/apache/cassandra/db/virtual/walker/CollectionEntryTestRowWalker.java
 
b/test/unit/org/apache/cassandra/db/virtual/walker/CollectionEntryTestRowWalker.java
index f6ea8d6904..5169e96561 100644
--- 
a/test/unit/org/apache/cassandra/db/virtual/walker/CollectionEntryTestRowWalker.java
+++ 
b/test/unit/org/apache/cassandra/db/virtual/walker/CollectionEntryTestRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/test/unit/org/apache/cassandra/db/virtual/walker/PartitionEntryTestRowWalker.java
 
b/test/unit/org/apache/cassandra/db/virtual/walker/PartitionEntryTestRowWalker.java
index 241f3b68df..e5fb014154 100644
--- 
a/test/unit/org/apache/cassandra/db/virtual/walker/PartitionEntryTestRowWalker.java
+++ 
b/test/unit/org/apache/cassandra/db/virtual/walker/PartitionEntryTestRowWalker.java
@@ -1,12 +1,13 @@
 /*
- * 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
+ * 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
  *
- *      https://www.apache.org/licenses/LICENSE-2.0
+ *     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,
diff --git 
a/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java 
b/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java
index 897265ef4d..b069d0330f 100644
--- a/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java
+++ b/test/unit/org/apache/cassandra/metrics/CassandraMetricsRegistryTest.java
@@ -29,7 +29,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.UUID;
-import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -38,7 +37,6 @@ import org.junit.Test;
 
 import com.codahale.metrics.Meter;
 import com.codahale.metrics.Metric;
-import com.codahale.metrics.MetricRegistryListener;
 import com.codahale.metrics.Timer;
 import com.codahale.metrics.jvm.BufferPoolMetricSet;
 import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
@@ -46,6 +44,8 @@ import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
 import org.apache.cassandra.metrics.CassandraMetricsRegistry.MetricName;
 import org.apache.cassandra.utils.EstimatedHistogram;
 
+import static com.codahale.metrics.MetricRegistry.name;
+import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.resolveShortMetricName;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -186,34 +186,18 @@ public class CassandraMetricsRegistryTest
     }
 
     @Test
-    public void testMetricAliasesOrder()
+    public void testMetricAliasesRemoveByCondition()
     {
-        String dummy = "defaultName";
         LinkedList<MetricName> aliases = new LinkedList<>();
-        int size = ThreadLocalRandom.current().nextInt(10, 1000);
-        MetricName first = DefaultNameFactory.createMetricName("Table", 
"FirstTestMetricAliasesOrder", "FirstScope");
+        int size = 10;
+        DefaultNameFactory factory = new DefaultNameFactory("Table", 
"FirstScope");
+        DefaultNameFactory aliasFactory = new DefaultNameFactory("Table", 
"SecondScope");
+        MetricName first = 
factory.createMetricName("FirstTestMetricAliasesOrder");
         for (int i = 0; i < size; i++)
-            aliases.add(DefaultNameFactory.createMetricName("Table", 
"FirstTestMetricAliasesOrder" + UUID.randomUUID(),
-                                                            
UUID.randomUUID().toString()));
-
-        Meter metric = CassandraMetricsRegistry.Metrics.meter(dummy);
-        LinkedList<MetricName> verify = new LinkedList<>(aliases);
-        verify.addFirst(first);
-        MetricRegistryListener listener;
-        CassandraMetricsRegistry.Metrics.addListener(listener = new 
MetricRegistryListener.Base()
-        {
-            @Override
-            public void onMeterAdded(String name, Meter meter)
-            {
-                if (dummy.equals(name))
-                    return;
+            
aliases.add(aliasFactory.createMetricName("AliasFirstTestMetricAliasesOrder_" + 
UUID.randomUUID()));
 
-                assertEquals(verify.removeFirst().getMetricName(), name);
-            }
-        });
+        Meter metric = CassandraMetricsRegistry.Metrics.meter(first);
         CassandraMetricsRegistry.Metrics.register(first, metric, 
aliases.toArray(new MetricName[size]));
-        CassandraMetricsRegistry.Metrics.removeListener(listener);
-
         List<String> all = 
CassandraMetricsRegistry.Metrics.getMetrics().keySet().
                                                            stream()
                                                            .filter(m -> 
m.contains("FirstTestMetricAliasesOrder"))
@@ -222,12 +206,18 @@ public class CassandraMetricsRegistryTest
         assertNotNull(all);
         assertEquals(size + 1, all.size());
 
-        CassandraMetricsRegistry.Metrics.remove(first.getMetricName());
+        CassandraMetricsRegistry.Metrics.removeIfMatch(fullName ->
+                                                           
resolveShortMetricName(fullName, DefaultNameFactory.GROUP_NAME, "Table", null),
+                                                       
factory::createMetricName,
+                                                       m -> {});
         Map<String, Metric> metrics = 
CassandraMetricsRegistry.Metrics.getMetrics();
-        assertEquals(1, metrics.size());
-        assertEquals(dummy, metrics.keySet().iterator().next());
+        assertEquals(size, metrics.size());
+        assertTrue(metrics.keySet().stream().allMatch(m -> 
m.startsWith(name(DefaultNameFactory.GROUP_NAME, "Table", 
"AliasFirstTestMetricAliasesOrder_"))));
 
-        CassandraMetricsRegistry.Metrics.remove(dummy);
+        CassandraMetricsRegistry.Metrics.removeIfMatch(fullName ->
+                                                           
resolveShortMetricName(fullName, DefaultNameFactory.GROUP_NAME, "Table", null),
+                                                       
aliasFactory::createMetricName,
+                                                       m -> {});
         assertTrue(CassandraMetricsRegistry.Metrics.getMetrics().isEmpty());
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to