From ee8eb2db95619b1003a9449a35c9c03fbf406de3 Mon Sep 17 00:00:00 2001 From: kasemir Date: Thu, 28 Aug 2025 15:23:11 -0400 Subject: [PATCH 1/2] PVA client: Fix ConcurrentModificationException in search `ChannelSearch.runSearches` used to re-use one `to_search` array list. By the time the submitted searches encode the channels from that list, it might get cleared and re-populated. Need to create a new one in each `runSearches` call. At same time removed some unnecessary casts. --- .../java/org/epics/pva/client/ChannelSearch.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java b/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java index 35ee2ba03b..59e1dfc6a5 100644 --- a/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java +++ b/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java @@ -342,9 +342,6 @@ public synchronized void boost() } } - /** List of channels to search, re-used within runSearches */ - private final ArrayList to_search = new ArrayList<>(); - /** Invoked by timer: Check searched channels for the next one to handle */ @SuppressWarnings("unchecked") private void runSearches() @@ -352,7 +349,7 @@ private void runSearches() // Determine current search bucket final int current = current_search_bucket.getAndUpdate(i -> (i + 1) % search_buckets.size()); // Collect channels to be searched while sync'ed - to_search.clear(); + final ArrayList to_search = new ArrayList<>(); synchronized (this) { final Set bucket = search_buckets.get(current); @@ -406,7 +403,7 @@ private void runSearches() int count = 0; while (start + count < to_search.size() && count < Short.MAX_VALUE-1) { - final PVAChannel channel = to_search.get(start + count); + final SearchRequest.Channel channel = to_search.get(start + count); int size = 4 + PVAString.getEncodedSize(channel.getName()); if (payload + size < MAX_SEARCH_PAYLOAD) { @@ -428,9 +425,9 @@ else if (count == 0) if (count == 0) break; - final List batch = to_search.subList(start, start + count); - // PVAChannel extends SearchRequest.Channel, so use List as Collection - search((Collection) (List)batch); + // Submit one batch from 'to_search' + final List batch = to_search.subList(start, start + count); + search(batch); start += count; } } From 4b1dbf73fab1eb1fc084856348b3a45d2856c5c4 Mon Sep 17 00:00:00 2001 From: kasemir Date: Thu, 28 Aug 2025 15:59:18 -0400 Subject: [PATCH 2/2] PVA: "unchecked" cast has been removed --- core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java b/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java index 59e1dfc6a5..7d434e69ce 100644 --- a/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java +++ b/core/pva/src/main/java/org/epics/pva/client/ChannelSearch.java @@ -343,7 +343,6 @@ public synchronized void boost() } /** Invoked by timer: Check searched channels for the next one to handle */ - @SuppressWarnings("unchecked") private void runSearches() { // Determine current search bucket