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