RFR: 8327137: Add test for ConcurrentModificationException in BasicDirectoryModel

Alexey Ivanov aivanov at openjdk.org
Mon Mar 4 15:58:05 UTC 2024


I'm adding a regression test for [JDK-8323670](https://bugs.openjdk.org/browse/JDK-8323670) and [JDK-8307091](https://bugs.openjdk.org/browse/JDK-8307091); it's also a regression test for [JDK-8240690](https://bugs.openjdk.org/browse/JDK-8240690).

I referenced this test in PR #17462 in [this comment](https://github.com/openjdk/jdk/pull/17462#issuecomment-1914844026). I fine-tuned the test since that time.

The test doesn't fail all the time without the fix for JDK-8323670, however, it fails sometimes. If you run the test several times, it will likely fail _without the fix_.

For me, the test fails about 10 times from 40 runs in the CI. It fails on macOS more frequently than on Linux.

When the test passes, it usually completes in 5 minutes.

**How the test works**

The test creates a temporary directory in the current directory and creates a number of files in it. (The number of files is controlled by `NUMBER_OF_THREADS` constant). Then the test creates `JFileChooser` in the temporary directory.

The test starts several _scanner_ threads, the number is controlled by `NUMBER_OF_THREADS`, which repeatedly call `fileChooser.rescanCurrentDirectory()`. This results in calling `BasicDirectoryModel.validateFileCache` which starts a background thread — "Basic L&F File Loading Thread" — to enumerate the files.

A timer is used to create new files in the directory that the file chooser is using.

After enumerating the files, the File Loading Thread posts an event to EDT. The event updates `fileCache` and fires a `ListDataEvent`.

If the File Loading Thread is iterating over `fileCache` using `Iterator` (when `fileCache.subList` or `fileCache.equals` is running; or a new `Vector` instance is created from a `fileCache` or its sublist) and `fileCache` is being updated on EDT, then `ConcurrentModificationException` is thrown.

On Linux and on _headless_ macOS, `ShellFolder.invoke` is executed in the caller, which makes it easier to reproduce the issue. Because of [JDK-8325179](https://bugs.openjdk.org/browse/JDK-8325179), there are several File Loading Threads, which also helps to reproduce the issue.

On _headful_ macOS, the `BasicDirectoryModel` is not used, so the test does not reproduce the issue.

On Windows, the test does not fail or fails with `OutOfMemoryError`. It is because all the File Loading Threads are serialised on the COM thread, `ShellFolder.invoke` submits the task to the COM thread and waits for it to complete. The chance of updating `fileCache` while another thread is iterating over it is significantly reduced.

Even more, `filechooser.isTraversable(file)` is also executed on the COM thread, which means there's a heavy contention for the COM thread from each File Loading Thread.

-------------

Commit messages:
 - Explicitly run the test in headless mode
 - Rename the class
 - Move the test under jx.s.plaf.basic/BasicDirectoryModel
 - Add comment for fields, explain usage of ThreadGroup
 - Reduce the parameters: files: 50; file limit: 10; timer: 250
 - Merge master
 - The test is for Linux and macOS only
 - Set 'Test Runner' name to the (main) runner
 - Back to initial parameters: 1,000 files, 5 threads, 2,000 repeats
 - Amend the summary of the test
 - ... and 16 more: https://git.openjdk.org/jdk/compare/8f6edd8d...0d6be7a4

Changes: https://git.openjdk.org/jdk/pull/18109/files
 Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=18109&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8327137
  Stats: 237 lines in 1 file changed: 237 ins; 0 del; 0 mod
  Patch: https://git.openjdk.org/jdk/pull/18109.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/18109/head:pull/18109

PR: https://git.openjdk.org/jdk/pull/18109


More information about the client-libs-dev mailing list