infra-cluster: consul/helm/doris CWE-407 scan; buildkit/containerd/traefik/grafana/victoria-metrics/nifi/samza CLEAN
consul-0001: makeMeshGatewayPeerFilterChain peerNames O(S×B×P) slice scan → map[string]struct{}
helm-0001: ResourceList.Difference/Intersect O(N²) via Contains → pre-built map index
doris-0001: EquivalenceClass.getEquivalenceSetList ArrayList visited O(V²) → IdentityHashMap
doris-0002: PlanNode.addConjunct ArrayList.contains O(C²) → LinkedHashSet
6 CLEAN: buildkit, containerd, traefik, grafana, victoria-metrics, nifi (except pre-existing 0001), samza
This commit is contained in:
parent
cfed6f1c5b
commit
5b5355cb07
11 changed files with 479 additions and 50 deletions
|
|
@ -0,0 +1,94 @@
|
|||
# UNDF: UNDF-2026-000000090
|
||||
# UNDF: (pending)
|
||||
# consul-0001: makeMeshGatewayPeerFilterChain — peerNames O(S×B×P) slice lookup
|
||||
|
||||
## CWE-407 — Algorithmic Complexity
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| ID | consul-0001 |
|
||||
| Severity | MEDIUM |
|
||||
| Ecosystem | consul |
|
||||
| Package | agent/xds |
|
||||
| File | `agent/xds/listeners.go` |
|
||||
| Lines | 2282–2286 |
|
||||
| Complexity | O(S×B×P) — services × bundles × peers per service |
|
||||
| Hot path | Mesh gateway listener rebuild on every topology change |
|
||||
|
||||
## Defect
|
||||
|
||||
`makeMeshGatewayPeerFilterChain` receives `peerNames []string` (the set of peer names
|
||||
for this exported service) and iterates over all peering trust bundles, calling
|
||||
`stringslice.Contains(peerNames, bundle.PeerName)` for each bundle:
|
||||
|
||||
```go
|
||||
// agent/xds/listeners.go
|
||||
for _, bundle := range cfgSnap.MeshGateway.PeeringTrustBundles { // O(B)
|
||||
if stringslice.Contains(peerNames, bundle.PeerName) { // O(P) scan
|
||||
peerBundles = append(peerBundles, bundle)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`stringslice.Contains` is a linear scan:
|
||||
|
||||
```go
|
||||
// lib/stringslice/stringslice.go
|
||||
func Contains(l []string, s string) bool {
|
||||
for _, v := range l {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
The outer caller iterates over all exported services:
|
||||
|
||||
```go
|
||||
for _, svc := range cfgSnap.MeshGatewayValidExportedServices() { // O(S)
|
||||
peerNames := cfgSnap.MeshGateway.ExportedServicesWithPeers[svc]
|
||||
filterChain, err := s.makeMeshGatewayPeerFilterChain(cfgSnap, svc, peerNames, chain)
|
||||
```
|
||||
|
||||
Total: O(S × B × P). In a production Consul cluster with S=50 services, B=20 trust
|
||||
bundles, P=20 peers per service, each listener rebuild costs 50×20×20 = 20,000
|
||||
string comparisons instead of 50×20 = 1,000 map lookups.
|
||||
|
||||
## Fix
|
||||
|
||||
Convert `peerNames` to a `map[string]bool` before the bundle loop:
|
||||
|
||||
```go
|
||||
// Before:
|
||||
var peerBundles []*pbpeering.PeeringTrustBundle
|
||||
for _, bundle := range cfgSnap.MeshGateway.PeeringTrustBundles {
|
||||
if stringslice.Contains(peerNames, bundle.PeerName) {
|
||||
peerBundles = append(peerBundles, bundle)
|
||||
}
|
||||
}
|
||||
|
||||
// After:
|
||||
peerNameSet := make(map[string]struct{}, len(peerNames))
|
||||
for _, p := range peerNames {
|
||||
peerNameSet[p] = struct{}{}
|
||||
}
|
||||
var peerBundles []*pbpeering.PeeringTrustBundle
|
||||
for _, bundle := range cfgSnap.MeshGateway.PeeringTrustBundles {
|
||||
if _, ok := peerNameSet[bundle.PeerName]; ok {
|
||||
peerBundles = append(peerBundles, bundle)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, `ExportedServicesWithPeers` could store `map[string]struct{}` instead of
|
||||
`[]string`, propagating O(1) lookup to all callers.
|
||||
|
||||
## Speedup
|
||||
|
||||
| S (services) | B (bundles) | P (peers) | Before (ops) | After (ops) | Speedup |
|
||||
|---|---|---|---|---|---|
|
||||
| 10 | 10 | 10 | 1,000 | 200 | 5× |
|
||||
| 50 | 20 | 20 | 20,000 | 2,000 | 10× |
|
||||
| 100 | 50 | 50 | 250,000 | 10,000 | 25× |
|
||||
Loading…
Add table
Add a link
Reference in a new issue