erpnext-0001: BOM.get_children list dedup O(B^2) MEDIUM 4x erpnext-0002: serial_batch_bundle serial/batch dedup O(N^2) HIGH 45x ofbiz-0001: PaymentGatewayServices processList LinkedList O(N^2) HIGH 45x ofbiz-0002: OrderReturnServices/OrderReadHelper payment dedup O(N^2) MEDIUM 36x odoo: CLEAN (consistent set/frozenset/OrderedSet usage throughout)
94 lines
3.4 KiB
Java
94 lines
3.4 KiB
Java
import java.util.*;
|
|
|
|
/**
|
|
* Unit test for ofbiz-0001: PaymentGatewayServices processList LinkedList.contains O(N^2)
|
|
*
|
|
* Simulates the order dedup pattern in retryFailedAuths / retryFailedAuthNsfs
|
|
* where orderId membership is checked via LinkedList.contains (defect) vs
|
|
* HashSet.contains (fix).
|
|
*
|
|
* Defect: PaymentGatewayServices.java lines 2714-2724, 2755-2765 —
|
|
* "if (!processList.contains(orderId))" where processList is a LinkedList<String>,
|
|
* giving O(N) per check inside a while loop over DB results → O(N^2).
|
|
*
|
|
* Fix: use HashSet<String> for O(1) contains.
|
|
*/
|
|
public class test_ofbiz_0001 {
|
|
|
|
// --- Defect: LinkedList dedup ---
|
|
static int processOrdersDefect(List<String> orderIds) {
|
|
List<String> processList = new LinkedList<>();
|
|
int processed = 0;
|
|
for (String orderId : orderIds) {
|
|
if (!processList.contains(orderId)) { // O(N) per check
|
|
processList.add(orderId);
|
|
processed++;
|
|
}
|
|
}
|
|
return processed;
|
|
}
|
|
|
|
// --- Fix: HashSet dedup ---
|
|
static int processOrdersFixed(List<String> orderIds) {
|
|
Set<String> processList = new HashSet<>();
|
|
int processed = 0;
|
|
for (String orderId : orderIds) {
|
|
if (!processList.contains(orderId)) { // O(1) per check
|
|
processList.add(orderId);
|
|
processed++;
|
|
}
|
|
}
|
|
return processed;
|
|
}
|
|
|
|
static List<String> generateOrderIds(int n, int uniqueOrders) {
|
|
List<String> ids = new ArrayList<>(n);
|
|
for (int i = 0; i < n; i++) {
|
|
ids.add("ORD-" + String.format("%06d", i % uniqueOrders));
|
|
}
|
|
return ids;
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
System.out.println("=== ofbiz-0001: PaymentGatewayServices processList O(N^2) ===\n");
|
|
|
|
// Correctness test
|
|
List<String> input = Arrays.asList("ORD-001", "ORD-002", "ORD-001", "ORD-003");
|
|
assert processOrdersDefect(input) == 3 : "Defect: wrong unique count";
|
|
assert processOrdersFixed(input) == 3 : "Fixed: wrong unique count";
|
|
System.out.println("Correctness: PASS");
|
|
|
|
// Performance test: 10000 payment preferences, 2000 unique orders
|
|
int N = 10000, uniqueOrders = 2000;
|
|
List<String> orderIds = generateOrderIds(N, uniqueOrders);
|
|
System.out.println("Payment preferences: " + N + ", unique orders: " + uniqueOrders);
|
|
|
|
// Warmup
|
|
for (int i = 0; i < 5; i++) {
|
|
processOrdersDefect(orderIds);
|
|
processOrdersFixed(orderIds);
|
|
}
|
|
|
|
int iterations = 50;
|
|
long t0 = System.nanoTime();
|
|
for (int i = 0; i < iterations; i++) {
|
|
processOrdersDefect(orderIds);
|
|
}
|
|
long defectNs = System.nanoTime() - t0;
|
|
|
|
t0 = System.nanoTime();
|
|
for (int i = 0; i < iterations; i++) {
|
|
processOrdersFixed(orderIds);
|
|
}
|
|
long fixedNs = System.nanoTime() - t0;
|
|
|
|
double ratio = (double) defectNs / fixedNs;
|
|
System.out.printf("Defect: %,d ns / %d iters%n", defectNs, iterations);
|
|
System.out.printf("Fixed: %,d ns / %d iters%n", fixedNs, iterations);
|
|
System.out.printf("Ratio: %.1fx%n", ratio);
|
|
|
|
boolean pass = ratio > 5.0;
|
|
System.out.println("\nResult: " + (pass ? "PASS" : "FAIL") + " (ratio=" + String.format("%.1f", ratio) + "x)");
|
|
assert pass : "Expected speedup > 5x, got " + ratio;
|
|
}
|
|
}
|