wave6a/6b: elasticsearch/opensearch/solr/llvm-0004-5/linux-0005-6/gcc-0002/tokio/actix-web + love2d/raylib new defects

This commit is contained in:
russell@unturf.com 2026-03-27 15:45:14 -04:00
parent a4b0cf4edd
commit 3eebda37e1
38 changed files with 3651 additions and 0 deletions

View file

@ -0,0 +1,73 @@
# 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+).

View file

@ -0,0 +1,60 @@
# solr-002: ActiveReplicaWatcher O(n²) replicaIds/solrCoreNames.contains in state-change loop
## Classification
- **CWE**: CWE-407 (Inefficient Algorithmic Complexity)
- **Severity**: MEDIUM
- **Path**: ZooKeeper state-change callback — fires on every cluster state update
## Location
`solr/core/src/java/org/apache/solr/cloud/ActiveReplicaWatcher.java:161,169`
## Defect
```java
private final List<String> replicaIds = new ArrayList<>();
private final List<String> solrCoreNames = new ArrayList<>();
// Called on every ZK state change:
for (Slice slice : collectionState.getSlices()) { // O(shards)
for (Replica replica : slice.getReplicas()) { // O(replicas/shard)
if (replicaIds.contains(replica.getName())) { // O(replicaIds) = O(n)
...
} else if (solrCoreNames.contains( // O(solrCoreNames) = O(n)
replica.getStr(ZkStateReader.CORE_NAME_PROP))) {
...
}
}
}
```
Both `replicaIds` and `solrCoreNames` are `ArrayList`. The watcher fires on every
ZooKeeper cluster-state change event (node joins, replica state transitions, shard
splits, etc.). For a collection with S shards × R replicas and N watched IDs:
Total comparisons per event: **O(S × R × N)** for each list independently.
## Fix
Convert to `HashSet` at construction time (the lists are populated once and then only
shrink via `remove()`):
```java
private final Set<String> replicaIds = new HashSet<>();
private final Set<String> solrCoreNames = new HashSet<>();
```
`HashSet.remove()` is also O(1), so the existing removal calls in the loop body
(`replicaIds.remove(replica.getName())`) remain correct and become faster.
The public getters at lines 93/98 return the field directly as `List`; the return type
would need to change to `Collection` or the getter can wrap with `new ArrayList<>(replicaIds)`.
## Complexity
| Metric | Before | After |
|--------|--------|-------|
| contains() | O(N) | O(1) |
| Per ZK event | O(S×R×N) | O(S×R) |
| remove() | O(N) | O(1) |
## Affected Versions
Present in all Solr versions with `ActiveReplicaWatcher` (Solr 7+).