Skip to content

Commit

Permalink
DeadLock diagnostic fix (#2288)
Browse files Browse the repository at this point in the history
Fix for event when massive dumps, triggered by dead lock diagnostic, are produced. Before this fix the concurrency layers should continue to update structures (Maps, Sets) passed to dead lock diagnostic and these structures could be updated in time period between detected dead lock event and print to some log output.
After this fix snapshots are produced.

Signed-off-by: Radek Felcman <[email protected]>
  • Loading branch information
rfelcman authored Jan 15, 2025
1 parent 3b66e99 commit 4c55b68
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -437,6 +435,13 @@ protected static Map<Thread, DeferredLockManager> getDeferredLockManagers() {
return DEFERRED_LOCK_MANAGERS;
}

/**
* Return snapshot of the deferred lock manager hashtable (thread - DeferredLockManager).
*/
protected static Map<Thread, DeferredLockManager> getDeferredLockManagersSnapshot() {
return Map.copyOf(DEFERRED_LOCK_MANAGERS);
}

/**
* Init the deferred lock managers (thread - DeferredLockManager).
*/
Expand Down Expand Up @@ -870,6 +875,13 @@ protected static Map<Thread, ReadLockManager> getReadLockManagers() {
return READ_LOCK_MANAGERS;
}

/**
* Return snapshot of the deferred lock manager hashtable (thread - DeferredLockManager).
*/
protected static Map<Thread, ReadLockManager> getReadLockManagersSnapshot() {
return Map.copyOf(READ_LOCK_MANAGERS);
}

/**
* Print the nested depth.
*/
Expand Down Expand Up @@ -971,33 +983,33 @@ public long getTotalNumberOfKeysReleasedForReadingBlewUpExceptionDueToCacheKeyHa
}

/** Getter for {@link #THREADS_TO_WAIT_ON_ACQUIRE} */
public static Map<Thread, ConcurrencyManager> getThreadsToWaitOnAcquire() {
return new HashMap<>(THREADS_TO_WAIT_ON_ACQUIRE);
public static Map<Thread, ConcurrencyManager> getThreadsToWaitOnAcquireSnapshot() {
return Map.copyOf(THREADS_TO_WAIT_ON_ACQUIRE);
}

/** Getter for {@link #THREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE} */
public static Map<Thread, String> getThreadsToWaitOnAcquireMethodName() {
return new HashMap<>(THREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE);
public static Map<Thread, String> getThreadsToWaitOnAcquireMethodNameSnapshot() {
return Map.copyOf(THREADS_TO_WAIT_ON_ACQUIRE_NAME_OF_METHOD_CREATING_TRACE);
}

/** Getter for {@link #THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK} */
public static Map<Thread, ConcurrencyManager> getThreadsToWaitOnAcquireReadLock() {
return THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK;
public static Map<Thread, ConcurrencyManager> getThreadsToWaitOnAcquireReadLockSnapshot() {
return Map.copyOf(THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK);
}

/** Getter for {@link #THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE} */
public static Map<Thread, String> getThreadsToWaitOnAcquireReadLockMethodName() {
return THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE;
public static Map<Thread, String> getThreadsToWaitOnAcquireReadLockMethodNameSnapshot() {
return Map.copyOf(THREADS_TO_WAIT_ON_ACQUIRE_READ_LOCK_NAME_OF_METHOD_CREATING_TRACE);
}

/** Getter for {@link #THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS} */
public static Set<Thread> getThreadsWaitingToReleaseDeferredLocks() {
return new HashSet<>(THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS);
public static Set<Thread> getThreadsWaitingToReleaseDeferredLocksSnapshot() {
return Set.copyOf(THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS);
}

/** Getter for {@link #THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE} */
public static Map<Thread, String> getThreadsWaitingToReleaseDeferredLocksJustification() {
return new HashMap<>(THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE);
public static Map<Thread, String> getThreadsWaitingToReleaseDeferredLocksJustificationSnapshot() {
return Map.copyOf(THREADS_WAITING_TO_RELEASE_DEFERRED_LOCKS_BUILD_OBJECT_COMPLETE_GOES_NOWHERE);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -469,16 +469,16 @@ public void dumpConcurrencyManagerInformationIfAppropriate() {
}

// do the "MassiveDump" logging if enough time has passed since the previous massive dump logging
Map<Thread, DeferredLockManager> deferredLockManagers = ConcurrencyManager.getDeferredLockManagers();
Map<Thread, ReadLockManager> readLockManagersOriginal = ConcurrencyManager.getReadLockManagers();
Map<Thread, ConcurrencyManager> mapThreadToWaitOnAcquireOriginal = ConcurrencyManager.getThreadsToWaitOnAcquire();
Map<Thread, String> mapThreadToWaitOnAcquireMethodNameOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireMethodName();
Map<Thread, ConcurrencyManager> mapThreadToWaitOnAcquireReadLockOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireReadLock();
Map<Thread, String> mapThreadToWaitOnAcquireReadLockMethodNameOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireReadLockMethodName();
Map<Thread, Set<ConcurrencyManager>> mapThreadToWaitOnAcquireInsideWriteLockManagerOriginal = WriteLockManager.getThreadToFailToAcquireCacheKeys();
Set<Thread> setThreadWaitingToReleaseDeferredLocksOriginal = ConcurrencyManager.getThreadsWaitingToReleaseDeferredLocks();
Map<Thread, String> mapThreadsThatAreCurrentlyWaitingToReleaseDeferredLocksJustificationClone = ConcurrencyManager.getThreadsWaitingToReleaseDeferredLocksJustification();
Map<Thread, Set<Object>> mapThreadToObjectIdWithWriteLockManagerChangesOriginal = WriteLockManager.getMapWriteLockManagerThreadToObjectIdsWithChangeSet();
Map<Thread, DeferredLockManager> deferredLockManagers = ConcurrencyManager.getDeferredLockManagersSnapshot();
Map<Thread, ReadLockManager> readLockManagersOriginal = ConcurrencyManager.getReadLockManagersSnapshot();
Map<Thread, ConcurrencyManager> mapThreadToWaitOnAcquireOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireSnapshot();
Map<Thread, String> mapThreadToWaitOnAcquireMethodNameOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireMethodNameSnapshot();
Map<Thread, ConcurrencyManager> mapThreadToWaitOnAcquireReadLockOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireReadLockSnapshot();
Map<Thread, String> mapThreadToWaitOnAcquireReadLockMethodNameOriginal = ConcurrencyManager.getThreadsToWaitOnAcquireReadLockMethodNameSnapshot();
Map<Thread, Set<ConcurrencyManager>> mapThreadToWaitOnAcquireInsideWriteLockManagerOriginal = WriteLockManager.getThreadToFailToAcquireCacheKeysSnapshot();
Set<Thread> setThreadWaitingToReleaseDeferredLocksOriginal = ConcurrencyManager.getThreadsWaitingToReleaseDeferredLocksSnapshot();
Map<Thread, String> mapThreadsThatAreCurrentlyWaitingToReleaseDeferredLocksJustificationClone = ConcurrencyManager.getThreadsWaitingToReleaseDeferredLocksJustificationSnapshot();
Map<Thread, Set<Object>> mapThreadToObjectIdWithWriteLockManagerChangesOriginal = WriteLockManager.getMapWriteLockManagerThreadToObjectIdsWithChangeSetSnapshot();
dumpConcurrencyManagerInformationStep01(
deferredLockManagers,
readLockManagersOriginal,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static java.util.Collections.unmodifiableMap;

/**
* INTERNAL:
* <p>
Expand Down Expand Up @@ -654,13 +652,13 @@ protected CacheKey waitOnObjectLock(ClassDescriptor descriptor, Object primaryKe
// Helper data structures to have tracebility about object ids with change sets and cache keys we are sturggling to acquire

/** Getter for {@link #THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS} */
public static Map<Thread, Set<ConcurrencyManager>> getThreadToFailToAcquireCacheKeys() {
return unmodifiableMap(THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS);
public static Map<Thread, Set<ConcurrencyManager>> getThreadToFailToAcquireCacheKeysSnapshot() {
return Map.copyOf(THREAD_TO_FAIL_TO_ACQUIRE_CACHE_KEYS);
}

/** Getter for {@link #MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET} */
public static Map<Thread, Set<Object>> getMapWriteLockManagerThreadToObjectIdsWithChangeSet() {
return unmodifiableMap(MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET);
public static Map<Thread, Set<Object>> getMapWriteLockManagerThreadToObjectIdsWithChangeSetSnapshot() {
return Map.copyOf(MAP_WRITE_LOCK_MANAGER_THREAD_TO_OBJECT_IDS_WITH_CHANGE_SET);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2024 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
Expand Down Expand Up @@ -62,7 +62,7 @@ public class CacheKeyToThreadRelationships {

/**
* These are threads that have registered themselves as waiting for the cache key. See
* {@link org.eclipse.persistence.internal.helper.ConcurrencyManager#getThreadsToWaitOnAcquire()}
* {@link org.eclipse.persistence.internal.helper.ConcurrencyManager#getThreadsToWaitOnAcquireSnapshot()}
*
* (acquire lock for writing or as deferred - the cache key must be found with number of readers 0).
*/
Expand Down

0 comments on commit 4c55b68

Please sign in to comment.