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

smiklosovic 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 64e2a4e9a3 Refactor structure of caching metrics and expose auth cache 
metrics via JMX
64e2a4e9a3 is described below

commit 64e2a4e9a3e209cc6153c0e348ba7f3d56a7016f
Author: Aleksei Zotov <azotc...@gmail.com>
AuthorDate: Thu Jan 25 17:27:08 2024 +0100

    Refactor structure of caching metrics and expose auth cache metrics via JMX
    
    patch by Aleksei Zotov; reviewed by Stefan Miklosovic, Maxim Muzafarov for 
CASSANDRA-17062
    
    Co-authored-by: Sam Tunnicliffe <s...@apache.org>
    Co-authored-by: Stefan Miklosovic <smikloso...@apache.org>
---
 CHANGES.txt                                        |   1 +
 .../pages/managing/operating/metrics.adoc          |  64 +++++++++-
 src/java/org/apache/cassandra/auth/AuthCache.java  |  67 ++++++++++-
 src/java/org/apache/cassandra/cache/CacheSize.java |  20 +++-
 .../org/apache/cassandra/cache/ChunkCache.java     |   5 +-
 .../{CacheSize.java => UnweightedCacheSize.java}   |  27 +++--
 ...CacheMetrics.java => AbstractCacheMetrics.java} |  83 +++++++------
 .../org/apache/cassandra/metrics/CacheMetrics.java |  76 ++----------
 .../cassandra/metrics/UnweightedCacheMetrics.java  |  53 +++++++++
 .../org/apache/cassandra/auth/AuthCacheTest.java   | 131 ++++++++++++++++++++-
 10 files changed, 393 insertions(+), 134 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 367d65ecdb..9b8da81077 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.1
+ * Refactor structure of caching metrics and expose auth cache metrics via JMX 
(CASSANDRA-17062)
  * Allow CQL client certificate authentication to work without sending an 
AUTHENTICATE request (CASSANDRA-18857)
  * Extend nodetool tpstats and system_views.thread_pools with detailed pool 
parameters (CASSANDRA-19289) 
  * Remove dependency on Sigar in favor of OSHI (CASSANDRA-16565)
diff --git a/doc/modules/cassandra/pages/managing/operating/metrics.adoc 
b/doc/modules/cassandra/pages/managing/operating/metrics.adoc
index 3edfe54478..2c709b9d16 100644
--- a/doc/modules/cassandra/pages/managing/operating/metrics.adoc
+++ b/doc/modules/cassandra/pages/managing/operating/metrics.adoc
@@ -528,9 +528,16 @@ ViewReplicasSuccess.
 base table and when CL.ONE is achieved on view.
 |===
 
-== Cache Metrics
+== Weighted Cache Metrics
 
-Cassandra caches have metrics to track the effectivness of the caches.
+[NOTE]
+====
+The non-auth caches are weighted (they do care about weight of a single entry) 
whereas the auth caches are
+non-weighted. Particularly it affects Capacity and Size attributes of the 
MBeans.
+For weighted caches they represent size of entries in bytes, for non-weighted 
caches they represent number of entries.
+====
+
+Cassandra caches have metrics to track the effectivness of the weighted caches.
 Though the `Table Metrics` might be more useful.
 
 Reported name format:
@@ -538,7 +545,7 @@ Reported name format:
 *Metric Name*::
   `org.apache.cassandra.metrics.Cache.<MetricName>.<CacheName>`
 *JMX MBean*::
-  `org.apache.cassandra.metrics:type=Cache scope=<CacheName> name=<MetricName>`
+  `org.apache.cassandra.metrics:type=Cache,scope=<CacheName>,name=<MetricName>`
 
 [cols=",,",options="header",]
 |===
@@ -569,8 +576,57 @@ The following caches are covered:
 
 [NOTE]
 ====
-Misses and MissLatency are only defined for the ChunkCache
+* Misses and MissLatency are only defined for the ChunkCache
+* ChunkCache MBean is only available if the cache is enabled
+====
+
+== Unweighted Cache Metrics
+
+Cassandra caches have metrics to track the effectivness of the unweighted 
caches.
+
+Reported name format:
+
+*Metric Name*::
+`org.apache.cassandra.metrics.UnweightedCache.<MetricName>.<CacheName>`
+
+*JMX MBean*::
+`org.apache.cassandra.metrics:type=UnweightedCache,scope=<CacheName>,name=<MetricName>`
+
+[cols=",,",options="header",]
+|===
+|Name |Type |Description
+|MaxEntries |Gauge<Integer> |Maximum number of entries.
+|Entries |Gauge<Integer> |Total number of cache entries.
+|FifteenMinuteCacheHitRate |Gauge<Double> |15m cache hit rate.
+|FiveMinuteCacheHitRate |Gauge<Double> |5m cache hit rate.
+|OneMinuteCacheHitRate |Gauge<Double> |1m cache hit rate.
+|HitRate |Gauge<Double> |All time cache hit rate.
+|Hits |Meter |Total number of cache hits.
+|Misses |Meter |Total number of cache misses.
+|MissLatency |Timer |Latency of misses.
+|Requests |Gauge<Long> |Total number of cache requests.
+|===
+
+The following caches are covered:
+
+[cols=",",options="header",]
+|===
+|Name |Description
+|CredentialsCache |Auth cache for credentials.
+|JmxPermissionsCache |Auth cache for JMX permissions.
+|CIDRPermissionsCache | Auth cache for CIDR permissions.
+|IdentityCache| Auth cache for `MutualTlsAuthenticator`.
+|NetworkPermissionsCache |Auth cache for network permissions.
+|PermissionsCache |Auth cache for permissions.
+|RolesCache |Auth cache for roles.
+|===
+
+[NOTE]
+.Note
+====
+AuthCache metrics MBeans are only available if corresponding authorizers and 
authenticators are enabled.
 ====
+
 == CQL Metrics
 
 Metrics specific to CQL prepared statement caching.
diff --git a/src/java/org/apache/cassandra/auth/AuthCache.java 
b/src/java/org/apache/cassandra/auth/AuthCache.java
index 6d78d368b4..2a3eb1af4a 100644
--- a/src/java/org/apache/cassandra/auth/AuthCache.java
+++ b/src/java/org/apache/cassandra/auth/AuthCache.java
@@ -33,6 +33,7 @@ import java.util.function.IntConsumer;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
+import com.google.common.primitives.Ints;
 import com.google.common.util.concurrent.Uninterruptibles;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -40,9 +41,14 @@ import org.slf4j.LoggerFactory;
 import com.github.benmanes.caffeine.cache.Caffeine;
 import com.github.benmanes.caffeine.cache.LoadingCache;
 import com.github.benmanes.caffeine.cache.Policy;
+import com.github.benmanes.caffeine.cache.RemovalCause;
+import org.apache.cassandra.cache.UnweightedCacheSize;
+import com.github.benmanes.caffeine.cache.stats.CacheStats;
+import com.github.benmanes.caffeine.cache.stats.StatsCounter;
 import org.apache.cassandra.concurrent.ExecutorPlus;
 import org.apache.cassandra.concurrent.ScheduledExecutors;
 import org.apache.cassandra.concurrent.Shutdownable;
+import org.apache.cassandra.metrics.UnweightedCacheMetrics;
 import org.apache.cassandra.utils.ExecutorUtils;
 import org.apache.cassandra.utils.MBeanWrapper;
 
@@ -52,13 +58,13 @@ import static 
org.apache.cassandra.config.CassandraRelevantProperties.AUTH_CACHE
 import static 
org.apache.cassandra.config.CassandraRelevantProperties.AUTH_CACHE_WARMING_RETRY_INTERVAL_MS;
 import static 
org.apache.cassandra.config.CassandraRelevantProperties.DISABLE_AUTH_CACHES_REMOTE_CONFIGURATION;
 
-public class AuthCache<K, V> implements AuthCacheMBean, Shutdownable
+public class AuthCache<K, V> implements AuthCacheMBean, UnweightedCacheSize, 
Shutdownable
 {
     private static final Logger logger = 
LoggerFactory.getLogger(AuthCache.class);
 
     public static final String MBEAN_NAME_BASE = 
"org.apache.cassandra.auth:type=";
 
-    private volatile ScheduledFuture cacheRefresher = null;
+    private volatile ScheduledFuture<?> cacheRefresher = null;
 
     // Keep a handle on created instances so their executors can be terminated 
cleanly
     private static final Set<Shutdownable> REGISTRY = new HashSet<>(4);
@@ -93,6 +99,8 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
     // values until the natural expiry time.
     private final BiPredicate<K, V> invalidateCondition;
 
+    private final UnweightedCacheMetrics metrics;
+
     /**
      * @param name Used for MBean
      * @param setValidityDelegate Used to set cache validity period. See 
{@link Policy#expireAfterWrite()}
@@ -176,6 +184,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
         this.bulkLoadFunction = checkNotNull(bulkLoadFunction);
         this.enableCache = checkNotNull(cacheEnabledDelegate);
         this.invalidateCondition = checkNotNull(invalidationCondition);
+        this.metrics = new UnweightedCacheMetrics(name, this);
         init();
     }
 
@@ -215,7 +224,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
     /**
      * Retrieve a value from the cache. Will call {@link 
LoadingCache#get(Object)} which will
      * "load" the value if it's not present, thus populating the key.
-     * @param k
+     * @param k key
      * @return The current value of {@code K} if cached or loaded.
      *
      * See {@link LoadingCache#get(Object)} for possible exceptions.
@@ -284,7 +293,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
 
     /**
      * Set maximum number of entries in the cache.
-     * @param maxEntries
+     * @param maxEntries max number of entries
      */
     public synchronized void setMaxEntries(int maxEntries)
     {
@@ -319,6 +328,11 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
         return cache == null ? 0L : cache.estimatedSize();
     }
 
+    public UnweightedCacheMetrics getMetrics()
+    {
+        return metrics;
+    }
+
     /**
      * (Re-)initialise the underlying cache. Will update validity, max 
entries, and update interval if
      * any have changed. The underlying {@link LoadingCache} will be initiated 
based on the provided {@code loadFunction}.
@@ -345,6 +359,7 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
                                    .expireAfterWrite(getValidity(), 
TimeUnit.MILLISECONDS)
                                    .maximumSize(getMaxEntries())
                                    .executor(cacheRefreshExecutor)
+                                   .recordStats(MetricsUpdater::new)
                                    .build(loadFunction::apply);
         }
         else
@@ -439,4 +454,48 @@ public class AuthCache<K, V> implements AuthCacheMBean, 
Shutdownable
             return Collections::emptyMap;
         }
     }
+
+    @Override
+    public int maxEntries()
+    {
+        return getMaxEntries();
+    }
+
+    @Override
+    public int entries()
+    {
+        return Ints.checkedCast(getEstimatedSize());
+    }
+
+    private class MetricsUpdater implements StatsCounter
+    {
+        @Override
+        public void recordHits(int i)
+        {
+            metrics.requests.mark(i);
+            metrics.hits.mark(i);
+        }
+
+        @Override
+        public void recordMisses(int i)
+        {
+            metrics.requests.mark(i);
+            metrics.misses.mark(i);
+        }
+
+        @Override
+        public void recordLoadSuccess(long l) {}
+
+        @Override
+        public void recordLoadFailure(long l) {}
+
+        @Override
+        public void recordEviction(int i, RemovalCause removalCause) {}
+
+        @Override
+        public CacheStats snapshot()
+        {
+            return CacheStats.of(metrics.hits.getCount(), 
metrics.misses.getCount(), 0, 0L, 0, 0L, 0L);
+        }
+    }
 }
diff --git a/src/java/org/apache/cassandra/cache/CacheSize.java 
b/src/java/org/apache/cassandra/cache/CacheSize.java
index 71365bb32a..57e4b8760b 100644
--- a/src/java/org/apache/cassandra/cache/CacheSize.java
+++ b/src/java/org/apache/cassandra/cache/CacheSize.java
@@ -20,15 +20,31 @@
  */
 package org.apache.cassandra.cache;
 
+/**
+ * Represents a weighted cache size.
+ *
+ * The non-auth caches are weighted (they do care about weight of a single 
entry) whereas the auth caches are
+ * unweighted.
+ */
 public interface CacheSize
 {
-
+    /**
+     * Returns the maximum total weighted size of this cache.
+     */
     long capacity();
 
+    /**
+     * Specifies the maximum total weighted size of this cache.
+     */
     void setCapacity(long capacity);
 
+    /**
+     * Returns the approximate number of entries in this cache.
+     */
     int size();
 
+    /**
+     * Returns the approximate accumulated weight of entries in this cache.
+     */
     long weightedSize();
-
 }
diff --git a/src/java/org/apache/cassandra/cache/ChunkCache.java 
b/src/java/org/apache/cassandra/cache/ChunkCache.java
index 8f22ee8b7b..d62ccbacb8 100644
--- a/src/java/org/apache/cassandra/cache/ChunkCache.java
+++ b/src/java/org/apache/cassandra/cache/ChunkCache.java
@@ -43,8 +43,7 @@ import org.apache.cassandra.metrics.ChunkCacheMetrics;
 import org.apache.cassandra.utils.memory.BufferPool;
 import org.apache.cassandra.utils.memory.BufferPools;
 
-public class ChunkCache
-        implements CacheLoader<ChunkCache.Key, ChunkCache.Buffer>, 
RemovalListener<ChunkCache.Key, ChunkCache.Buffer>, CacheSize
+public class ChunkCache implements CacheLoader<ChunkCache.Key, 
ChunkCache.Buffer>, RemovalListener<ChunkCache.Key, ChunkCache.Buffer>, 
CacheSize
 {
     public static final int RESERVED_POOL_SPACE_IN_MiB = 32;
     public static final long cacheSize = 1024L * 1024L * Math.max(0, 
DatabaseDescriptor.getFileCacheSizeInMiB() - RESERVED_POOL_SPACE_IN_MiB);
@@ -172,7 +171,7 @@ public class ChunkCache
         buffer.release();
     }
 
-    public void close()
+    public void clear()
     {
         cache.invalidateAll();
     }
diff --git a/src/java/org/apache/cassandra/cache/CacheSize.java 
b/src/java/org/apache/cassandra/cache/UnweightedCacheSize.java
similarity index 61%
copy from src/java/org/apache/cassandra/cache/CacheSize.java
copy to src/java/org/apache/cassandra/cache/UnweightedCacheSize.java
index 71365bb32a..1cded65e17 100644
--- a/src/java/org/apache/cassandra/cache/CacheSize.java
+++ b/src/java/org/apache/cassandra/cache/UnweightedCacheSize.java
@@ -20,15 +20,26 @@
  */
 package org.apache.cassandra.cache;
 
-public interface CacheSize
+/**
+ * Represents an unweighted cache size.
+ *
+ * The non-auth caches are weighted (they do care about weight of a single 
entry) whereas the auth caches are
+ * unweighted.
+ */
+public interface UnweightedCacheSize
 {
+    /**
+     * Returns the maximum number of entries in this cache.
+     */
+    int maxEntries();
 
-    long capacity();
-
-    void setCapacity(long capacity);
-
-    int size();
-
-    long weightedSize();
+    /**
+     * Specifies the maximum number of entries in this cache.
+     */
+    void setMaxEntries(int maxEntries);
 
+    /**
+     * Returns the approximate number of entries in this cache.
+     */
+    int entries();
 }
diff --git a/src/java/org/apache/cassandra/metrics/CacheMetrics.java 
b/src/java/org/apache/cassandra/metrics/AbstractCacheMetrics.java
similarity index 57%
copy from src/java/org/apache/cassandra/metrics/CacheMetrics.java
copy to src/java/org/apache/cassandra/metrics/AbstractCacheMetrics.java
index 34746bcee9..7b4b7510d5 100644
--- a/src/java/org/apache/cassandra/metrics/CacheMetrics.java
+++ b/src/java/org/apache/cassandra/metrics/AbstractCacheMetrics.java
@@ -21,71 +21,70 @@ import java.util.function.DoubleSupplier;
 
 import com.google.common.annotations.VisibleForTesting;
 
-import com.codahale.metrics.*;
-import org.apache.cassandra.cache.CacheSize;
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.Meter;
+import com.codahale.metrics.RatioGauge;
 
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
 
 /**
- * Metrics for {@code ICache}.
+ * Base class for metrics for weighted or unweighted caches.
  */
-public class CacheMetrics
+public abstract class AbstractCacheMetrics
 {
-    /** Cache capacity in bytes */
-    public final Gauge<Long> capacity;
-    /** Total size of cache, in bytes */
-    public final Gauge<Long> size;
-    /** Total number of cache entries */
-    public final Gauge<Integer> entries;
+    /**
+     * Type of the cache, basically its name
+     */
+    public final String type;
 
-    /** Total number of cache hits */
+    /**
+     * Total number of cache hits
+     */
     public final Meter hits;
-    /** Total number of cache misses */
+    /**
+     * Total number of cache misses
+     */
     public final Meter misses;
-    /** Total number of cache requests */
+    /**
+     * Total number of cache requests
+     */
     public final Meter requests;
 
-    /** all time cache hit rate */
+    /**
+     * all time cache hit rate
+     */
     public final Gauge<Double> hitRate;
-    /** 1m hit rate */
+    /**
+     * 1m hit rate
+     */
     public final Gauge<Double> oneMinuteHitRate;
-    /** 5m hit rate */
+    /**
+     * 5m hit rate
+     */
     public final Gauge<Double> fiveMinuteHitRate;
-    /** 15m hit rate */
+    /**
+     * 15m hit rate
+     */
     public final Gauge<Double> fifteenMinuteHitRate;
 
     protected final MetricNameFactory factory;
 
-    /**
-     * Create metrics for given cache.
-     *
-     * @param type Type of Cache to identify metrics.
-     * @param cache Cache to measure metrics
-     */
-    public CacheMetrics(String type, CacheSize cache)
+    protected AbstractCacheMetrics(MetricNameFactory metricNameFactory, String 
type)
     {
-        factory = new DefaultNameFactory("Cache", type);
-
-        capacity = Metrics.register(factory.createMetricName("Capacity"), 
cache::capacity);
-        size = Metrics.register(factory.createMetricName("Size"), 
cache::weightedSize);
-        entries = Metrics.register(factory.createMetricName("Entries"), 
cache::size);
-
+        this.type = type;
+        factory = metricNameFactory;
         hits = Metrics.meter(factory.createMetricName("Hits"));
         misses = Metrics.meter(factory.createMetricName("Misses"));
         requests = Metrics.meter(factory.createMetricName("Requests"));
 
-        hitRate =
-            Metrics.register(factory.createMetricName("HitRate"),
-                             ratioGauge(hits::getCount, requests::getCount));
-        oneMinuteHitRate =
-            Metrics.register(factory.createMetricName("OneMinuteHitRate"),
-                             ratioGauge(hits::getOneMinuteRate, 
requests::getOneMinuteRate));
-        fiveMinuteHitRate =
-            Metrics.register(factory.createMetricName("FiveMinuteHitRate"),
-                             ratioGauge(hits::getFiveMinuteRate, 
requests::getFiveMinuteRate));
-        fifteenMinuteHitRate =
-            Metrics.register(factory.createMetricName("FifteenMinuteHitRate"),
-                             ratioGauge(hits::getFifteenMinuteRate, 
requests::getFifteenMinuteRate));
+        hitRate = Metrics.register(factory.createMetricName("HitRate"),
+                                   ratioGauge(hits::getCount, 
requests::getCount));
+        oneMinuteHitRate = 
Metrics.register(factory.createMetricName("OneMinuteHitRate"),
+                                            ratioGauge(hits::getOneMinuteRate, 
requests::getOneMinuteRate));
+        fiveMinuteHitRate = 
Metrics.register(factory.createMetricName("FiveMinuteHitRate"),
+                                             
ratioGauge(hits::getFiveMinuteRate, requests::getFiveMinuteRate));
+        fifteenMinuteHitRate = 
Metrics.register(factory.createMetricName("FifteenMinuteHitRate"),
+                                                
ratioGauge(hits::getFifteenMinuteRate, requests::getFifteenMinuteRate));
     }
 
     @VisibleForTesting
diff --git a/src/java/org/apache/cassandra/metrics/CacheMetrics.java 
b/src/java/org/apache/cassandra/metrics/CacheMetrics.java
index 34746bcee9..a6017a39f8 100644
--- a/src/java/org/apache/cassandra/metrics/CacheMetrics.java
+++ b/src/java/org/apache/cassandra/metrics/CacheMetrics.java
@@ -17,11 +17,7 @@
  */
 package org.apache.cassandra.metrics;
 
-import java.util.function.DoubleSupplier;
-
-import com.google.common.annotations.VisibleForTesting;
-
-import com.codahale.metrics.*;
+import com.codahale.metrics.Gauge;
 import org.apache.cassandra.cache.CacheSize;
 
 import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
@@ -29,86 +25,28 @@ import static 
org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
 /**
  * Metrics for {@code ICache}.
  */
-public class CacheMetrics
+public class CacheMetrics extends AbstractCacheMetrics
 {
     /** Cache capacity in bytes */
     public final Gauge<Long> capacity;
+
     /** Total size of cache, in bytes */
     public final Gauge<Long> size;
+
     /** Total number of cache entries */
     public final Gauge<Integer> entries;
 
-    /** Total number of cache hits */
-    public final Meter hits;
-    /** Total number of cache misses */
-    public final Meter misses;
-    /** Total number of cache requests */
-    public final Meter requests;
-
-    /** all time cache hit rate */
-    public final Gauge<Double> hitRate;
-    /** 1m hit rate */
-    public final Gauge<Double> oneMinuteHitRate;
-    /** 5m hit rate */
-    public final Gauge<Double> fiveMinuteHitRate;
-    /** 15m hit rate */
-    public final Gauge<Double> fifteenMinuteHitRate;
-
-    protected final MetricNameFactory factory;
-
     /**
      * Create metrics for given cache.
      *
-     * @param type Type of Cache to identify metrics.
-     * @param cache Cache to measure metrics
+     * @param type Type of Cache to identify metrics
+     * @param cache Weighted Cache to measure metrics
      */
     public CacheMetrics(String type, CacheSize cache)
     {
-        factory = new DefaultNameFactory("Cache", type);
-
+        super(new DefaultNameFactory("Cache", type), type);
         capacity = Metrics.register(factory.createMetricName("Capacity"), 
cache::capacity);
         size = Metrics.register(factory.createMetricName("Size"), 
cache::weightedSize);
         entries = Metrics.register(factory.createMetricName("Entries"), 
cache::size);
-
-        hits = Metrics.meter(factory.createMetricName("Hits"));
-        misses = Metrics.meter(factory.createMetricName("Misses"));
-        requests = Metrics.meter(factory.createMetricName("Requests"));
-
-        hitRate =
-            Metrics.register(factory.createMetricName("HitRate"),
-                             ratioGauge(hits::getCount, requests::getCount));
-        oneMinuteHitRate =
-            Metrics.register(factory.createMetricName("OneMinuteHitRate"),
-                             ratioGauge(hits::getOneMinuteRate, 
requests::getOneMinuteRate));
-        fiveMinuteHitRate =
-            Metrics.register(factory.createMetricName("FiveMinuteHitRate"),
-                             ratioGauge(hits::getFiveMinuteRate, 
requests::getFiveMinuteRate));
-        fifteenMinuteHitRate =
-            Metrics.register(factory.createMetricName("FifteenMinuteHitRate"),
-                             ratioGauge(hits::getFifteenMinuteRate, 
requests::getFifteenMinuteRate));
-    }
-
-    @VisibleForTesting
-    public void reset()
-    {
-        // No actual reset happens. The Meter counter is put to zero but will 
not reset the moving averages
-        // It rather injects a weird value into them.
-        // This method is being only used by CacheMetricsTest and CachingBench 
so fixing this issue was acknowledged
-        // but not considered mandatory to be fixed now (CASSANDRA-16228)
-        hits.mark(-hits.getCount());
-        misses.mark(-misses.getCount());
-        requests.mark(-requests.getCount());
-    }
-
-    private static RatioGauge ratioGauge(DoubleSupplier numeratorSupplier, 
DoubleSupplier denominatorSupplier)
-    {
-        return new RatioGauge()
-        {
-            @Override
-            public Ratio getRatio()
-            {
-                return Ratio.of(numeratorSupplier.getAsDouble(), 
denominatorSupplier.getAsDouble());
-            }
-        };
     }
 }
diff --git a/src/java/org/apache/cassandra/metrics/UnweightedCacheMetrics.java 
b/src/java/org/apache/cassandra/metrics/UnweightedCacheMetrics.java
new file mode 100644
index 0000000000..ff40f3a038
--- /dev/null
+++ b/src/java/org/apache/cassandra/metrics/UnweightedCacheMetrics.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.metrics;
+
+import com.codahale.metrics.Gauge;
+import org.apache.cassandra.cache.UnweightedCacheSize;
+
+import static org.apache.cassandra.metrics.CassandraMetricsRegistry.Metrics;
+
+/**
+ * Metrics for an unweighted cache like {@code AuthCache}.
+ */
+public class UnweightedCacheMetrics extends AbstractCacheMetrics
+{
+    /**
+     * Cache capacity (maximum number of entries)
+     */
+    public final Gauge<Integer> maxEntries;
+
+    /**
+     * Total number of cache entries
+     */
+    public final Gauge<Integer> entries;
+
+    /**
+     * Create metrics for given cache.
+     *
+     * @param type  Type of Cache to identify metrics
+     * @param cache Unweighted Cache to measure metrics
+     */
+    public UnweightedCacheMetrics(String type, UnweightedCacheSize cache)
+    {
+        super(new DefaultNameFactory("UnweightedCache", type), type);
+
+        maxEntries = Metrics.register(factory.createMetricName("MaxEntries"), 
cache::maxEntries);
+        entries = Metrics.register(factory.createMetricName("Entries"), 
cache::entries);
+    }
+}
diff --git a/test/unit/org/apache/cassandra/auth/AuthCacheTest.java 
b/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
index 50a0a9c0fc..73062161a3 100644
--- a/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
+++ b/test/unit/org/apache/cassandra/auth/AuthCacheTest.java
@@ -20,6 +20,7 @@ package org.apache.cassandra.auth;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BooleanSupplier;
@@ -28,6 +29,8 @@ import java.util.function.IntConsumer;
 import java.util.function.IntSupplier;
 import java.util.function.Supplier;
 
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.cassandra.db.ConsistencyLevel;
@@ -50,6 +53,12 @@ public class AuthCacheTest
 
     private final int MAX_ENTRIES = 10;
 
+    @After
+    public void afterTest() throws Throwable
+    {
+        AuthCache.shutdownAllAndWait(1, TimeUnit.MINUTES);
+    }
+
     @Test
     public void testCacheLoaderIsCalledOnFirst()
     {
@@ -322,6 +331,107 @@ public class AuthCacheTest
         assertEquals(1, loadCounter);
     }
 
+    @Test
+    public void testMetricsOnCacheEnabled()
+    {
+        TestCache authCache = new TestCache(this::countingLoader, 
this::emptyBulkLoader, this::setValidity, () -> validity, () -> isCacheEnabled);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(0, authCache.entries());
+
+        authCache.get("10");
+        authCache.get("11");
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(2L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(2L);
+        assertEquals(2, loadCounter);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(2, authCache.entries());
+
+        authCache.get("10");
+        authCache.get("11");
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(2, authCache.entries());
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(4L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(2L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(2L);
+        assertEquals(2, loadCounter);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(2, authCache.entries());
+
+        authCache.getAll();
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(4L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(2L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(2L);
+        assertEquals(2, loadCounter);
+    }
+
+    @Test
+    public void testMetricsOnCacheDisabled()
+    {
+        isCacheEnabled = false;
+        TestCache authCache = new TestCache(this::countingLoader, 
this::emptyBulkLoader, this::setValidity, () -> validity, () -> isCacheEnabled);
+        authCache.get("10");
+        authCache.get("11");
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(0L);
+        assertEquals(2, loadCounter);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(0, authCache.entries());
+
+        authCache.getAll();
+
+        assertThat(authCache.getMetrics().requests.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().hits.getCount()).isEqualTo(0L);
+        assertThat(authCache.getMetrics().misses.getCount()).isEqualTo(0L);
+        assertEquals(2, loadCounter);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(0, authCache.entries());
+    }
+
+    @Test
+    public void testSettingMaxEntries()
+    {
+        AtomicInteger maxEntries = new AtomicInteger(10);
+        TestCache authCache = new TestCache(this::countingLoader,
+                                            this::emptyBulkLoader,
+                                            this::setValidity,
+                                            () -> validity,
+                                            () -> isCacheEnabled,
+                                            maxEntries::set,
+                                            maxEntries::get);
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(0, authCache.entries());
+
+        authCache.get("10");
+        authCache.get("11");
+
+        Assert.assertEquals(10, authCache.getMaxEntries());
+        Assert.assertEquals(2, authCache.entries());
+
+        authCache.setMaxEntries(20);
+
+        Assert.assertEquals(20, authCache.getMaxEntries());
+        Assert.assertEquals(2, authCache.entries());
+
+        authCache.invalidate();
+        authCache.cleanup();
+
+        Assert.assertEquals(20, authCache.getMaxEntries());
+        Assert.assertEquals(0, authCache.entries());
+    }
+
     private void setValidity(int validity)
     {
         this.validity = validity;
@@ -384,14 +494,31 @@ public class AuthCacheTest
                   IntConsumer setValidityDelegate,
                   IntSupplier getValidityDelegate,
                   BooleanSupplier cacheEnabledDelegate)
+        {
+            this(loadFunction,
+                 bulkLoadFunction,
+                 setValidityDelegate,
+                 getValidityDelegate,
+                 cacheEnabledDelegate,
+                 (MAX_ENTRIES) -> {},
+                 () -> 10);
+        }
+
+        TestCache(Function<String, Integer> loadFunction,
+                  Supplier<Map<String, Integer>> bulkLoadFunction,
+                  IntConsumer setValidityDelegate,
+                  IntSupplier getValidityDelegate,
+                  BooleanSupplier cacheEnabledDelegate,
+                  IntConsumer maxEntriesSetter,
+                  IntSupplier maxEntriesGetter)
         {
             super("TestCache" + nameCounter++,
                   setValidityDelegate,
                   getValidityDelegate,
                   (updateInterval) -> {},               // set update interval
                   () -> 1000,                           // get update interval
-                  (MAX_ENTRIES) -> {},                   // set max entries
-                  () -> 10,                             // get max entries
+                  maxEntriesSetter,                     // set max entries
+                  maxEntriesGetter,                     // get max entries
                   (updateActiveUpdate) -> {},           // set active update 
enabled
                   () -> false,                          // get active update 
enabled
                   loadFunction,


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

Reply via email to