gnodet opened a new pull request, #328:
URL: https://github.com/apache/maven-clean-plugin/pull/328

   ## Summary
   
   Refactors the fast clean (`-Dmaven.clean.fast=true`) `BackgroundCleaner` to 
fix the MCLEAN-102 performance regression and three regressions introduced by 
the per-module refactoring in PR #286.
   
   ### What this fixes
   
   | # | Bug | Root Cause | Fix |
   |---|------|------------|-----|
   | 1 | **MCLEAN-102** — fast mode 50% slower on 12-core Windows | 
`System.gc()` stop-the-world per file + per-file retry sleeps from background 
thread | Batch retry: walk once without retry, sleep once (250ms), retry all 
failures |
   | 2 | **Thread proliferation** — 500 threads in 500-module reactor | 
Per-module `BackgroundCleaner`, each with its own `ExecutorService` | 
Session-scoped instance via `SessionData.computeIfAbsent()` |
   | 3 | **500 session listeners** | Per-module 
`session.registerListener(this)` | Single listener registered in constructor |
   | 4 | **Leftover cleanup lost** | `init()` scan removed in PR #286 when 
singleton was dropped | Restored: `scanForLeftovers()` queues leftover dirs for 
background deletion |
   
   ### Changes
   
   - **`BackgroundCleaner.java`** (major rewrite):
     - `SessionData.Key<BackgroundCleaner>` + `getOrCreate()` factory — one 
instance, one thread, one listener per session
     - `deleteInBackground()` replaces `deleteSilently()` — uses 
`SimpleFileVisitor` with batch retry instead of creating a `Cleaner` copy that 
uses per-file retry with `System.gc()`
     - `scanForLeftovers()` — scans fast directory for dirs left by killed 
previous builds
     - `fastDelete()` is `synchronized` for parallel build safety (`-T`)
   
   - **`Cleaner.java`** (one-line change):
     - `setWritable()`: `private static` → `static` (package-private) so 
`BackgroundCleaner` can reuse it for force-delete in background
   
   - **`CleanMojo.java`** (one-line change):
     - `new BackgroundCleaner(...)` → `BackgroundCleaner.getOrCreate(...)`
   
   ### Before vs After (500-module reactor)
   
   | Metric | Before | After |
   |--------|--------|-------|
   | Background threads | **500** | **1** |
   | Session listeners | **500** | **1** |
   | `System.gc()` calls (Windows) | thousands | **0** |
   | Per-file sleeps (background) | 50–1050ms × N | **0** |
   | Batch sleeps | 0 | **1 × 250ms per directory** |
   | Leftover cleanup | ❌ | ✅ |
   
   ### Design notes
   
   - **Foreground path unchanged**: the traditional `Cleaner.tryDelete()` keeps 
`System.gc()` + per-file retry — it runs in the main thread where it can't 
cause stop-the-world on other threads, and it may genuinely need to release 
JVM-held file handles.
   - **Batch retry respects `retryOnError`**: if user sets 
`-Dmaven.clean.retryOnError=false`, no retry happens even in background.
   - **Remaining failures deferred to next build**: any files that survive the 
batch retry will be cleaned up by the leftover scan on the next `fast=true` 
build.
   
   ## Test plan
   
   - [x] `mvn verify` passes (15 tests, 0 failures)
   - [ ] Manual test on Windows with large reactor to verify MCLEAN-102 fix
   - [ ] Manual test: kill build mid-clean, verify leftovers cleaned on next run
   - [ ] Manual test with `-T 4C` parallel build to verify session-scoped 
sharing
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to