New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unwrapped java.sql PreparedStatement and Connection #2052
Conversation
bc3ea36
to
b6cf741
Compare
import java.sql.Statement; | ||
|
||
public abstract class JDBCUtils { | ||
private static Field c3poField = null; | ||
|
||
// Cache if the class's isWrapperFor() or unwrap() methods are abstract | ||
// Using classnames to avoid the need for a WeakMap | ||
public static final DDCache<String, Boolean> ABSTRACT_UNWRAP = DDCaches.newFixedSizeCache(64); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we use ClassValue
here instead? (which have weak keys)
@@ -11,6 +11,24 @@ public CHMCache(final int initialCapacity) { | |||
this.chm = new ConcurrentHashMap<>(initialCapacity); | |||
} | |||
|
|||
@Override |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changes aren't necessary if we, ahem, wrap the unwrapping logic in a ClassValue<Boolean>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The majority of this change seems to be caching changes for caching flags at class level, whereas I think this is a classic use case for ClassValue
, which is well optimised for this sort of thing.
@richardstartin The main reason for those changes was the only way to add items to a Why this matters: With the way the PR is currently written, the common case just works. We catch the extremely rare In a I guess it the end it doesn't really matter because its only once per class extending PreparedStatement/Connection |
@randomanderson even so, you're going to hit the cache in Since I'm claiming a performance advantage for |
I wrote up what I have in mind here |
This reverts commit c5c6d4c.
It looks like public class ClassPredicate extends ClassValue<Boolean> {
private final Predicate<Class<?>> predicate;
public ClassPredicate(Predicate<Class<?>> predicate) {
this.predicate = predicate;
}
@Override
protected Boolean computeValue(Class<?> type) {
return predicate.test(type);
}
}
@State(Scope.Benchmark)
public class ClassValueVsFixedSizeCache {
private ClassPredicate classPredicate;
private FixedSizeCache<String, Boolean> fixedSizeCache;
private Class[] types;
int i = 0;
@Setup(Level.Iteration)
public void init() {
this.classPredicate = new ClassPredicate(type -> type.getName().equals("java.lang.String"));
this.fixedSizeCache = new FixedSizeCache<>(64);
this.types = new Class[]{
Short.class,
Long.class,
Double.class,
Float.class,
Object.class,
Integer.class,
String.class
};
}
@Benchmark
public Boolean classPredicate() {
int index = i;
i = (i + 1) % 7;
return classPredicate.get(types[index]);
}
@Benchmark
public Boolean fixedSizeCache() {
int index = i;
i = (i + 1) % 7;
String type = types[index].getName();
Boolean result = fixedSizeCache.getIfPresent(type);
if (null == result && index == 6) {
fixedSizeCache.put(type, true);
return true;
}
return result;
}
}
Rather than making a material difference to a user's application, this would probably only show up in CPU% metrics. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. Thanks for accommodating the requested changes and fixing my buggy suggestion.
java.sql.PreparedStatement
andjava.sql.Connection
are wrappers to delegates when they implement theWrapper
interface. When this happens, our previous instrumentation was unable to find the saved sql statements in theContextStore
. This pull request unwraps these objects to do lookups on the delegates instead of the wrappers.The one complication is older drivers like
h2
implementing an older version of the interface. This throwsAbstractMethodError
at runtime. I cached which classes throw the error for efficiency. I added a couple methods toDDCache
so it can be used in the implementation.