You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
High amount of Acquire and Release lock acquisition time being wasted on I18n localtiozation cost of low value message - ReadLockManager.addReadLock is being slow because of ConcurrencyUtil.createReadLockAcquisitionMetadata because of TraceLocalization.buildMessage("concurrency_util_read_lock_acquisition_metadata")
#2152
All the massive dump information on this bug has been reported to Oracle via a private channel.
In a specific live application where the level of concurrency is really high, we have a very specific CacheKey that is extremely popular. We have encountered a MassiveDump being generated not because of a deadlock, but as a result of throttling the performance of the application attributed to this bottleneck cache key. The bottleneck cache key looks like this
Upon close examination of the cache key provided above, a few observations become evident:
High Number of Readers:
The current number of readers associated with this cache key is exceptionally high. Specifically, we have a total of 90 threads that currently own the cache key for reading. These threads may need to invoke the org.eclipse.persistence.internal.helper.ConcurrencyManager.releaseReadLock(ConcurrencyManager.java:697) method at any given time.
Potential Contention:
Additionally, there may be just as many threads (or even more) attempting to acquire this cache key for reading. These threads will contend for access to the synchronized block defined in the org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLockNoWait(ConcurrencyManager.java:373) method.
Addressing the Issue:
Our current focus is on resolving the specific problem related to this highly popular cache key.
Blocked Threads:
It's crucial to note that our extensive thread dump reveals a significant number of threads blocked on the synchronized block. These threads are actively competing to either increment or decrement the count of readers. As an illustration, I've included two examples of such threads from our massive dump (page 01).
Here is the example of thread BLOCKED trying to release this problematic CacheKey.
[ACTIVE] ExecuteThread: '16' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: BLOCKED
at org.eclipse.persistence.internal.helper.ConcurrencyManager.releaseReadLock(ConcurrencyManager.java:697)
at org.eclipse.persistence.internal.identitymaps.CacheKey.releaseReadLock(CacheKey.java:615)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1103)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1014)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(UnitOfWorkIdentityMapAccessor.java:211)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:139)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4093)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4016)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementUnitOfWorkClone(CollectionMapping.java:313)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementClone(CollectionMapping.java:326)
at org.eclipse.persistence.internal.queries.ContainerPolicy.addNextValueFromIteratorInto(ContainerPolicy.java:217)
at org.eclipse.persistence.mappings.CollectionMapping.buildCloneForPartObject(CollectionMapping.java:228)
at org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder.buildCloneFor(UnitOfWorkQueryValueHolder.java:62)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:177)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:238)
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:97)
at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:275)
at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:458)
at org.eclipse.persistence.indirection.IndirectList$1.<init>(IndirectList.java:602)
at org.eclipse.persistence.indirection.IndirectList.listIterator(IndirectList.java:601)
at org.eclipse.persistence.indirection.IndirectList.iterator(IndirectList.java:560)
Next we have the example of another thread equally blocked trying to access this contentious cachekey, this time to increase the counter of readers.
[ACTIVE] ExecuteThread: '17' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: BLOCKED
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLockNoWait(ConcurrencyManager.java:373)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLockNoWait(CacheKey.java:366)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLockAndRelatedLocks(WriteLockManager.java:225)
at org.eclipse.persistence.internal.helper.WriteLockManager.checkAndLockObject(WriteLockManager.java:582)
at org.eclipse.persistence.internal.helper.WriteLockManager.traverseRelatedLocks(WriteLockManager.java:311)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLockAndRelatedLocks(WriteLockManager.java:240)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLocksForClone(WriteLockManager.java:152)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1056)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1014)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(UnitOfWorkIdentityMapAccessor.java:211)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:139)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4093)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4016)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementUnitOfWorkClone(CollectionMapping.java:313)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementClone(CollectionMapping.java:326)
at org.eclipse.persistence.internal.queries.ContainerPolicy.addNextValueFromIteratorInto(ContainerPolicy.java:217)
at org.eclipse.persistence.mappings.CollectionMapping.buildCloneForPartObject(CollectionMapping.java:228)
at org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder.buildCloneFor(UnitOfWorkQueryValueHolder.java:62)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:177)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:238)
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:97)
at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:275)
at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:458)
at org.eclipse.persistence.indirection.IndirectList$1.<init>(IndirectList.java:602)
at org.eclipse.persistence.indirection.IndirectList.listIterator(IndirectList.java:601)
at org.eclipse.persistence.indirection.IndirectList.iterator(IndirectList.java:560)
Next we have the example of yet another thread blocked on different pattern to acquire read lock.
[ACTIVE] ExecuteThread: '118' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: BLOCKED
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:336)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLock(CacheKey.java:355)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1059)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1014)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(UnitOfWorkIdentityMapAccessor.java:211)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:139)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4093)
at org.eclipse.persistence.queries.ObjectBuildingQuery.registerIndividualResult(ObjectBuildingQuery.java:472)
at org.eclipse.persistence.queries.ReadObjectQuery.conformResult(ReadObjectQuery.java:383)
at org.eclipse.persistence.queries.ReadObjectQuery.registerResultInUnitOfWork(ReadObjectQuery.java:897)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkEarlyReturn(ObjectLevelReadQuery.java:947)
at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:848)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1191)
at org.eclipse.persistence.queries.ReadObjectQuery.execute(ReadObjectQuery.java:447)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1279)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:3004)
at whatever.MonitoringProfiler.profileExecutionOfQuery(SynQQueryMonitoringProfiler.java:107)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1930)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1914)
at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1864)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.executeQuery(EntityManagerImpl.java:1012)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.findInternal(EntityManagerImpl.java:954)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:830)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.find(EntityManagerImpl.java:696)
at jdk.internal.reflect.GeneratedMethodAccessor422.invoke(Unknown Source)
at [email protected]/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at [email protected]/java.lang.reflect.Method.invoke(Method.java:566)
at weblogic.persistence.BasePersistenceContextProxyImpl.invoke(BasePersistenceContextProxyImpl.java:97)
at weblogic.persistence.TransactionalEntityManagerProxyImpl.invoke(TransactionalEntityManagerProxyImpl.java:164)
at weblogic.persistence.BasePersistenceContextProxyImpl.invoke(BasePersistenceContextProxyImpl.java:86)
at com.sun.proxy.$Proxy528.find(Unknown Source)
at jdk.internal.reflect.GeneratedMethodAccessor418.invoke(Unknown Source)
at [email protected]/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at [email protected]/java.lang.reflect.Method.invoke(Method.java:566)
at org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:106)
at org.jboss.weld.generated.proxiesx.persistence.EntityManager$2044256704$Proxy$_$$_WeldClientProxy.find(Unknown Source)
Understanding the Concurrency Challenges with the Cache Key
Up to this point, we should understand the following:
High Level of Concurrency:
Our application experiences an exceptionally high level of concurrency. It is in the nature of this application.
The sheer volume of concurrency requests places significant strain on the eclipselink cache.
The Fatal Cache Key:
One particular cache key stands out—it's incredibly popular. Unfortunately, its popularity becomes a bottleneck, affecting overall performance.
Read Lock Performance:
The code responsible for acquiring and releasing read locks is struggling to keep up with the demand generated by this highly accessed cache key. The sheer concurrency exacerbates the issue. While read lock acquisition/release performance is acceptable for your average CacheKey, it falls short for a CacheKey as popular as this one in an application under as much pressure and parallelism as this.
Identifying the Bottleneck:
Instead of focusing solely on reducing the number of accesses to this cache key, let's delve into the root cause of the slowdown. What specifically causes delays in the CacheKey code related to read locks?
Surprising Discovery:
The answer surprised me. As I expected, it is related to the logic of keeping the very valuable data about threads acquiring CacheKeys for reading. Yes, it is related to the code of the ReadLockManager. This much I expected. However, the surprising aspect is the specific code within the ReadLockManager that is at fault
When we explore the threads that are currently withing the synchronized CacheKey and we have a look at what they are doing we find patters such as the following.
I will only put a subset of the hits.
"[ACTIVE] ExecuteThread: '384' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/sun.util.locale.BaseLocale.hashCode(BaseLocale.java:148)
at [email protected]/java.util.Locale.hashCode(Locale.java:2104)
at [email protected]/java.util.ResourceBundle$CacheKey.hashCode(ResourceBundle.java:744)
at [email protected]/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
at [email protected]/java.util.ResourceBundle.findBundleInCache(ResourceBundle.java:2074)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1750)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1662)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1593)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1556)
at [email protected]/java.util.ResourceBundle.getBundle(ResourceBundle.java:932)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:63)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
this is is the killer thread in massive dump 01:
[ACTIVE] ExecuteThread: '350' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.util.HashMap.hash(HashMap.java:340)
at [email protected]/java.util.HashMap.get(HashMap.java:553)
at [email protected]/java.util.ListResourceBundle.handleGetObject(ListResourceBundle.java:135)
at [email protected]/java.util.ResourceBundle.getObject(ResourceBundle.java:555)
at [email protected]/java.util.ResourceBundle.getString(ResourceBundle.java:521)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:64)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLock(CacheKey.java:355)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLockNoWait(ConcurrencyManager.java:374)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLockNoWait(CacheKey.java:366)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLockAndRelatedLocks(WriteLockManager.java:225)
at org.eclipse.persistence.internal.helper.WriteLockManager.acquireLocksForClone(WriteLockManager.java:152)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1056)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.cloneAndRegisterObject(UnitOfWorkImpl.java:1014)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getAndCloneCacheKeyFromParent(UnitOfWorkIdentityMapAccessor.java:211)
at org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor.getFromIdentityMap(UnitOfWorkIdentityMapAccessor.java:139)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4093)
at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerExistingObject(UnitOfWorkImpl.java:4016)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementUnitOfWorkClone(CollectionMapping.java:313)
at org.eclipse.persistence.mappings.CollectionMapping.buildElementClone(CollectionMapping.java:326)
at org.eclipse.persistence.internal.queries.ContainerPolicy.addNextValueFromIteratorInto(ContainerPolicy.java:217)
at org.eclipse.persistence.mappings.CollectionMapping.buildCloneForPartObject(CollectionMapping.java:228)
at org.eclipse.persistence.internal.indirection.UnitOfWorkQueryValueHolder.buildCloneFor(UnitOfWorkQueryValueHolder.java:62)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:177)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:238)
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:97)
at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:275)
at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:458)
at org.eclipse.persistence.indirection.IndirectList$1.<init>(IndirectList.java:602)
at org.eclipse.persistence.indirection.IndirectList.listIterator(IndirectList.java:601)
at org.eclipse.persistence.indirection.IndirectList.iterator(IndirectList.java:560)
[ACTIVE] ExecuteThread: '350' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.util.HashMap.hash(HashMap.java:340)
at [email protected]/java.util.HashMap.get(HashMap.java:553)
at [email protected]/java.util.ListResourceBundle.handleGetObject(ListResourceBundle.java:135)
at [email protected]/java.util.ResourceBundle.getObject(ResourceBundle.java:555)
at [email protected]/java.util.ResourceBundle.getString(ResourceBundle.java:521)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:64)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
[ACTIVE] ExecuteThread: '318' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.lang.StringLatin1.equals(StringLatin1.java:95)
at [email protected]/java.lang.String.equals(String.java:1009)
at [email protected]/java.util.ResourceBundle$CacheKey.equals(ResourceBundle.java:725)
at [email protected]/java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:940)
at [email protected]/java.util.ResourceBundle.findBundleInCache(ResourceBundle.java:2074)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1750)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.findBundle(ResourceBundle.java:1728)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1662)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1593)
at [email protected]/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1556)
at [email protected]/java.util.ResourceBundle.getBundle(ResourceBundle.java:932)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:63)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
[STANDBY] ExecuteThread: '228' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLock(CacheKey.java:355)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLockNoWait(ConcurrencyManager.java:374)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLockNoWait(CacheKey.java:366)
"[STANDBY] ExecuteThread: '185' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.lang.AbstractStringBuilder.appendChars(AbstractStringBuilder.java:1695)
at [email protected]/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:634)
at [email protected]/java.lang.StringBuffer.append(StringBuffer.java:392)
at [email protected]/java.text.MessageFormat.subformat(MessageFormat.java:1357)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:885)
at [email protected]/java.text.Format.format(Format.java:158)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:860)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:74)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLock(CacheKey.java:355)
[STANDBY] ExecuteThread: '185' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.lang.AbstractStringBuilder.appendChars(AbstractStringBuilder.java:1695)
at [email protected]/java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:634)
at [email protected]/java.lang.StringBuffer.append(StringBuffer.java:392)
at [email protected]/java.text.MessageFormat.subformat(MessageFormat.java:1357)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:885)
at [email protected]/java.text.Format.format(Format.java:158)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:860)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:74)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
at org.eclipse.persistence.internal.identitymaps.CacheKey.acquireReadLock(CacheKey.java:355)
[STANDBY] ExecuteThread: '152' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.text.MessageFormat.applyPattern(MessageFormat.java:522)
at [email protected]/java.text.MessageFormat.<init>(MessageFormat.java:370)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:859)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:74)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
"[ACTIVE] ExecuteThread: '100' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.text.MessageFormat.applyPattern(MessageFormat.java:448)
at [email protected]/java.text.MessageFormat.<init>(MessageFormat.java:370)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:859)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:74)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLock(ConcurrencyManager.java:362)
[STANDBY] ExecuteThread: '3' for queue: 'weblogic.kernel.Default (self-tuning)'"
java.lang.Thread.State: RUNNABLE
at [email protected]/java.text.MessageFormat.applyPattern(MessageFormat.java:448)
at [email protected]/java.text.MessageFormat.<init>(MessageFormat.java:370)
at [email protected]/java.text.MessageFormat.format(MessageFormat.java:859)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:74)
at org.eclipse.persistence.internal.localization.EclipseLinkLocalization.buildMessage(EclipseLinkLocalization.java:36)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:31)
at org.eclipse.persistence.internal.localization.TraceLocalization.buildMessage(TraceLocalization.java:43)
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
at org.eclipse.persistence.internal.helper.ReadLockManager.addReadLock(ReadLockManager.java:80)
at org.eclipse.persistence.internal.helper.ConcurrencyManager.addReadLockToReadLockManager(ConcurrencyManager.java:963)
Now we have our answer.
The culprit is this line of code here: at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883).
In short it is a mix of a lot of CPU time spent between gettig the i18n ResourceBundle of Eclipselink and the code behind MessageFormat.format.
Between ResourceBundle.getBundle and java.text.MessageFormat.format
A tremendous amount of CPU time is wasted on every single read lock acquisition.
If we now ask ourselves, what exactly this localized message are trying to get here.
let us have look at the code
publicReadLockAcquisitionMetadatacreateReadLockAcquisitionMetadata(ConcurrencyManagerconcurrencyManager) {
finalbooleanisAllowTakingStackTraceDuringReadLockAcquisition = isAllowTakingStackTraceDuringReadLockAcquisition();
StringcurrentThreadStackTraceInformation = TraceLocalization.buildMessage("concurrency_util_read_lock_acquisition_metadata");
longcurrentThreadStackTraceInformationCpuTimeCostMs = 0l;
if (isAllowTakingStackTraceDuringReadLockAcquisition) {
longstartTimeMillis = System.currentTimeMillis();
currentThreadStackTraceInformation = enrichGenerateThreadDumpForCurrentThread();
longendTimeMillis = System.currentTimeMillis();
currentThreadStackTraceInformationCpuTimeCostMs = endTimeMillis - startTimeMillis;
}
intnumberOfReadersOnCacheKeyBeforeIncrementingByOne = concurrencyManager.getNumberOfReaders();
// data in ReadLockAcquisitionMetadata are immutable it reflects an accurate snapshot of the time of acquisitionreturnnewReadLockAcquisitionMetadata(concurrencyManager, numberOfReadersOnCacheKeyBeforeIncrementingByOne,
currentThreadStackTraceInformation, currentThreadStackTraceInformationCpuTimeCostMs);
}
The actual line of code that we are wanting to patch is this
This shocked me quite a bit.
I was expecting to be much deeper problem, some collection cost withig add/removing metadata.
But no, it is High Cpu cost just to initialize a constant with the text
{ "concurrency_util_read_lock_acquisition_metadata", "No stack trace take. isAllowTakingStackTraceDuringReadLockAcquisition is false."}
In the meantime, I will provide our project team a patched eclipselink where the line of code lookslike this,.
finalbooleanisAllowTakingStackTraceDuringReadLockAcquisition = isAllowTakingStackTraceDuringReadLockAcquisition();
// TRK-32421 - we have seen that cost of calling Eclipselink resource bundle is really high// the official solution should be store a static constant with this value// we do not care about supporting localization for technical metadata. For us english is more than good enough for technical people// so we just hard code this text.// see github issue ...// String currentThreadStackTraceInformation = TraceLocalization.buildMessage("concurrency_util_read_lock_acquisition_metadata");StringcurrentThreadStackTraceInformation = "No stack trace take. isAllowTakingStackTraceDuringReadLockAcquisition is false.";
longcurrentThreadStackTraceInformationCpuTimeCostMs = 0l;
if (isAllowTakingStackTraceDuringReadLockAcquisition) {
longstartTimeMillis = System.currentTimeMillis();
currentThreadStackTraceInformation = enrichGenerateThreadDumpForCurrentThread();
longendTimeMillis = System.currentTimeMillis();
currentThreadStackTraceInformationCpuTimeCostMs = endTimeMillis - startTimeMillis;
}
intnumberOfReadersOnCacheKeyBeforeIncrementingByOne = concurrencyManager.getNumberOfReaders();
// data in ReadLockAcquisitionMetadata are immutable it reflects an accurate snapshot of the time of acquisitionreturnnewReadLockAcquisitionMetadata(concurrencyManager, numberOfReadersOnCacheKeyBeforeIncrementingByOne,
currentThreadStackTraceInformation, currentThreadStackTraceInformationCpuTimeCostMs);
}
This change should significantly boost cache performance without compromising any of the precious metadata we want to retain.
However, I’d like to caution about the following: If possible, EclipseLink should avoid frequent calls to the ResourceBundle.getBundle code. The search for the resource bundle is expensive, and the LOCALE of a running server essentially never changes once it is set. Calls to APIs like EclipseLinkLocalization.buildMessage should minimize unnecessary loading of the resource bundle. Implementing some form of caching could provide the answer without additional overhead.
The text was updated successfully, but these errors were encountered:
All the massive dump information on this bug has been reported to Oracle via a private channel.
In a specific live application where the level of concurrency is really high, we have a very specific CacheKey that is extremely popular. We have encountered a MassiveDump being generated not because of a deadlock, but as a result of throttling the performance of the application attributed to this bottleneck cache key. The bottleneck cache key looks like this
CacheKey
(WhateverEntity):
(primaryKey: WhateverEntityPrimaryKey)
(object hash code: 1746196526)
(cacheKeyClass: org.eclipse.persistence.internal.identitymaps.HardCacheWeakIdentityMap.ReferenceCacheKey)
(cacheKey hash code: 1828274617)
(current cache key owner/activeThread: Null)
(getNumberOfReaders: 90)
(concurrencyManagerId: 105,503)
(concurrencyManagerCreationDate: 2024-05-06 05:53:07.768)
(totalNumberOfTimeCacheKeyAcquiredForReading: 22,594,187,969)
(totalNumberOfTimeCacheKeyReleasedForReading: 22,594,187,879)
Upon close examination of the cache key provided above, a few observations become evident:
High Number of Readers:
The current number of readers associated with this cache key is exceptionally high. Specifically, we have a total of 90 threads that currently own the cache key for reading. These threads may need to invoke the
org.eclipse.persistence.internal.helper.ConcurrencyManager.releaseReadLock(ConcurrencyManager.java:697)
method at any given time.Potential Contention:
Additionally, there may be just as many threads (or even more) attempting to acquire this cache key for reading. These threads will contend for access to the synchronized block defined in the
org.eclipse.persistence.internal.helper.ConcurrencyManager.acquireReadLockNoWait(ConcurrencyManager.java:373)
method.Addressing the Issue:
Our current focus is on resolving the specific problem related to this highly popular cache key.
Blocked Threads:
It's crucial to note that our extensive thread dump reveals a significant number of threads blocked on the synchronized block. These threads are actively competing to either increment or decrement the count of readers. As an illustration, I've included two examples of such threads from our massive dump (page 01).
Here is the example of thread BLOCKED trying to release this problematic CacheKey.
Next we have the example of another thread equally blocked trying to access this contentious cachekey, this time to increase the counter of readers.
Next we have the example of yet another thread blocked on different pattern to acquire read lock.
Understanding the Concurrency Challenges with the Cache Key
Up to this point, we should understand the following:
High Level of Concurrency:
Our application experiences an exceptionally high level of concurrency. It is in the nature of this application.
The sheer volume of concurrency requests places significant strain on the eclipselink cache.
The Fatal Cache Key:
One particular cache key stands out—it's incredibly popular. Unfortunately, its popularity becomes a bottleneck, affecting overall performance.
Read Lock Performance:
The code responsible for acquiring and releasing read locks is struggling to keep up with the demand generated by this highly accessed cache key. The sheer concurrency exacerbates the issue. While read lock acquisition/release performance is acceptable for your average CacheKey, it falls short for a CacheKey as popular as this one in an application under as much pressure and parallelism as this.
Identifying the Bottleneck:
Instead of focusing solely on reducing the number of accesses to this cache key, let's delve into the root cause of the slowdown. What specifically causes delays in the CacheKey code related to read locks?
Surprising Discovery:
The answer surprised me. As I expected, it is related to the logic of keeping the very valuable data about threads acquiring CacheKeys for reading. Yes, it is related to the code of the ReadLockManager. This much I expected. However, the surprising aspect is the specific code within the ReadLockManager that is at fault
When we explore the threads that are currently withing the synchronized CacheKey and we have a look at what they are doing we find patters such as the following.
I will only put a subset of the hits.
Now we have our answer.
The culprit is this line of code here:
at org.eclipse.persistence.internal.helper.ConcurrencyUtil.createReadLockAcquisitionMetadata(ConcurrencyUtil.java:1883)
.In short it is a mix of a lot of CPU time spent between gettig the i18n ResourceBundle of Eclipselink and the code behind MessageFormat.format.
Between
ResourceBundle.getBundle
andjava.text.MessageFormat.format
A tremendous amount of CPU time is wasted on every single read lock acquisition.
If we now ask ourselves, what exactly this localized message are trying to get here.
let us have look at the code
The actual line of code that we are wanting to patch is this
This shocked me quite a bit.
I was expecting to be much deeper problem, some collection cost withig add/removing metadata.
But no, it is High Cpu cost just to initialize a constant with the text
{ "concurrency_util_read_lock_acquisition_metadata", "No stack trace take. isAllowTakingStackTraceDuringReadLockAcquisition is false."}
In the meantime, I will provide our project team a patched eclipselink where the line of code lookslike this,.
This change should significantly boost cache performance without compromising any of the precious metadata we want to retain.
However, I’d like to caution about the following: If possible, EclipseLink should avoid frequent calls to the ResourceBundle.getBundle code. The search for the resource bundle is expensive, and the LOCALE of a running server essentially never changes once it is set. Calls to APIs like EclipseLinkLocalization.buildMessage should minimize unnecessary loading of the resource bundle. Implementing some form of caching could provide the answer without additional overhead.
The text was updated successfully, but these errors were encountered: