This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new eb2f10067c39 CAMEL-23681: Fix race condition in DefaultUnitOfWork
route stack
eb2f10067c39 is described below
commit eb2f10067c39eab410282bfec2155fc1d147b295
Author: Guillaume Nodet <[email protected]>
AuthorDate: Fri Jun 5 10:16:48 2026 +0200
CAMEL-23681: Fix race condition in DefaultUnitOfWork route stack
The CAMEL-23686 optimization replaced ConcurrentLinkedDeque with a plain
Route field + lazy ArrayDeque, reintroducing the race condition from
CAMEL-22533 when split().parallelProcessing().shareUnitOfWork() causes
concurrent access. Protect route stack operations (getRoute, pushRoute,
popRoute, routeStackLevel) with the existing ReentrantLock while
preserving the memory optimization.
Closes #23777
---
.../camel/impl/engine/DefaultUnitOfWork.java | 79 +++++++++++++++-------
1 file changed, 54 insertions(+), 25 deletions(-)
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
index bcb35ca1f866..60ce4d4b8c3e 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultUnitOfWork.java
@@ -371,53 +371,82 @@ public class DefaultUnitOfWork implements UnitOfWork {
@Override
public Route getRoute() {
- return route;
+ lock.lock();
+ try {
+ return route;
+ } finally {
+ lock.unlock();
+ }
}
@Override
public void pushRoute(Route route) {
- if (this.route == null) {
- this.route = route;
- } else {
- if (routeStack == null) {
- routeStack = new ArrayDeque<>();
+ lock.lock();
+ try {
+ if (this.route == null) {
+ this.route = route;
+ } else {
+ if (routeStack == null) {
+ routeStack = new ArrayDeque<>();
+ }
+ routeStack.push(this.route);
+ this.route = route;
}
- routeStack.push(this.route);
- this.route = route;
+ } finally {
+ lock.unlock();
}
}
@Override
public Route popRoute() {
- Route old = this.route;
- if (routeStack != null && !routeStack.isEmpty()) {
- this.route = routeStack.pop();
- } else {
- this.route = null;
+ lock.lock();
+ try {
+ Route old = this.route;
+ if (routeStack != null && !routeStack.isEmpty()) {
+ this.route = routeStack.pop();
+ } else {
+ this.route = null;
+ }
+ return old;
+ } finally {
+ lock.unlock();
}
- return old;
}
@Override
public int routeStackLevel() {
+ lock.lock();
+ try {
+ return routeStackSize();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private int routeStackSize() {
return (route != null ? 1 : 0) + (routeStack != null ?
routeStack.size() : 0);
}
public int routeStackLevel(boolean includeRouteTemplate, boolean
includeKamelet) {
- if (includeKamelet && includeRouteTemplate) {
- return routeStackLevel();
- }
+ lock.lock();
+ try {
+ if (includeKamelet && includeRouteTemplate) {
+ return routeStackSize();
+ }
- int level = 0;
- if (route != null) {
- level += countRoute(route, includeRouteTemplate, includeKamelet);
- }
- if (routeStack != null) {
- for (Route r : routeStack) {
- level += countRoute(r, includeRouteTemplate, includeKamelet);
+ int level = 0;
+ if (route != null) {
+ level += countRoute(route, includeRouteTemplate,
includeKamelet);
}
+ if (routeStack != null) {
+ for (Route r : routeStack) {
+ level += countRoute(r, includeRouteTemplate,
includeKamelet);
+ }
+ }
+ return level;
+ } finally {
+ lock.unlock();
}
- return level;
}
private static int countRoute(Route r, boolean includeRouteTemplate,
boolean includeKamelet) {