
--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
--
You received this message because you are subscribed to a topic in the Google Groups "jOOQ User Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/jooq-user/YpIpRVVsd5A/unsubscribe.
To unsubscribe from this group and all its topics, send an email to jooq-user+...@googlegroups.com.
Hi Darren,I had tried once more and in a different Mission Control tab, I could also see that getAnnotation() is incredibly expensive. Much more than getMethods() or anything else. I'll investigate this more in-depth soon. Further head start on a sensible solution is still appreciated, though.CheersLukas
I've broken the environment where I tested this, so I'll probably get back to you tomorrow. The stack trace is a bit different. It is on the getAnnotation() call not the getMethods() call. I'm also using jdk1.7.0_45 just incase that matters. I'll see if there is some easy way that I can reproduce it too.
Darren
On Wed, Jan 15, 2014 at 10:41 AM, Lukas Eder <lukas...@gmail.com> wrote:
Hi Darren,Thanks for reporting this. I'll be tracking this issue as #2955Awesome news that Oracle now ships Mission Control with the JDK 7u40+. Just about when I was going to renew my YourKit license :-)So let's see if I read this correctly. The only significant contention I get from the jOOQ integration tests originate from the benchmarks for the into() method:
<image.png>
Now that I think about it if the caching was done in the Configuration object, not stored in some global static, then that would seem like an acceptable solution. I can't image that in a dynamic classloader situation that you would be sharing the Configuration object such that it would cause a memory. Or at least in that situation you give the option to disable it.
I found an IBM bug related to this, which is obviously for their J9 JVM, but it seems to indicate that java 7 introduced this slow down. http://www-01.ibm.com/support/docview.wss?uid=swg1IV53758
public class DefaultRecordMapperProvider implements RecordMapperProvider { private final ConcurrentHashMap<Key<?, ?>, DefaultRecordMapper<?, ?>> cache = new ConcurrentHashMap<Key<?, ?>, DefaultRecordMapper<?, ?>>(); @SuppressWarnings("unchecked") @Override public final <R extends Record, E> RecordMapper<R, E> provide(RecordType<R> rowType, Class<? extends E> type) { Key<R, E> key = new Key<R, E>(rowType, type); DefaultRecordMapper<?, ?> mapper = cache.get(key); if (mapper == null) { mapper = new DefaultRecordMapper<R, E>(rowType, type); cache.put(key, mapper); } return (RecordMapper<R, E>) mapper; } private static class Key<R extends Record, E> { final RecordType<R> rowType; final Class<? extends E> type; Key(RecordType<R> rowType, Class<? extends E> type) { this.rowType = rowType; this.type = type; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((rowType == null) ? 0 : rowType.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; } @Override public boolean equals(Object that) { if (this == that) return true; if (that == null) return false; Key<?, ?> other = (Key<?, ?>) that; if (rowType == null) { if (other.rowType != null) return false; } else if (!rowType.equals(other.rowType)) return false; if (type == null) { if (other.type != null) return false; } else if (!type.equals(other.type)) return false; return true; } } }
It is evident that the cache object might explode as it depends on the { RecordType × Class<?> } cartesian product, where RecordType itself has an immense "possible instances" complexity of O(n!) (all the permutations of possible field combinations). A possibility would be to use a LRUCache, but that might not be generally applicable.
What is your opinion on this? Or anyone else on the group?
Lukas
Yeah, doesn't exactly seem ideal. But at the end of the day, we're
not exactly looking for RecordMapper caching, but instead caching of
reflection information.
Would it be possible to change the annotation
utils methods, such as getAnnotatedMembers(), to accept a
Configuration object as an argument, then do something like the
following:
static final List<java.lang.reflect.Field>
getAnnotatedMembers(Configuration configuration, Class<?> type, String
name) {
if ( configuration instanceof SomeMagicalInterface ) {
((SomeMagicalInterface)configuration).getCachedStuff(type, name);
}
...
}
If we are focusing on just providing caching for reflection, it may
make sense to not specifically tie the interface and logic to the
record mapper. In fact you could just use Configuration.data(...) as
your cache.


Hi Darren,This is now fixed on GitHub master for jOOQ 3.3:I have added a new Setting to activate / deactivate this cache. The flag defaults to true in jOOQ 3.3.x and will default to false when merged onto jOOQ 3.2.4.By adding such a cache, I have observed tremendous performance improvements both when using "mapping by jOOQ's naming conventions" (A) and "mapping by annotations" (B). For 200'000 runs of Result.into(Class) with four Records:A: From 7.3 seconds to 0.9 secondsB: From 134 seconds to 1.4 seconds (!)The latter is what you have observed yourself and can be verified impressively on these Oracle Java Mission Control screenshots:Before:
<image.png>After:<image.png>