package unit; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; /** * hadoop-0003: StoragePolicySatisfier.findTargetNode() — ArrayList.contains() O(E) * called inside nested loops over storage types and candidate nodes. * Total complexity: O(T * N * E) where T=storageTypes, N=nodesPerType, E=excludedNodes. * * Standalone unit test — no JUnit required. * Compile: javac -d . HadoopStoragePolicySatisfierTest.java * Run: java -ea unit.HadoopStoragePolicySatisfierTest */ public class HadoopStoragePolicySatisfierTest { static long slowOps; static long fastOps; /** * Simulates findTargetNode() with ArrayList excludeNodes — O(E) per candidate. * Returns count of valid targets found (to verify correctness). */ static int slowFindTargets(int numStorageTypes, int nodesPerType, List excludeNodes) { slowOps = 0; int validTargets = 0; for (int t = 0; t < numStorageTypes; t++) { // outer: storage types O(T) for (int n = 0; n < nodesPerType; n++) { // inner: candidate nodes O(N) slowOps++; int nodeId = t * nodesPerType + n; for (Integer ex : excludeNodes) { // ArrayList.contains() scan O(E) slowOps++; if (ex.equals(nodeId)) break; } if (!excludeNodes.contains(nodeId)) { validTargets++; } } } return validTargets; } /** * Patched: HashSet excludeNodes — O(1) contains(). */ static int fastFindTargets(int numStorageTypes, int nodesPerType, Collection excludeNodes) { fastOps = 0; int validTargets = 0; for (int t = 0; t < numStorageTypes; t++) { for (int n = 0; n < nodesPerType; n++) { fastOps++; int nodeId = t * nodesPerType + n; fastOps++; // O(1) HashSet.contains() if (!excludeNodes.contains(nodeId)) { validTargets++; } } } return validTargets; } static void run(int T, int N, int E, int expectedRatio) { // Exclude nodes: first E node IDs List slowExclude = new ArrayList<>(); HashSet fastExclude = new HashSet<>(); for (int i = 0; i < E; i++) { slowExclude.add(i); fastExclude.add(i); } int slowResult = slowFindTargets(T, N, slowExclude); int fastResult = fastFindTargets(T, N, fastExclude); boolean resultsMatch = (slowResult == fastResult); boolean quadraticWorse = slowOps > fastOps * expectedRatio; boolean pass = resultsMatch && quadraticWorse; System.out.printf("T=%-3d N=%-4d E=%-4d slow=%8d fast=%6d ratio=%6.1fx match=%b PASS=%b%n", T, N, E, slowOps, fastOps, (double) slowOps / fastOps, resultsMatch, pass); if (!pass) { throw new AssertionError( "FAIL T=" + T + " N=" + N + " E=" + E + " resultsMatch=" + resultsMatch + " slowOps=" + slowOps + " fastOps=" + fastOps + " needed ratio>" + expectedRatio); } } public static void main(String[] args) { System.out.println("=== hadoop-0003: StoragePolicySatisfier.findTargetNode() O(T*N*E) vs O(T*N) ==="); run(3, 100, 20, 5); run(5, 200, 50, 15); run(5, 300, 100, 25); System.out.println("3/3 PASS"); } }