From a296980c0fd9bcb2d125978e953589d2fa49cc7b Mon Sep 17 00:00:00 2001 From: Petr Aubrecht Date: Mon, 19 Aug 2024 15:47:58 +0200 Subject: [PATCH] FISH-9063 allow throwing an exception after locks for clone is interrupted --- .../persistence/config/SystemProperties.java | 16 ++++++++++++++++ .../internal/helper/ConcurrencyUtil.java | 10 ++++++++++ .../internal/helper/WriteLockManager.java | 10 +++++++++- .../i18n/TraceLocalizationResource.java | 7 +++++-- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/SystemProperties.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/SystemProperties.java index ea2ca7867d3..5344900fc21 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/SystemProperties.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/config/SystemProperties.java @@ -186,6 +186,22 @@ public class SystemProperties { */ public static final String CONCURRENCY_MANAGER_ALLOW_STACK_TRACE_READ_LOCK = "eclipselink.concurrency.manager.allow.readlockstacktrace"; + /** + *

+ * This property control (enable/disable) if + * ConcurrencyException fired when dead-lock diagnostic is + * enabled. + *

+ * Allowed Values (case sensitive String): + *

+ */ + public static final String CONCURRENCY_MANAGER_ALLOW_INTERRUPTION_OF_LOCKWAIT = "eclipselink.concurrency.manager.allow.interruption.lockwait"; + /** *

* This property control (enable/disable) semaphore in {@link org.eclipse.persistence.internal.descriptors.ObjectBuilder} diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java index 8ff241e34d0..455a5fbbd6d 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java @@ -59,6 +59,7 @@ public class ConcurrencyUtil { public static final int DEFAULT_CONCURRENCY_MANAGER_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS_NO_THREADS = 2; public static final long DEFAULT_CONCURRENCY_SEMAPHORE_MAX_TIME_PERMIT = 2000L; public static final long DEFAULT_CONCURRENCY_SEMAPHORE_LOG_TIMEOUT = 10000L; + private static final boolean DEFAULT_INTERRUPTION_OF_LOCKWAIT = false; private long acquireWaitTime = getLongProperty(SystemProperties.CONCURRENCY_MANAGER_ACQUIRE_WAIT_TIME, DEFAULT_ACQUIRE_WAIT_TIME); private long buildObjectCompleteWaitTime = getLongProperty(SystemProperties.CONCURRENCY_MANAGER_BUILD_OBJECT_COMPLETE_WAIT_TIME, DEFAULT_BUILD_OBJECT_COMPLETE_WAIT_TIME); @@ -68,6 +69,7 @@ public class ConcurrencyUtil { private boolean allowInterruptedExceptionFired = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_ALLOW_INTERRUPTED_EXCEPTION, DEFAULT_INTERRUPTED_EXCEPTION_FIRED); private boolean allowConcurrencyExceptionToBeFiredUp = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_ALLOW_CONCURRENCY_EXCEPTION, DEFAULT_CONCURRENCY_EXCEPTION_FIRED); private boolean allowTakingStackTraceDuringReadLockAcquisition = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_ALLOW_STACK_TRACE_READ_LOCK, DEFAULT_TAKING_STACKTRACE_DURING_READ_LOCK_ACQUISITION); + private boolean allowInterruptionOfLockWait = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_ALLOW_INTERRUPTION_OF_LOCKWAIT, DEFAULT_INTERRUPTION_OF_LOCKWAIT); private boolean useSemaphoreInObjectBuilder = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_OBJECT_BUILDING, DEFAULT_USE_SEMAPHORE_TO_SLOW_DOWN_OBJECT_BUILDING_CONCURRENCY); private boolean useSemaphoreToLimitConcurrencyOnWriteLockManagerAcquireRequiredLocks = getBooleanProperty(SystemProperties.CONCURRENCY_MANAGER_USE_SEMAPHORE_TO_SLOW_DOWN_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS, DEFAULT_USE_SEMAPHORE_TO_SLOW_DOWN_WRITE_LOCK_MANAGER_ACQUIRE_REQUIRED_LOCKS); @@ -300,6 +302,14 @@ public void setAllowTakingStackTraceDuringReadLockAcquisition(boolean allowTakin this.allowTakingStackTraceDuringReadLockAcquisition = allowTakingStackTraceDuringReadLockAcquisition; } + public boolean isInterruptionOfLockWaitEnabled() { + return allowInterruptionOfLockWait; + } + + public void setInterruptionOfLockWaitEnabled(boolean interruptionOfLockWaitEnabled) { + this.allowInterruptionOfLockWait = interruptionOfLockWaitEnabled; + } + public boolean isUseSemaphoreInObjectBuilder() { return useSemaphoreInObjectBuilder; } diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java index 629c532c526..f7e44c11382 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/helper/WriteLockManager.java @@ -37,6 +37,7 @@ import org.eclipse.persistence.internal.sessions.MergeManager; import org.eclipse.persistence.internal.sessions.ObjectChangeSet; import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet; +import org.eclipse.persistence.logging.AbstractSessionLog; import org.eclipse.persistence.logging.SessionLog; import org.eclipse.persistence.mappings.DatabaseMapping; @@ -166,6 +167,7 @@ public Map acquireLocksForClone(Object objectForClone, ClassDescriptor descripto // we will now always check for how long the current thread is stuck in this while loop going nowhere // using the exact same approach we have been adding to the concurrency manager ConcurrencyUtil.SINGLETON.determineIfReleaseDeferredLockAppearsToBeDeadLocked(toWaitOn, whileStartTimeMillis, lockManager, readLockManager, ALLOW_INTERRUPTED_EXCEPTION_TO_BE_FIRED_UP_TRUE); + SessionLog logger = AbstractSessionLog.getLog(); synchronized (toWaitOn) { try { @@ -173,7 +175,12 @@ public Map acquireLocksForClone(Object objectForClone, ClassDescriptor descripto toWaitOn.wait(ConcurrencyUtil.SINGLETON.getAcquireWaitTime());// wait for lock on object to be released } } catch (InterruptedException ex) { - // Ignore exception thread should continue. + // Allow thread interruptions for bad threads stuck in org.eclipse.persistence.internal.helper.WriteLockManager.acquireLocksForClone + if (ConcurrencyUtil.SINGLETON.isInterruptionOfLockWaitEnabled()) { + logger.log(SessionLog.SEVERE, SessionLog.CACHE, "write_lock_manager_allow_interruption_lockwait_interrupted_throws"); + throw ConcurrencyException.waitWasInterrupted(ex.getMessage()); + } + logger.log(SessionLog.FINE, SessionLog.CACHE, "write_lock_manager_allow_interruption_lockwait_interrupted_continues"); } } Object waitObject = toWaitOn.getObject(); @@ -185,6 +192,7 @@ public Map acquireLocksForClone(Object objectForClone, ClassDescriptor descripto toWaitOn = acquireLockAndRelatedLocks(objectForClone, lockedObjects, refreshedObjects, cacheKey, descriptor, cloningSession); if ((toWaitOn != null) && ((++tries) > MAXTRIES)) { // If we've tried too many times abort. + logger.log(SessionLog.FINE, SessionLog.CACHE, "write_lock_manager_lockwait_exceeded_max_tries", MAXTRIES); throw ConcurrencyException.maxTriesLockOnCloneExceded(objectForClone); } } diff --git a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java index fde7ef1317e..6999161df90 100644 --- a/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java +++ b/foundation/org.eclipse.persistence.core/src/main/java/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java @@ -268,8 +268,11 @@ public class TraceLocalizationResource extends ListResourceBundle { + " But our hacked implementation of the isBuildObjectOnThreadComplete was not able to explain what thread and cache key are recursively " + " stopping the candidate thread to make progress... We expect this code spot to never be invoked. " + " Either this thread made progress or if it continues to be stuck in the releaseDeferredLock " - + " we most likely have an implementation bug somewhere. "}, - + + " we most likely have an implementation bug somewhere. "}, + {"write_lock_manager_lockwait_exceeded_max_tries", "Max {0} tries exceeded during Write Lock Manager acquiring locks for clone."}, + {"write_lock_manager_allow_interruption_lockwait_interrupted_throws", "Write Lock Manager was interrupted during acquiring locks for clone and 'eclipselink.concurrency.manager.allow.interruption.lockwait' was set to true, throwing ConcurrencyException"}, + {"write_lock_manager_allow_interruption_lockwait_interrupted_continues", "Write Lock Manager was interrupted during acquiring locks for clone and 'eclipselink.concurrency.manager.allow.interruption.lockwait' was set to false, ignoring and continue"}, + { "XML_call", "XML call" }, { "XML_data_call", "XML data call" }, { "XML_data_delete", "XML data delete" },