There are multiple usages of @NewField in the jdbc-generic module that overburden the global @NewField cache with writes - specifically, PreparedStatement and Statement. Every time these classes are instantiated, an extension is written to the cache. In high DB throughput scenarios, the cache cannot balance continual write pressure with its WeakKey eviction policy, as discussed in spike #2523 . Per Ben Manes' helpful comments on this issue, these ultra high-write scenarios are not really the use case these caches are optimized for to begin with.
For jdbc-generic, a viable alternative is to replace the cache with a vanilla JDK ConcurrentHashMap, and let the instrumentation manage removals per-statement - that is, when close is called on the Statement, we can ask the instrumentation to boot the statement from the map, so that the map does not need to self-manage an eviction policy the way a cache does. Initial tests show 2-3x performance (latency) improvements compared to the @NewField approach.
We also experimented with the possibility of striping the cache. This showed performance improvements when paired with Caffeine caches, but not with vanilla JDK CHMap (performance of striped cache vs. concurrent hash map were fairly comparable, though, with concurrent hash map taking a slight edge).
For this story, actually implement this change. It would be good to document performance differences - latency and CPU being the two most important in this case.
There are multiple usages of
@NewFieldin the jdbc-generic module that overburden the global@NewFieldcache with writes - specifically,PreparedStatementandStatement. Every time these classes are instantiated, an extension is written to the cache. In high DB throughput scenarios, the cache cannot balance continual write pressure with its WeakKey eviction policy, as discussed in spike #2523 . Per Ben Manes' helpful comments on this issue, these ultra high-write scenarios are not really the use case these caches are optimized for to begin with.For jdbc-generic, a viable alternative is to replace the cache with a vanilla JDK
ConcurrentHashMap, and let the instrumentation manage removals per-statement - that is, whencloseis called on the Statement, we can ask the instrumentation to boot the statement from the map, so that the map does not need to self-manage an eviction policy the way a cache does. Initial tests show 2-3x performance (latency) improvements compared to the@NewFieldapproach.We also experimented with the possibility of striping the cache. This showed performance improvements when paired with Caffeine caches, but not with vanilla JDK CHMap (performance of striped cache vs. concurrent hash map were fairly comparable, though, with concurrent hash map taking a slight edge).
For this story, actually implement this change. It would be good to document performance differences - latency and CPU being the two most important in this case.