Repository navigation
Prune FileLockNamedLock thread entries and align the composite unlock error - #2300
slachiewicz wants to merge 1 commit into
Conversation
… error threadSteps kept every thread that ever used the lock; CompositeNamedLock threw NoSuchElementException instead of the IllegalStateException the other locks throw.
gnodet-bot
left a comment
There was a problem hiding this comment.
Both fixes are correct. The thread-entry leak in FileLockNamedLock is a real memory/GC-root bug (threads held as map keys prevent GC after termination) fixed properly under criticalRegion. CompositeNamedLock.doUnlock() now aligns its exception semantics with the rest of the codebase. The new test correctly validates the composite fix — before this PR, steps.pop() on an empty ArrayDeque would throw NoSuchElementException, not IllegalStateException, causing assertThrows(IllegalStateException.class, ...) to fail.
Root cause: computeIfAbsent(Thread.currentThread(), ...) in doLockSharedPerform/doLockExclusivelyPerform creates map entries that are never cleaned up when lock acquisition times out. forgetThreadWithoutSteps() correctly addresses the timeout path; the doUnlock() restructuring (remove before anyOtherThreadHasSteps()) addresses the unlock path with a minor efficiency improvement.
This review was generated by an AI agent, Hermès on behalf of @gnodet.
FileLockNamedLock.threadStepskept an entry for every thread that ever used the lock, including threads whose attempt timed out, so it retainedThreadobjects for the lock's lifetime. Entries are now removed when a thread's step stack empties or its attempt fails.CompositeNamedLock.doUnlock()threwNoSuchElementExceptionfor an unlock without a lock; it now throws the sameIllegalStateException("Wrong API usage: unlock without lock")as the other locks, covered byunlockWoLockCompositefor the three named-locks factories.