blob: 44ae51286d7d99ebbeab870d2881493c202c6b89 [file] [log] [blame]
/*
* 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";
}
}