java-topology/defects/camel/patch/camel-0001-route-startup-quadratic-endpoint-scan.md

2.9 KiB
Raw Blame History

UNDF: UNDF-2026-000000158

camel-0001 — O(R²) Route Startup Endpoint Clash Scan

Severity: HIGH Complexity: O(R²) → O(R) CWE: CWE-407 (Algorithmic Complexity)

Affected File

File Lines Notes
core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/InternalRouteStartupManager.java 357444 Route startup consumer clash check

Defective Code

InternalRouteStartupManager.doStartOrResumeRouteConsumers lines 357444

List<Endpoint> routeInputs = new ArrayList<>();

for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
    // ...
    Endpoint endpoint = consumer.getEndpoint();

    // CHECK 1: O(R) linear scan inside O(R) outer loop → O(R²)
    if (!doCheckMultipleConsumerSupportClash(endpoint, routeInputs)) {
        throw new FailedToStartRouteException(...);
    }

    // CHECK 2: rebuild existingEndpoints as ArrayList each iteration → O(R²)
    List<Endpoint> existingEndpoints = new ArrayList<>();
    for (Route existingRoute : camelContext.getRoutes()) {
        // ... add to existingEndpoints
    }
    if (!doCheckMultipleConsumerSupportClash(endpoint, existingEndpoints)) {
        throw new FailedToStartRouteException(...);
    }

    routeInputs.add(endpoint);   // List grows by 1 each iteration
}

doCheckMultipleConsumerSupportClash calls routeInputs.contains(endpoint) and existingEndpoints.contains(endpoint). Both lists use ArrayList.contains() which is O(N). The outer loop runs R times (R = number of routes). Total: O(R²).

Root Cause

routeInputs is declared as ArrayList<Endpoint>. The .contains() call scans every existing element linearly. At R=1000 routes, this is ~500,000 comparisons instead of ~1,000.

Fix

Replace ArrayList<Endpoint> with LinkedHashSet<Endpoint> (preserves insertion order, provides O(1) contains()):

// Before
List<Endpoint> routeInputs = new ArrayList<>();

// After
Set<Endpoint> routeInputs = new LinkedHashSet<>();

doCheckMultipleConsumerSupportClash accepts a Collection<Endpoint> parameter (declared as List<Endpoint>), so the call site parameter type must also be updated:

// Before
private boolean doCheckMultipleConsumerSupportClash(Endpoint endpoint, List<Endpoint> routeInputs)

// After
private boolean doCheckMultipleConsumerSupportClash(Endpoint endpoint, Collection<Endpoint> routeInputs)

For existingEndpoints, use LinkedHashSet as well:

// Before
List<Endpoint> existingEndpoints = new ArrayList<>();

// After
Set<Endpoint> existingEndpoints = new LinkedHashSet<>();

Impact

  • Affects Camel applications with R ≥ 50 routes at startup
  • Startup time grows quadratically with route count
  • At R=500: ~12,500 comparisons → ~500 (25x reduction)
  • At R=1000: ~500,000 comparisons → ~1,000 (500x reduction)
  • Cloud deployments with large route counts (e.g., microservice monorepos using Camel) are most affected