Skip to content

Commit e312bfc

Browse files
committed
Add specific type for matching class-loaders by their indexed key
1 parent a9b9875 commit e312bfc

File tree

3 files changed

+45
-22
lines changed

3 files changed

+45
-22
lines changed

utils/src/main/java/datadog/instrument/utils/ClassInfoCache.java

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,15 @@
88

99
import java.util.Arrays;
1010
import java.util.concurrent.atomic.AtomicLong;
11-
import java.util.function.IntPredicate;
1211

1312
/**
1413
* Shares class information from multiple classloaders in a single cache.
1514
*
16-
* <p>Information is indexed by class-name, with an optional class-loader filter. When multiple
15+
* <p>Information is indexed by class-name, with an optional class-loader matcher. When multiple
1716
* classes are defined with the same name, only one has its information cached at any given time.
1817
* The class-loader can then be used to check information is for the correct class.
1918
*
20-
* @see ClassLoaderIndex#getClassLoaderKeyId
19+
* @see ClassLoaderIndex#getClassLoaderKeyId(ClassLoader)
2120
*/
2221
public final class ClassInfoCache<T> {
2322

@@ -72,7 +71,7 @@ public void share(String className, T info) {
7271
}
7372

7473
/**
75-
* Finds information for the given class-name, under the given class-loader.
74+
* Finds information for the given class-name, scoped to the given class-loader.
7675
*
7776
* @param className the class-name
7877
* @param cl the class-loader
@@ -83,18 +82,18 @@ public T find(CharSequence className, ClassLoader cl) {
8382
}
8483

8584
/**
86-
* Shares information for the given class-name, under the given class-loader.
85+
* Shares information for the given class-name, scoped to the given class-loader.
8786
*
8887
* @param className the class-name
8988
* @param info the information to share under the class-name and class-loader
90-
* @param cl limit the information to this class-loader
89+
* @param cl scope the information to this class-loader
9190
*/
9291
public void share(String className, T info, ClassLoader cl) {
9392
share(className, info, ClassLoaderIndex.getClassLoaderKeyId(cl));
9493
}
9594

9695
/**
97-
* Finds information for the given class-name, under the given class-loader key.
96+
* Finds information for the given class-name, scoped to the given class-loader key.
9897
*
9998
* @param className the class-name
10099
* @param classLoaderKeyId the class-loader's key-id
@@ -113,7 +112,7 @@ public T find(CharSequence className, int classLoaderKeyId) {
113112
SharedInfo existing = shared[slot];
114113
if (existing != null) {
115114
if (existing.className.contentEquals(className)) {
116-
// filter on class-loader, -1 on either side matches all
115+
// match on class-loader key, -1 on either side matches all
117116
if ((classLoaderKeyId ^ existing.classLoaderKeyId) <= 0) {
118117
// use global TICKS as a substitute for access time
119118
// TICKS is only incremented in 'share' for performance reasons
@@ -134,15 +133,15 @@ public T find(CharSequence className, int classLoaderKeyId) {
134133
}
135134

136135
/**
137-
* Finds information for the given class-name, filtered by class-loader key.
136+
* Finds information for the given class-name, scoped to class-loaders with matching keys.
138137
*
139138
* @param className the class-name
140-
* @param classLoaderKeyFilter the filter for the class-loader key
141-
* @return information shared under the class-name and filtered class-loader
139+
* @param classLoaderKeyMatcher matcher of class-loader keys
140+
* @return information shared under the class-name and matching class-loader
142141
* @see ClassLoaderIndex#getClassLoaderKeyId(ClassLoader)
143142
*/
144143
@SuppressWarnings("unchecked")
145-
public T find(CharSequence className, IntPredicate classLoaderKeyFilter) {
144+
public T find(CharSequence className, ClassLoaderKeyMatcher classLoaderKeyMatcher) {
146145
final int hash = className.hashCode();
147146
final SharedInfo[] shared = this.shared;
148147
final int slotMask = this.slotMask;
@@ -153,9 +152,9 @@ public T find(CharSequence className, IntPredicate classLoaderKeyFilter) {
153152
SharedInfo existing = shared[slot];
154153
if (existing != null) {
155154
if (existing.className.contentEquals(className)) {
156-
// apply filter to class-loader key, -1 always matches
155+
// apply custom matcher to class-loader key, -1 always matches
157156
if (existing.classLoaderKeyId < 0
158-
|| classLoaderKeyFilter.test(existing.classLoaderKeyId)) {
157+
|| classLoaderKeyMatcher.test(existing.classLoaderKeyId)) {
159158
// use global TICKS as a substitute for access time
160159
// TICKS is only incremented in 'share' for performance reasons
161160
existing.accessed = TICKS.get();
@@ -175,11 +174,11 @@ public T find(CharSequence className, IntPredicate classLoaderKeyFilter) {
175174
}
176175

177176
/**
178-
* Shares information for the given class-name, under the given class-loader key.
177+
* Shares information for the given class-name, scoped to the given class-loader key.
179178
*
180179
* @param className the class-name
181180
* @param info the information to share under the class-name and class-loader
182-
* @param classLoaderKeyId limit the information to this class-loader key-id
181+
* @param classLoaderKeyId scope the information to this class-loader key-id
183182
* @see ClassLoaderIndex#getClassLoaderKeyId(ClassLoader)
184183
*/
185184
@SuppressWarnings("StatementWithEmptyBody")
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
3+
* This product includes software developed at Datadog (https://www.datadoghq.com/).
4+
* Copyright 2025-Present Datadog, Inc.
5+
*/
6+
7+
package datadog.instrument.utils;
8+
9+
/**
10+
* Matcher used to partition class-loaders by their indexed key-id.
11+
*
12+
* @see ClassLoaderIndex#getClassLoaderKeyId(ClassLoader)
13+
* @see ClassInfoCache#find(CharSequence, ClassLoaderKeyMatcher)
14+
*/
15+
@FunctionalInterface
16+
public interface ClassLoaderKeyMatcher {
17+
18+
/**
19+
* Evaluates this matcher against the given class-loader key-id.
20+
*
21+
* @param classLoaderKeyId the class-loader key-id
22+
* @return {@code true} if the key-id matched; otherwise {@code false}
23+
*/
24+
boolean test(int classLoaderKeyId);
25+
}

utils/src/test/java/datadog/instrument/utils/ClassInfoCacheTest.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
import java.util.HashSet;
1010
import java.util.Set;
11-
import java.util.function.IntPredicate;
1211
import org.junit.jupiter.api.Test;
1312

1413
class ClassInfoCacheTest {
@@ -20,10 +19,10 @@ void basicOperation() {
2019
ClassLoader myCL = newCL();
2120
ClassLoader notMyCL = newCL();
2221

23-
int myCLKey = ClassLoaderIndex.getClassLoaderKeyId(myCL);
22+
int myCLKeyId = ClassLoaderIndex.getClassLoaderKeyId(myCL);
2423

25-
IntPredicate myCLFilter = sameCLKey(myCLKey);
26-
IntPredicate notMyCLFilter = myCLFilter.negate();
24+
ClassLoaderKeyMatcher myCLFilter = sameCLKey(myCLKeyId);
25+
ClassLoaderKeyMatcher notMyCLFilter = keyId -> !myCLFilter.test(keyId);
2726

2827
assertNull(cache.find("example.test.MyGlobalClass"));
2928
assertNull(cache.find("example.test.MyLocalClass"));
@@ -151,8 +150,8 @@ void overflow() {
151150
}
152151
}
153152

154-
private static IntPredicate sameCLKey(int clKey) {
155-
return k -> k == clKey;
153+
private static ClassLoaderKeyMatcher sameCLKey(int expectedKeyId) {
154+
return keyId -> keyId == expectedKeyId;
156155
}
157156

158157
private static ClassLoader newCL() {

0 commit comments

Comments
 (0)