ConversionRules LRUCache - Blocking / Alternatives
Not completely sure if it's not because of how I'm using Saxon, but I hit some serious blocking in LRUCache coming from ConversionRules.
- Saxon-HE 9.5.1-5
- I create a new TransformerFactoryImpl
- add some extension functions to it via getConfiguration().registerExtensionFunction
- create a new Templates instance with my .xsl
- same Templates gets re-used in whole application for same transformation, doing newTransformer on it every time (Transformers are not shared between threads)
Problem: During some tests which did a lot of long/heavy transformations I noticed a lot of BLOCKED threads. The stack looks like this for all of them (I had hundreds): @ "default task-1" prio=10 tid=0x000000000260b800 nid=0x1cfd waiting for monitor entry [0x00007fd2eabe6000] java.lang.Thread.State: BLOCKED (on object monitor) at java.util.Collections$SynchronizedMap.get(Collections.java:2037) - waiting to lock <0x00000003328c05b0> (a java.util.Collections$SynchronizedMap) at net.sf.saxon.expr.sort.LRUCache.get(LRUCache.java:58) at net.sf.saxon.lib.ConversionRules.getConverter(ConversionRules.java:207) at net.sf.saxon.type.Converter.convert(Converter.java:111) at net.sf.saxon.expr.GeneralComparison.compare(GeneralComparison.java:778) ... @
Sharing: From what I see a ConversionRules instance is shared for same Configuration, so it will be shared for all Transformers generated from same Templates.
Workaround: I extended ConversionRules with a custom one which replaced @LRUCache<>@ with @ConcurrentMap<>@ and problems went away. (Obviously not an ideal solution since it might grow indefinitely) Also @ConversionRules.makeConverter@ and @ConversionRules.makeStringConverter@ were private so I had to copy them to make it work.
The LRUCache only contained a few entries, all of the blocking was on @.get()@ calls.
- Could someone confirm ConversionRules LRUCache caches really is a problem in case of usage from multiple threads? Or am I doing something wrong and that's why I was hitting this issue?
- Any good concurrent alternatives to LRUCache which could be used instead?
Yes, we've also seen workloads in which this mechanism doesn't work well, and we've redesigned it for 9.6. One of the problems is that new instances of ConversionRules are allocated rather more frequently than we thought, and each instance has its own copy of the LRUCache. This means that the cache doesn't stabilise as well as it should; and because the content isn't stable, I can well believe that there is conention, though this isn't something we've observed ourselves.
In the 9.6 design we're still using an LRUCache for the general converters, but each AtomicType object is now responsible for allocating a StringConverter, and the StringConverter is generally held as a property of the AtomicType.
One thing you can do to reduce the overhead is to declare the types of your variables and parameters. This will tend to mean that converters get allocated at compile time rather than at run-time, which reduces the burden on these data structures.
Please register to reply