Skip to content
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

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

Open
99sono opened this issue May 24, 2024 · 1 comment

Comments

@99sono
Copy link

99sono commented May 24, 2024

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:

  1. 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.

  2. 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.

  3. Addressing the Issue:
    Our current focus is on resolving the specific problem related to this highly popular cache key.

  4. 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:

  1. 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.

  2. The Fatal Cache Key:
    One particular cache key stands out—it's incredibly popular. Unfortunately, its popularity becomes a bottleneck, affecting overall performance.

  3. 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.

  4. 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?

  5. 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

    public ReadLockAcquisitionMetadata createReadLockAcquisitionMetadata(ConcurrencyManager concurrencyManager) {
        final boolean isAllowTakingStackTraceDuringReadLockAcquisition = isAllowTakingStackTraceDuringReadLockAcquisition();
        String currentThreadStackTraceInformation = TraceLocalization.buildMessage("concurrency_util_read_lock_acquisition_metadata");
        long currentThreadStackTraceInformationCpuTimeCostMs = 0l;
        if (isAllowTakingStackTraceDuringReadLockAcquisition) {
            long startTimeMillis = System.currentTimeMillis();
            currentThreadStackTraceInformation = enrichGenerateThreadDumpForCurrentThread();
            long endTimeMillis = System.currentTimeMillis();
            currentThreadStackTraceInformationCpuTimeCostMs = endTimeMillis - startTimeMillis;
        }
        int numberOfReadersOnCacheKeyBeforeIncrementingByOne = concurrencyManager.getNumberOfReaders();
        // data in ReadLockAcquisitionMetadata are immutable it reflects an accurate snapshot of the time of acquisition
        return new ReadLockAcquisitionMetadata(concurrencyManager, numberOfReadersOnCacheKeyBeforeIncrementingByOne,
                currentThreadStackTraceInformation, currentThreadStackTraceInformationCpuTimeCostMs);
    }

The actual line of code that we are wanting to patch is this

 String currentThreadStackTraceInformation = TraceLocalization.buildMessage("concurrency_util_read_lock_acquisition_metadata");

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,.

    final boolean isAllowTakingStackTraceDuringReadLockAcquisition = 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");
        String currentThreadStackTraceInformation =   "No stack trace take. isAllowTakingStackTraceDuringReadLockAcquisition is false.";
      
        long currentThreadStackTraceInformationCpuTimeCostMs = 0l;
        if (isAllowTakingStackTraceDuringReadLockAcquisition) {
            long startTimeMillis = System.currentTimeMillis();
            currentThreadStackTraceInformation = enrichGenerateThreadDumpForCurrentThread();
            long endTimeMillis = System.currentTimeMillis();
            currentThreadStackTraceInformationCpuTimeCostMs = endTimeMillis - startTimeMillis;
        }
        int numberOfReadersOnCacheKeyBeforeIncrementingByOne = concurrencyManager.getNumberOfReaders();
        // data in ReadLockAcquisitionMetadata are immutable it reflects an accurate snapshot of the time of acquisition
        return new ReadLockAcquisitionMetadata(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.

@rfelcman
Copy link
Contributor

Hello we did some logging performance improvement in #2174 .
Code change like String currentThreadStackTraceInformation = "No stack trace take. isAllowTakingStackTraceDuringReadLockAcquisition is false."; doesn't suite into current EclipseLink code style as it leads into logging messages spread across so many classes and not in few central resource bundles like https://github.com/eclipse-ee4j/eclipselink/tree/2.7/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants