package unit; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Random; import java.util.Set; /** * Unit test for hbase-0002: BaseLoadBalancer.randomAssignment usedSNs ArrayList.contains() O(n²). * * Standalone — no JUnit. Run: javac -d . BaseLoadBalancerAlgorithm.java && java -ea unit.BaseLoadBalancerAlgorithm */ public class BaseLoadBalancerAlgorithm { // Simulates the wouldLowerAvailability predicate — always true to trigger maxIterations static boolean wouldLowerAvailability(int server) { return true; // worst-case: triggers maxIterations path } // ---------- Slow: ArrayList.contains in do-while + fallback for loop ---------- static class SlowResult { final int serverChosen; final long containsOps; SlowResult(int server, long ops) { this.serverChosen = server; this.containsOps = ops; } } static SlowResult slowRandomAssignment(List servers) { int numServers = servers.size(); int sn = -1; final int maxIterations = numServers * 4; int iterations = 0; List usedSNs = new ArrayList<>(numServers); Random rand = new Random(42); long ops = 0; do { int i = rand.nextInt(numServers); sn = servers.get(i); ops += usedSNs.size(); // O(size) per contains if (!usedSNs.contains(sn)) { usedSNs.add(sn); } } while (wouldLowerAvailability(sn) && iterations++ < maxIterations); if (iterations >= maxIterations) { // Fallback: scan all servers for (Integer unusedServer : servers) { ops += usedSNs.size(); // O(size) per contains if (!usedSNs.contains(unusedServer)) { if (!wouldLowerAvailability(unusedServer)) { sn = unusedServer; break; } } } } return new SlowResult(sn, ops); } // ---------- Fast: LinkedHashSet.contains O(1) ---------- static class FastResult { final int serverChosen; final long containsOps; FastResult(int server, long ops) { this.serverChosen = server; this.containsOps = ops; } } static FastResult fastRandomAssignment(List servers) { int numServers = servers.size(); int sn = -1; final int maxIterations = numServers * 4; int iterations = 0; Set usedSNs = new LinkedHashSet<>(numServers); Random rand = new Random(42); long ops = 0; do { int i = rand.nextInt(numServers); sn = servers.get(i); ops += 1; // O(1) per contains usedSNs.add(sn); } while (wouldLowerAvailability(sn) && iterations++ < maxIterations); if (iterations >= maxIterations) { for (Integer unusedServer : servers) { ops += 1; // O(1) if (!usedSNs.contains(unusedServer)) { if (!wouldLowerAvailability(unusedServer)) { sn = unusedServer; break; } } } } return new FastResult(sn, ops); } static void testCorrectness() { int S = 50; List servers = new ArrayList<>(); for (int i = 0; i < S; i++) servers.add(i); SlowResult slow = slowRandomAssignment(servers); FastResult fast = fastRandomAssignment(servers); // Both should end up not finding a server (all trigger wouldLowerAvailability) assert slow.serverChosen == fast.serverChosen : "server mismatch: slow=" + slow.serverChosen + " fast=" + fast.serverChosen; System.out.println("PASS: correctness — same server chosen: " + slow.serverChosen); } static void testPerformance() { int S = 500; // 500 servers — large HBase cluster List servers = new ArrayList<>(); for (int i = 0; i < S; i++) servers.add(i); SlowResult slow = slowRandomAssignment(servers); FastResult fast = fastRandomAssignment(servers); double ratio = (double) slow.containsOps / fast.containsOps; System.out.printf("randomAssignment S=%d: slow_ops=%,d fast_ops=%,d ratio=%.1fx%n", S, slow.containsOps, fast.containsOps, ratio); assert ratio >= 10.0 : "Expected >=10x speedup, got ratio=" + ratio; System.out.println("PASS: performance — ratio >= 10x"); } static void testLargeCluster() { // Simulate 2000-server cluster (very large HBase) int S = 2000; List servers = new ArrayList<>(); for (int i = 0; i < S; i++) servers.add(i); SlowResult slow = slowRandomAssignment(servers); FastResult fast = fastRandomAssignment(servers); double ratio = (double) slow.containsOps / fast.containsOps; System.out.printf("randomAssignment S=%d: slow_ops=%,d fast_ops=%,d ratio=%.1fx%n", S, slow.containsOps, fast.containsOps, ratio); assert ratio >= 50.0 : "Expected >=50x speedup for large cluster, got ratio=" + ratio; System.out.println("PASS: large cluster — ratio >= 50x"); } public static void main(String[] args) { testCorrectness(); testPerformance(); testLargeCluster(); System.out.println("ALL PASS (3/3)"); } }