1.6 KiB
jitsi-videobridge-0003 — ConferenceSpeechActivity.java: ArrayList.contains() in endpointsChanged (O(n²))
Severity: HIGH
File: jvb/src/main/java/org/jitsi/videobridge/ConferenceSpeechActivity.java
Lines: 326, 331
Pattern
// line 326 — removeIf with lambda calling conferenceEndpoints.contains() — O(n) per element
endpointsListChanged = endpointsBySpeechActivity.removeIf(ep -> !conferenceEndpoints.contains(ep));
// line 329-335 — for loop calling endpointsBySpeechActivity.contains() — O(n) per element
for (AbstractEndpoint conferenceEndpoint : conferenceEndpoints) {
if (!endpointsBySpeechActivity.contains(conferenceEndpoint)) // O(n)
endpointsBySpeechActivity.add(conferenceEndpoint);
}
endpointsBySpeechActivity is ArrayList<AbstractEndpoint>.
conferenceEndpoints is List<AbstractEndpoint> (also ArrayList).
Both .contains() calls are O(n) — total is O(n²).
Complexity
O(|endpointsBySpeechActivity| × |conferenceEndpoints|). Called on every endpoint join/leave event. In large conferences (100+ participants) this fires frequently.
Fix
Pre-build Set<AbstractEndpoint> conferenceSet = new HashSet<>(conferenceEndpoints) before the loops.
Use conferenceSet.contains(ep) at line 326 and !conferenceSet.contains(...) at line 331.
A LinkedHashSet for endpointsBySpeechActivity would make line 331 O(1) always,
but the ordered-by-speech-activity requirement means the list must stay ordered by recency —
use a LinkedHashSet<AbstractEndpoint> for the membership check only.
Speedup (estimated)
~80× at N=100 endpoints. O(n²) → O(n).