fix: let an interrupt stop the parse, release striff-lib 4.3.3 - #72
Merged
Merged
Conversation
StriffOperation parsed the base and head revisions with CompletableFuture.supplyAsync on the common pool and waited with join(). join() ignores interrupts, and the threads doing the parsing were never the one a caller interrupts, so Clarpse's cooperative cancellation checks, which watch the thread they run on, never fired. A caller enforcing a time budget with Thread.interrupt() could not stop a parse: it ran to completion and the interrupt was only noticed afterwards, at the merge checkpoint. The two parses now run on a small pool owned by ParallelParse. The caller waits interruptibly; an interrupt cancels both parses, which interrupts their threads, and the call returns only once both have stopped, throwing CancellationException with the interrupt flag re-asserted. Results are taken in completion order, so one failed parse ends the wait and stops the other instead of leaving it running in the background. A CompileException from a parse now reaches the caller as itself rather than wrapped in a RuntimeException. Version 4.3.2 -> 4.3.3. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACYxqmHapz2iiCJn16tVhj
ExecutorService became AutoCloseable in Java 19, so PMD's CloseResource flags the pool when the build runs on a newer JDK. try-with-resources is not available at the Java 17 baseline; the pool is shut down and awaited by stop() in the finally, so the rule is suppressed on that method with the reason noted where the pool is created. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACYxqmHapz2iiCJn16tVhj
A thread pool reports termination from inside its last worker, so that thread can still be alive for an instant after the call returns, while it unwinds and after its parse has ended. Counting live threads at that instant raced it. The thread checks now give each thread a bounded time to finish exiting; that no parse is still running when the call returns stays pinned by the latch checks. The javadoc now states the guarantee in terms of the parses having ended rather than the threads having stopped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ACYxqmHapz2iiCJn16tVhj
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #73.
Releases striff-lib 4.3.3.
Problem
StriffOperationparsed the base and head revisions withCompletableFuture.supplyAsyncon the common pool and waited withjoin().join()ignores interrupts, and the threads doing the parsing were never the thread a caller interrupts. Clarpse's cooperative cancellation checks watch the thread they run on, so they never fired: a caller enforcing a time budget withThread.interrupt()could not stop a parse. The parse ran to completion, and the interrupt was only noticed afterwards at theCodeDiffmerge checkpoint.Change
ParallelParseruns the two parses on a two-thread pool it owns. The caller waits interruptibly; an interrupt cancels both parses (interrupting their threads, where Clarpse's checks see it) and the call throwsCancellationExceptionwith the interrupt flag re-asserted, matching the existing checkpoints inCodeDiffandExtractedRelationships.CompileExceptionfrom a parse now reaches the caller as itself. It was previously wrapped in aRuntimeExceptionby the lambda, which defeated the unwrappingjoinCompileResultintended.StriffOperation's full-pipeline constructor documents it.4.3.2 → 4.3.3.Verification
mvn clean package -Bon JDK 17 and JDK 21: 213 tests, 0 failures; Checkstyle and PMD clean. PMD'sCloseResourceis suppressed onParallelParse.run:ExecutorServiceisAutoCloseableonly from Java 19, so try-with-resources is unavailable at the Java 17 baseline, and the pool is shut down and awaited in afinally.ParallelParseTest(4 tests): the interrupt reaches both parse threads and the call returns only after both parses have ended; a failed parse stops the other without waiting for it; ordinary results are returned by revision; an interruptedStriffOperationthrowsCancellationException. Thread-count checks allow a pool thread a bounded moment to finish exiting, since a pool reports termination from inside its last worker; the parses having ended is pinned by latches. 10 repeated runs on JDK 21 passed.ParallelParsetemporarily reverted to the oldsupplyAsync+join()wait, two of the new tests fail for the expected reasons: the interrupt test ("the call must return once its thread is interrupted") and the failed-parse test (times out waiting behind the blocked parse).🤖 Generated with Claude Code
https://claude.ai/code/session_01ACYxqmHapz2iiCJn16tVhj