From 6e75593c7ac869f0ba6b28206361481f77817c4e 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 | 18 ++++++++++++++---- .../i18n/TraceLocalizationResource.java | 4 ++++ 4 files changed, 44 insertions(+), 4 deletions(-) diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/SystemProperties.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/SystemProperties.java index eee92c9543f..d567579dc7b 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/SystemProperties.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/config/SystemProperties.java @@ -184,6 +184,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/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java index fbe743f0f6e..769ee5fc47d 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/ConcurrencyUtil.java @@ -54,6 +54,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); @@ -63,6 +64,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); @@ -295,6 +297,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/org/eclipse/persistence/internal/helper/WriteLockManager.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/WriteLockManager.java index 5e180ab34d7..c5501dcd9c8 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/WriteLockManager.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/helper/WriteLockManager.java @@ -22,10 +22,13 @@ // - 526957 : Split the logging and trace messages package org.eclipse.persistence.internal.helper; +import java.util.Collection; +import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; -import java.util.*; +import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; @@ -34,7 +37,6 @@ import org.eclipse.persistence.exceptions.ConcurrencyException; import org.eclipse.persistence.internal.helper.linkedlist.ExposedNodeLinkedList; import org.eclipse.persistence.internal.identitymaps.CacheKey; -import org.eclipse.persistence.internal.localization.LoggingLocalization; import org.eclipse.persistence.internal.localization.TraceLocalization; import org.eclipse.persistence.internal.queries.ContainerPolicy; import org.eclipse.persistence.internal.sessions.AbstractSession; @@ -42,6 +44,7 @@ import org.eclipse.persistence.internal.sessions.ObjectChangeSet; import org.eclipse.persistence.internal.sessions.UnitOfWorkChangeSet; import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; +import org.eclipse.persistence.logging.AbstractSessionLog; import org.eclipse.persistence.logging.SessionLog; import org.eclipse.persistence.mappings.DatabaseMapping; @@ -169,6 +172,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 { @@ -176,7 +180,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(); @@ -188,6 +197,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); } } @@ -778,4 +788,4 @@ private static Set getCacheKeysThatCouldNotBeAcquiredByThrea // (b) We are certain the map is not empty anymore return the set return THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS.get(thread); } -} \ No newline at end of file +} diff --git a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java index f217f11463c..38539408540 100644 --- a/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java +++ b/foundation/org.eclipse.persistence.core/src/org/eclipse/persistence/internal/localization/i18n/TraceLocalizationResource.java @@ -269,6 +269,10 @@ public class TraceLocalizationResource extends ListResourceBundle { + " 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. "}, + {"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" },