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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]