java-topology/defects/synapse/test/SynapseSyncNewlyJoinedRoomsTest.java
russell@unturf.com 15db2a0269 synapse-0001: sync handler newly_joined_rooms List membership O(J*N); matrix-js-sdk CLEAN
synapse/handlers/sync.py _get_rooms_changed: newly_joined_rooms is List[str]
checked with `in` inside for-loop over all joined rooms (line 2252).
O(J*N) where J=joined rooms, N=newly joined. Fix: use Set. 99x at J=5000.
2026-03-30 15:23:53 -04:00

89 lines
3.4 KiB
Java

import java.util.*;
/**
* Unit test for synapse-0001: sync handler newly_joined_rooms List membership O(J*N)
*
* Simulates the _get_rooms_changed loop in synapse/handlers/sync.py
* where `room_id in newly_joined_rooms` is checked for every joined room.
*
* Defect: newly_joined_rooms is a List, so `in` is O(N) per check = O(J*N) total.
* Fix: Use a Set, so `in` is O(1) per check = O(J) total.
*/
public class SynapseSyncNewlyJoinedRoomsTest {
/** Simulate defective code: List-based membership test */
static int simulateDefective(List<String> joinedRoomIds, List<String> newlyJoinedRooms) {
int ops = 0;
for (String roomId : joinedRoomIds) {
// Simulates: newly_joined = room_id in newly_joined_rooms (line 2252)
boolean found = false;
for (String njr : newlyJoinedRooms) {
ops++;
if (njr.equals(roomId)) {
found = true;
break;
}
}
// In real code, `found` determines whether to do full-state sync for this room
}
return ops;
}
/** Simulate fixed code: Set-based membership test */
static int simulateFixed(List<String> joinedRoomIds, Set<String> newlyJoinedRooms) {
int ops = 0;
for (String roomId : joinedRoomIds) {
ops++;
boolean found = newlyJoinedRooms.contains(roomId);
}
return ops;
}
public static void main(String[] args) {
// Parameters: J = number of joined rooms, N = number of newly joined rooms
int[] sizes = {100, 500, 1000, 5000};
int N_NEWLY = 100; // newly joined rooms in a sync window
System.out.println("synapse-0001: sync handler newly_joined_rooms List membership O(J*N)");
System.out.println("=".repeat(75));
System.out.printf("%-12s %-12s %-12s %-12s %-10s%n",
"J(joined)", "N(newly)", "Defective", "Fixed", "Ratio");
System.out.println("-".repeat(75));
boolean allPass = true;
for (int J : sizes) {
// Build joined room IDs
List<String> joinedRoomIds = new ArrayList<>(J);
for (int i = 0; i < J; i++) {
joinedRoomIds.add("!room" + i + ":example.com");
}
// Build newly joined rooms (subset of joined)
List<String> newlyJoinedList = new ArrayList<>(N_NEWLY);
Set<String> newlyJoinedSet = new HashSet<>(N_NEWLY);
for (int i = 0; i < N_NEWLY; i++) {
String roomId = "!room" + (J - N_NEWLY + i) + ":example.com";
newlyJoinedList.add(roomId);
newlyJoinedSet.add(roomId);
}
int defectiveOps = simulateDefective(joinedRoomIds, newlyJoinedList);
int fixedOps = simulateFixed(joinedRoomIds, newlyJoinedSet);
double ratio = (double) defectiveOps / fixedOps;
System.out.printf("%-12d %-12d %-12d %-12d %-10.1fx%n",
J, N_NEWLY, defectiveOps, fixedOps, ratio);
// At J=5000, N=100: defective should be ~50x worse
if (J >= 1000 && ratio < 5.0) {
System.out.println(" FAIL: expected ratio >= 5.0 at J=" + J);
allPass = false;
}
}
System.out.println("-".repeat(75));
System.out.println(allPass ? "PASS" : "FAIL");
System.exit(allPass ? 0 : 1);
}
}