Skip to content

Commit 67e68c4

Browse files
author
Peter Alfonsi
committed
Made SingleDimensionCacheStats also take in tier dimensions
Signed-off-by: Peter Alfonsi <[email protected]>
1 parent 3777e3f commit 67e68c4

File tree

6 files changed

+120
-14
lines changed

6 files changed

+120
-14
lines changed

plugins/cache-ehcache/src/main/java/org/opensearch/cache/store/disk/EhcacheDiskCache.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.opensearch.common.cache.RemovalReason;
2525
import org.opensearch.common.cache.stats.CacheStats;
2626
import org.opensearch.common.cache.ICacheKey;
27+
import org.opensearch.common.cache.stats.CacheStatsDimension;
2728
import org.opensearch.common.cache.stats.SingleDimensionCacheStats;
2829
import org.opensearch.common.cache.store.builders.ICacheBuilder;
2930
import org.opensearch.common.cache.store.enums.CacheStoreType;
@@ -148,7 +149,7 @@ private EhcacheDiskCache(Builder<K, V> builder) {
148149
this.valueSerializer);
149150
this.cache = buildCache(Duration.ofMillis(expireAfterAccess.getMillis()), builder);
150151
this.shardIdDimensionName = Objects.requireNonNull(builder.shardIdDimensionName, "Dimension name can't be null");
151-
this.stats = new SingleDimensionCacheStats(shardIdDimensionName);
152+
this.stats = new SingleDimensionCacheStats(shardIdDimensionName, CacheStatsDimension.TIER_DIMENSION_VALUE_DISK);
152153
}
153154

154155
private Cache<ICacheKey, byte[]> buildCache(Duration expireAfterAccess, Builder<K, V> builder) {

plugins/cache-ehcache/src/test/java/org/opensearch/cache/store/disk/EhCacheDiskCacheTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,36 @@ public void testMemoryTracking() throws Exception {
607607
}
608608
}
609609

610+
public void testGetStatsByTierName() throws Exception {
611+
Settings settings = Settings.builder().build();
612+
MockRemovalListener<String, String> mockRemovalListener = new MockRemovalListener<>();
613+
ToLongBiFunction<ICacheKey<String>, String> weigher = getWeigher();
614+
try (NodeEnvironment env = newNodeEnvironment(settings)) {
615+
ICache<String, String> ehcacheTest = new EhcacheDiskCache.Builder<String, String>().setThreadPoolAlias("ehcacheTest")
616+
.setStoragePath(env.nodePaths()[0].indicesPath.toString() + "/request_cache")
617+
.setKeyType(String.class)
618+
.setValueType(String.class)
619+
.setKeySerializer(new StringSerializer())
620+
.setValueSerializer(new StringSerializer())
621+
.setShardIdDimensionName(dimensionName)
622+
.setCacheType(CacheType.INDICES_REQUEST_CACHE)
623+
.setSettings(settings)
624+
.setExpireAfterAccess(TimeValue.MAX_VALUE)
625+
.setMaximumWeightInBytes(CACHE_SIZE_IN_BYTES)
626+
.setRemovalListener(mockRemovalListener)
627+
.setWeigher(weigher)
628+
.build();
629+
int randomKeys = randomIntBetween(10, 100);
630+
for (int i = 0; i < randomKeys; i++) {
631+
ehcacheTest.put(getICacheKey(UUID.randomUUID().toString()), UUID.randomUUID().toString());
632+
}
633+
assertEquals(randomKeys, ehcacheTest.stats().getEntriesByDimensions(List.of(new CacheStatsDimension(CacheStatsDimension.TIER_DIMENSION_NAME, CacheStatsDimension.TIER_DIMENSION_VALUE_DISK))));
634+
assertEquals(0, ehcacheTest.stats().getEntriesByDimensions(List.of(new CacheStatsDimension(CacheStatsDimension.TIER_DIMENSION_NAME, CacheStatsDimension.TIER_DIMENSION_VALUE_ON_HEAP))));
635+
636+
ehcacheTest.close();
637+
}
638+
}
639+
610640
private static String generateRandomString(int length) {
611641
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
612642
StringBuilder randomString = new StringBuilder(length);

server/src/main/java/org/opensearch/common/cache/stats/CacheStatsDimension.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
import java.util.Objects;
1717

1818
public class CacheStatsDimension implements Writeable {
19+
// Values for tier dimensions, that are reused across CacheStats implementations
20+
public static final String TIER_DIMENSION_NAME = "tier";
21+
public static final String TIER_DIMENSION_VALUE_ON_HEAP = "on_heap";
22+
public static final String TIER_DIMENSION_VALUE_DISK = "disk";
1923
public final String dimensionName;
2024
public final String dimensionValue;
2125
public CacheStatsDimension(String dimensionName, String dimensionValue) {

server/src/main/java/org/opensearch/common/cache/stats/SingleDimensionCacheStats.java

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414
import org.opensearch.core.xcontent.XContentBuilder;
1515

1616
import java.io.IOException;
17+
import java.util.ArrayList;
1718
import java.util.HashMap;
1819
import java.util.List;
1920
import java.util.Map;
2021
import java.util.concurrent.ConcurrentHashMap;
2122
import java.util.concurrent.ConcurrentMap;
2223

2324
/**
24-
* A CacheStats implementation for caches that aggregate over a single dimension.
25+
* A CacheStats implementation for caches that aggregate over a single dimension, as well as holding a tier dimension.
2526
* For example, caches in the IndicesRequestCache only aggregate over ShardId value.
2627
*/
2728
public class SingleDimensionCacheStats implements CacheStats {
@@ -41,8 +42,10 @@ public class SingleDimensionCacheStats implements CacheStats {
4142

4243
// The allowed dimension name. This stats only allows a single dimension name
4344
private final String allowedDimensionName;
45+
// The value of the tier dimension for entries in this Stats object.
46+
private final String tierDimensionValue;
4447

45-
public SingleDimensionCacheStats(String allowedDimensionName) {
48+
public SingleDimensionCacheStats(String allowedDimensionName, String tierDimensionValue) {
4649
this.hitsMap = new ConcurrentHashMap<>();
4750
this.missesMap = new ConcurrentHashMap<>();
4851
this.evictionsMap = new ConcurrentHashMap<>();
@@ -56,6 +59,7 @@ public SingleDimensionCacheStats(String allowedDimensionName) {
5659
this.totalEntries = new CounterMetric();
5760

5861
this.allowedDimensionName = allowedDimensionName;
62+
this.tierDimensionValue = tierDimensionValue;
5963
}
6064

6165
public SingleDimensionCacheStats(StreamInput in) throws IOException {
@@ -77,6 +81,7 @@ public SingleDimensionCacheStats(StreamInput in) throws IOException {
7781
totalEntries.inc(in.readVLong());
7882

7983
this.allowedDimensionName = in.readString();
84+
this.tierDimensionValue = in.readString();
8085
}
8186

8287
@Override
@@ -104,7 +109,34 @@ public long getTotalEntries() {
104109
return this.totalEntries.count();
105110
}
106111

107-
private long internalGetByDimension(List<CacheStatsDimension> dimensions, Map<String, CounterMetric> metricsMap) {
112+
private long internalGetByDimension(List<CacheStatsDimension> dimensions, Map<String, CounterMetric> metricsMap, CounterMetric totalMetric) {
113+
CacheStatsDimension tierDimension = getTierDimensionIfPresent(dimensions);
114+
if (tierDimension != null) {
115+
// This get request includes a tier dimension. Return values only if the tier dimension value
116+
// matches the one for this stats object, otherwise return 0
117+
assert dimensions.size() == 1 || dimensions.size() == 2; // There can be at most one non-tier dimension value
118+
if (tierDimension.dimensionValue.equals(tierDimensionValue)) {
119+
// The list passed in may not be mutable; create a mutable copy to remove the tier dimension
120+
ArrayList<CacheStatsDimension> modifiedDimensions = new ArrayList<>(dimensions);
121+
modifiedDimensions.remove(tierDimension);
122+
123+
if (modifiedDimensions.size() == 1){
124+
return internalGetHelper(modifiedDimensions, metricsMap);
125+
} else {
126+
return totalMetric.count();
127+
}
128+
129+
} else {
130+
// Return 0 for incorrect tier value
131+
return 0;
132+
}
133+
} else {
134+
// This get request doesn't include a tier dimension. Return the appropriate values.
135+
return internalGetHelper(dimensions, metricsMap);
136+
}
137+
}
138+
139+
private long internalGetHelper(List<CacheStatsDimension> dimensions, Map<String, CounterMetric> metricsMap) {
108140
assert dimensions.size() == 1;
109141
CounterMetric counter = metricsMap.get(dimensions.get(0).dimensionValue);
110142
if (counter == null) {
@@ -113,29 +145,41 @@ private long internalGetByDimension(List<CacheStatsDimension> dimensions, Map<St
113145
return counter.count();
114146
}
115147

148+
/**
149+
* Returns the dimension that represents a tier value, if one is present. Otherwise return null.
150+
*/
151+
private CacheStatsDimension getTierDimensionIfPresent(List<CacheStatsDimension> dimensions) {
152+
for (CacheStatsDimension dim : dimensions) {
153+
if (dim.dimensionName.equals(CacheStatsDimension.TIER_DIMENSION_NAME)) {
154+
return dim;
155+
}
156+
}
157+
return null;
158+
}
159+
116160
@Override
117161
public long getHitsByDimensions(List<CacheStatsDimension> dimensions) {
118-
return internalGetByDimension(dimensions, hitsMap);
162+
return internalGetByDimension(dimensions, hitsMap, totalHits);
119163
}
120164

121165
@Override
122166
public long getMissesByDimensions(List<CacheStatsDimension> dimensions) {
123-
return internalGetByDimension(dimensions, missesMap);
167+
return internalGetByDimension(dimensions, missesMap, totalMisses);
124168
}
125169

126170
@Override
127171
public long getEvictionsByDimensions(List<CacheStatsDimension> dimensions) {
128-
return internalGetByDimension(dimensions, evictionsMap);
172+
return internalGetByDimension(dimensions, evictionsMap, totalEvictions);
129173
}
130174

131175
@Override
132176
public long getMemorySizeByDimensions(List<CacheStatsDimension> dimensions) {
133-
return internalGetByDimension(dimensions, memorySizeMap);
177+
return internalGetByDimension(dimensions, memorySizeMap, totalMemorySize);
134178
}
135179

136180
@Override
137181
public long getEntriesByDimensions(List<CacheStatsDimension> dimensions) {
138-
return internalGetByDimension(dimensions, entriesMap);
182+
return internalGetByDimension(dimensions, entriesMap, totalEntries);
139183
}
140184

141185
private boolean checkDimensionList(List<CacheStatsDimension> dimensions) {
@@ -199,6 +243,7 @@ public void writeTo(StreamOutput out) throws IOException {
199243
out.writeVLong(totalEntries.count());
200244

201245
out.writeString(allowedDimensionName);
246+
out.writeString(tierDimensionValue);
202247
}
203248

204249
public String getAllowedDimensionName() {

server/src/main/java/org/opensearch/common/cache/store/OpenSearchOnHeapCache.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.opensearch.common.cache.RemovalReason;
1818
import org.opensearch.common.cache.stats.CacheStats;
1919
import org.opensearch.common.cache.ICacheKey;
20+
import org.opensearch.common.cache.stats.CacheStatsDimension;
2021
import org.opensearch.common.cache.stats.SingleDimensionCacheStats;
2122
import org.opensearch.common.cache.store.builders.ICacheBuilder;
2223
import org.opensearch.common.settings.Settings;
@@ -49,7 +50,7 @@ public OpenSearchOnHeapCache(Builder<K, V> builder) {
4950
}
5051
cache = cacheBuilder.build();
5152
String dimensionName = Objects.requireNonNull(builder.shardIdDimensionName, "Shard id dimension name can't be null");
52-
this.stats = new SingleDimensionCacheStats(dimensionName);
53+
this.stats = new SingleDimensionCacheStats(dimensionName, CacheStatsDimension.TIER_DIMENSION_VALUE_ON_HEAP);
5354
this.removalListener = builder.getRemovalListener();
5455
}
5556

server/src/test/java/org/opensearch/common/cache/stats/SingleDimensionCacheStatsTests.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
public class SingleDimensionCacheStatsTests extends OpenSearchTestCase {
2424
private final String dimensionName = "shardId";
25+
private final String tierName = "test_tier";
2526
public void testAddAndGet() throws Exception {
26-
StatsAndExpectedResults statsAndExpectedResults = getPopulatedStats();
27+
StatsAndExpectedResults statsAndExpectedResults = getPopulatedStats(tierName);
2728
SingleDimensionCacheStats stats = statsAndExpectedResults.stats;
2829

2930
checkShardResults(statsAndExpectedResults);
@@ -32,10 +33,34 @@ public void testAddAndGet() throws Exception {
3233
// Check values returned for a nonexistent dimension value or name return 0
3334
assertEquals(0, stats.getHitsByDimensions(List.of(new CacheStatsDimension(dimensionName, "nonexistent"))));
3435
assertEquals(0, stats.getHitsByDimensions(List.of(new CacheStatsDimension("nonexistentName", "nonexistentValue"))));
36+
37+
// Check sending too many values causes an assertion error
38+
assertThrows(AssertionError.class, () -> stats.getHitsByDimensions(List.of(getDim(0), new CacheStatsDimension("test", "value"))));
39+
}
40+
41+
public void testTierFiltering() throws Exception {
42+
StatsAndExpectedResults statsAndExpectedResults = getPopulatedStats(tierName);
43+
SingleDimensionCacheStats stats = statsAndExpectedResults.stats;
44+
45+
// Values should be returned if the tier dimension value matches the one passed to SingleDimensionCacheStats. Otherwise we should get 0.
46+
CacheStatsDimension matchingTierDim = new CacheStatsDimension(CacheStatsDimension.TIER_DIMENSION_NAME, tierName);
47+
CacheStatsDimension nonMatchingTierDim = new CacheStatsDimension(CacheStatsDimension.TIER_DIMENSION_NAME, "another_tier");
48+
49+
assertEquals(stats.getTotalHits(), stats.getHitsByDimensions(List.of(matchingTierDim)));
50+
assertEquals(0, stats.getHitsByDimensions(List.of(nonMatchingTierDim)));
51+
for (int i = 0; i < statsAndExpectedResults.numShardIds; i++) {
52+
assertEquals(stats.getHitsByDimensions(List.of(getDim(i))), stats.getHitsByDimensions(List.of(getDim(i), matchingTierDim)));
53+
assertEquals(stats.getHitsByDimensions(List.of(getDim(i))), stats.getHitsByDimensions(List.of(matchingTierDim, getDim(i))));
54+
assertEquals(0, stats.getHitsByDimensions(List.of(getDim(i), nonMatchingTierDim)));
55+
assertEquals(0, stats.getHitsByDimensions(List.of(nonMatchingTierDim, getDim(i))));
56+
57+
}
58+
// Check sending too many values causes an assertion error
59+
assertThrows(AssertionError.class, () -> stats.getHitsByDimensions(List.of(getDim(0), matchingTierDim, new CacheStatsDimension("test", "value"))));
3560
}
3661

3762
public void testSerialization() throws Exception {
38-
StatsAndExpectedResults statsAndExpectedResults = getPopulatedStats();
63+
StatsAndExpectedResults statsAndExpectedResults = getPopulatedStats(tierName);
3964
SingleDimensionCacheStats stats = statsAndExpectedResults.stats;
4065
Map<String, Map<String, Long>> expectedResults = statsAndExpectedResults.expectedShardResults;
4166

@@ -68,8 +93,8 @@ private long sumMap(Map<String, Long> inputMap) {
6893
return result;
6994
}
7095

71-
private StatsAndExpectedResults getPopulatedStats() {
72-
SingleDimensionCacheStats stats = new SingleDimensionCacheStats(dimensionName);
96+
private StatsAndExpectedResults getPopulatedStats(String tierName) {
97+
SingleDimensionCacheStats stats = new SingleDimensionCacheStats(dimensionName, tierName);
7398

7499
int numShardIds = 10;
75100
Map<String, Long> expectedHits = new HashMap<>();

0 commit comments

Comments
 (0)