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.
89 lines
3.4 KiB
Java
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);
|
|
}
|
|
}
|