| /* |
| * Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| package org.eclipse.persistence.internal.helper.type; |
| |
| import org.eclipse.persistence.internal.helper.ConcurrencyManager; |
| import org.eclipse.persistence.internal.helper.ConcurrencyUtil; |
| |
| import java.util.List; |
| import java.util.Map; |
| |
| public class DeadLockComponent { |
| |
| Thread threadNotAbleToAccessResource; |
| |
| // Mutually exclusive boolean flags |
| /** |
| * One of the code spots a thread can get stuck is when it is waiting for |
| * {@link org.eclipse.persistence.internal.helper.ConcurrencyManager#isBuildObjectOnThreadComplete(Thread, Map, List, boolean)} to |
| * return true in the {@code CacheKey.releaseDeferredLock} |
| * |
| * <P> |
| * TRUE VALUE: <br> |
| * This is the least obvious of all scenario. When a thread is stuck on a deferred lock it wanted a key that it |
| * could not get for object building. So it needs to make sure the key is no longer acquired by anybody or if |
| * anybody is owning the key that this thread is also delcaring itself as finished and no longer to building |
| * anything. |
| * |
| * <P> |
| * we will need to re-write the |
| * {@link org.eclipse.persistence.internal.helper.ConcurrencyManager#isBuildObjectOnThreadComplete(Thread, Map, List, boolean)} |
| * to be able to know what thread and what cache key is being thorny point on object building. |
| * |
| */ |
| private boolean stuckOnReleaseDeferredLock; |
| |
| /** |
| * The current thread wants to do an acquire on a cache key but is not able to get the cache key. So it is stuck. |
| */ |
| private boolean stuckThreadAcquiringLockForWriting; |
| |
| /** |
| * The current thread wants to do an acquire on a cache key but the cache key is not available for reading. So the |
| * thread is stuck. |
| */ |
| private boolean stuckThreadAcquiringLockForReading; |
| |
| // The cache key that is at the heart of the problems of the current thread. |
| /** |
| * Then a thread wants to acquire a specific cache key and cannot get it we can put explicit information about cache |
| * key. |
| */ |
| private ConcurrencyManager cacheKeyThreadWantsToAcquireButCannotGet; |
| |
| // Flags that would be set to true if we run out of happy path options to expand and realize |
| // that the cache key our thread wants seems to be corrupted |
| |
| /** |
| * after some explosions in the concurrent manager, we believe to already have seen the cache corrupted where a |
| * cache key had an active thread that was no longer doing anything. This could lead to a dummy dead lock. |
| */ |
| private boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread; |
| |
| /** |
| * We are able to track everyone that registers for READING. So if we see a cache key with a number of readers we |
| * are not able to justify and have no other routes to expand we need to consider the possibility of being stuck due |
| * to a cache key that has a number of readers greater than the known readers. |
| */ |
| private boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders; |
| |
| // Recursion unwinding. |
| |
| /** |
| * The next thread in the dead lock sequence. |
| */ |
| private DeadLockComponent nextThreadPartOfDeadLock; |
| |
| /** |
| * Set to true on the very first DTO we build - at the moment when we finally disocver our dead lock. |
| * |
| */ |
| private boolean isFirstRepeatingThreadThatExplainsDeadLock; |
| |
| /** |
| * Create a new DeadLockComponent. |
| * |
| */ |
| public DeadLockComponent(Thread threadNotAbleToAccessResource, boolean stuckOnReleaseDeferredLock, |
| boolean stuckThreadAcquiringLockForWriting, boolean stuckThreadAcquiringLockForReading, |
| ConcurrencyManager cacheKeyThreadWantsToAcquireButCannotGet, |
| boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread, |
| boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders, |
| DeadLockComponent nextThreadPartOfDeadLock) { |
| super(); |
| this.threadNotAbleToAccessResource = threadNotAbleToAccessResource; |
| this.stuckOnReleaseDeferredLock = stuckOnReleaseDeferredLock; |
| this.stuckThreadAcquiringLockForWriting = stuckThreadAcquiringLockForWriting; |
| this.stuckThreadAcquiringLockForReading = stuckThreadAcquiringLockForReading; |
| this.cacheKeyThreadWantsToAcquireButCannotGet = cacheKeyThreadWantsToAcquireButCannotGet; |
| this.deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread = deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread; |
| this.deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders = deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders; |
| this.nextThreadPartOfDeadLock = nextThreadPartOfDeadLock; |
| this.isFirstRepeatingThreadThatExplainsDeadLock = false; |
| } |
| |
| /** |
| * Constructor to be used when we start undoing our recursion due to having found a repeated thread that allows to |
| * conclude we have discovered our dead lock. When we do this, we will not populate any additionla data on the DTO. |
| * |
| * Create a new DeadLockComponent. |
| * |
| */ |
| public DeadLockComponent(Thread threadNotAbleToAccessResource) { |
| // our deadlock has been found |
| this.threadNotAbleToAccessResource = threadNotAbleToAccessResource; |
| this.isFirstRepeatingThreadThatExplainsDeadLock = true; |
| } |
| |
| /** Getter for {@link #threadNotAbleToAccessResource} */ |
| public Thread getThreadNotAbleToAccessResource() { |
| return threadNotAbleToAccessResource; |
| } |
| |
| /** Setter for {@link #threadNotAbleToAccessResource} */ |
| public void setThreadNotAbleToAccessResource(Thread threadNotAbleToAccessResource) { |
| this.threadNotAbleToAccessResource = threadNotAbleToAccessResource; |
| } |
| |
| /** Getter for {@link #stuckOnReleaseDeferredLock} */ |
| public boolean isStuckOnReleaseDeferredLock() { |
| return stuckOnReleaseDeferredLock; |
| } |
| |
| /** Setter for {@link #stuckOnReleaseDeferredLock} */ |
| public void setStuckOnReleaseDeferredLock(boolean stuckOnReleaseDeferredLock) { |
| this.stuckOnReleaseDeferredLock = stuckOnReleaseDeferredLock; |
| } |
| |
| /** Getter for {@link #stuckThreadAcquiringLockForWriting} */ |
| public boolean isStuckThreadAcquiringLockForWriting() { |
| return stuckThreadAcquiringLockForWriting; |
| } |
| |
| /** Setter for {@link #stuckThreadAcquiringLockForWriting} */ |
| public void setStuckThreadAcquiringLockForWriting(boolean stuckThreadAcquiringLockForWriting) { |
| this.stuckThreadAcquiringLockForWriting = stuckThreadAcquiringLockForWriting; |
| } |
| |
| /** Getter for {@link #stuckThreadAcquiringLockForReading} */ |
| public boolean isStuckThreadAcquiringLockForReading() { |
| return stuckThreadAcquiringLockForReading; |
| } |
| |
| /** Setter for {@link #stuckThreadAcquiringLockForReading} */ |
| public void setStuckThreadAcquiringLockForReading(boolean stuckThreadAcquiringLockForReading) { |
| this.stuckThreadAcquiringLockForReading = stuckThreadAcquiringLockForReading; |
| } |
| |
| /** Getter for {@link #cacheKeyThreadWantsToAcquireButCannotGet} */ |
| public ConcurrencyManager getCacheKeyThreadWantsToAcquireButCannotGet() { |
| return cacheKeyThreadWantsToAcquireButCannotGet; |
| } |
| |
| /** Setter for {@link #cacheKeyThreadWantsToAcquireButCannotGet} */ |
| public void setCacheKeyThreadWantsToAcquireButCannotGet( |
| ConcurrencyManager cacheKeyThreadWantsToAcquireButCannotGet) { |
| this.cacheKeyThreadWantsToAcquireButCannotGet = cacheKeyThreadWantsToAcquireButCannotGet; |
| } |
| |
| /** Getter for {@link #deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread} */ |
| public boolean isDeadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread() { |
| return deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread; |
| } |
| |
| /** Setter for {@link #deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread} */ |
| public void setDeadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread( |
| boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread) { |
| this.deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread = deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread; |
| } |
| |
| /** Getter for {@link #deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders} */ |
| public boolean isDeadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders() { |
| return deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders; |
| } |
| |
| /** Setter for {@link #deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders} */ |
| public void setDeadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders( |
| boolean deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders) { |
| this.deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders = deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders; |
| } |
| |
| /** Getter for {@link #nextThreadPartOfDeadLock} */ |
| public DeadLockComponent getNextThreadPartOfDeadLock() { |
| return nextThreadPartOfDeadLock; |
| } |
| |
| /** Setter for {@link #nextThreadPartOfDeadLock} */ |
| public void setNextThreadPartOfDeadLock(DeadLockComponent nextThreadPartOfDeadLock) { |
| this.nextThreadPartOfDeadLock = nextThreadPartOfDeadLock; |
| } |
| |
| /** Getter for {@link #isFirstRepeatingThreadThatExplainsDeadLock} */ |
| public boolean isFirstRepeatingThreadThatExplainsDeadLock() { |
| return isFirstRepeatingThreadThatExplainsDeadLock; |
| } |
| |
| /** Setter for {@link #isFirstRepeatingThreadThatExplainsDeadLock} */ |
| public void setFirstRepeatingThreadThatExplainsDeadLock(boolean isFirstRepeatingThreadThatExplainsDeadLock) { |
| this.isFirstRepeatingThreadThatExplainsDeadLock = isFirstRepeatingThreadThatExplainsDeadLock; |
| } |
| |
| @Override |
| public String toString() { |
| return "\nDeadLockComponent [\n------->threadNotAbleToAccessResource=" |
| + threadNotAbleToAccessResource.getName() + "\n, stuckOnReleaseDeferredLock=" |
| + stuckOnReleaseDeferredLock |
| + ", stuckThreadAcquiringLockForWriting=" + stuckThreadAcquiringLockForWriting |
| + ", stuckThreadAcquiringLockForReading=" + stuckThreadAcquiringLockForReading |
| + ",\n-------> cacheKeyThreadWantsToAcquireButCannotGet=" |
| + ConcurrencyUtil.SINGLETON |
| .createToStringExplainingOwnedCacheKey(cacheKeyThreadWantsToAcquireButCannotGet) |
| + "\n, deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread=" |
| + deadLockPotentiallyCausedByCacheKeyWithCorruptedActiveThread |
| + ", deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders=" |
| + deadLockPotentiallyCausedByCacheKeyWithCorruptedNumberOfReaders |
| + ", isFirstRepeatingThreadThatExplainsDeadLock=" + isFirstRepeatingThreadThatExplainsDeadLock + "]\n"; |
| } |
| } |