# UNDF: UNDF-2026-000000533
# solr-001: ClusterStatus O(n²) liveNodes.contains in crossCheckReplicaStateWithLiveNodes

## Classification
- **CWE**: CWE-407 (Inefficient Algorithmic Complexity)
- **Severity**: HIGH
- **Path**: Admin API handler — called on every CLUSTERSTATUS request, which monitoring
  tools typically poll every few seconds

## Location
`solr/core/src/java/org/apache/solr/handler/admin/ClusterStatus.java:303`

## Defect

```java
protected void crossCheckReplicaStateWithLiveNodes(
        List<String> liveNodes, Map<String, Object> collectionProps) {
    var shards = (Map<String, Object>) collectionProps.get("shards");
    for (Object nextShard : shards.values()) {                      // O(shards)
        var replicas = (Map<String, Object>) shardMap.get("replicas");
        for (Object nextReplica : replicas.values()) {              // O(replicas/shard)
            // ...
            String node_name = (String) replicaMap.get(ZkStateReader.NODE_NAME_PROP);
            if (!liveNodes.contains(node_name)) {                   // O(liveNodes)
                replicaMap.put(ZkStateReader.STATE_PROP, Replica.State.DOWN.toString());
            }
        }
    }
}
```

`liveNodes` is fetched via `zkStateReader.getZkClient().getChildren(ZkStateReader.LIVE_NODES_ZKNODE, null)`
which returns a plain `List<String>`. The double-nested shard/replica loop calls
`liveNodes.contains()` for every replica.

For a cluster with:
- N live nodes
- S shards
- R replicas/shard

Total comparisons per CLUSTERSTATUS call: **O(N × S × R)**

A production Solr cluster with 100 nodes, 500 shards, 3 replicas/shard =
150,000 string comparisons per call. With monitoring polling at 5s intervals:
1.8 million string comparisons per minute, completely wasted.

## Fix

Convert `liveNodes` to a `HashSet<String>` before the nested loops:

```java
Set<String> liveNodeSet = new HashSet<>(liveNodes);   // O(N) once
for (Object nextShard : shards.values()) {
    for (Object nextReplica : replicas.values()) {
        if (!liveNodeSet.contains(node_name)) {        // O(1)
            ...
        }
    }
}
```

The caller at line 129 already has `liveNodes` as a List; the fix can be applied
inside `crossCheckReplicaStateWithLiveNodes` without changing any callers.

## Complexity
| Metric | Before | After |
|--------|--------|-------|
| contains() | O(N) | O(1) |
| Full cross-check | O(N×S×R) | O(N + S×R) |
| At N=100, S=500, R=3 | 150,000 comparisons | ~1,600 |
| Speedup | 1× | ~94× |

## Affected Versions
Present in all Solr versions with the ClusterStatus handler (Solr 5+).
