rabbitmq-0001/0002: fifo service-queue O(C) member→O(1) map; blocked O(B) member→O(1) map
This commit is contained in:
parent
dff753904b
commit
3d0519f28d
3 changed files with 186 additions and 0 deletions
109
defects/rabbitmq/unit/RabbitMQTest.java
Normal file
109
defects/rabbitmq/unit/RabbitMQTest.java
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CWE-407 unit tests for RabbitMQ rabbit_fifo.erl defects.
|
||||
*
|
||||
* rabbitmq-0001: deps/rabbit/src/rabbit_fifo.erl maybe_queue_consumer()
|
||||
* priority_queue:member(Key, ServiceQueue) — O(C) linear scan per message dispatch.
|
||||
* Called from update_or_remove_con after checkout_one pops the consumer;
|
||||
* the consumer is NEVER in SQ1 at that point — the scan is 100% wasted work.
|
||||
* Fix: maintain a shadow map #{consumer_key => true} for O(1) maps:is_key().
|
||||
*
|
||||
* rabbitmq-0002: deps/rabbit/src/rabbit_queue_consumers.erl is_blocked()
|
||||
* priority_queue:member(Consumer, BlockedConsumers) — O(B) per delivery attempt
|
||||
* in single-active-consumer mode.
|
||||
* Fix: shadow set #{consumer => true} in #cr{} for O(1) maps:is_key().
|
||||
*/
|
||||
public class RabbitMQTest {
|
||||
|
||||
// --- rabbitmq-0001 ---
|
||||
// Benchmark the core operation: O(C) scan vs O(1) map lookup for member check.
|
||||
// In the post-checkout path the consumer is NEVER in the service queue —
|
||||
// the scan always does a full traversal and returns false (100% wasted).
|
||||
|
||||
static boolean pqMember_scan(List<Integer> pq, int key) {
|
||||
for (int k : pq) { // O(C) — defect: full scan, always false post-checkout
|
||||
if (k == key) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static boolean pqMember_map(Set<Integer> sqSet, int key) {
|
||||
return sqSet.contains(key); // O(1) — fix
|
||||
}
|
||||
|
||||
static void testRabbitMQ0001() throws Exception {
|
||||
int C = 500; // consumers in service queue
|
||||
List<Integer> sq = new ArrayList<>(C);
|
||||
Set<Integer> sqSet = new HashSet<>(C);
|
||||
for (int i = 1; i <= C; i++) { sq.add(i); sqSet.add(i); }
|
||||
|
||||
// The post-checkout consumer key (0) is NOT in the queue — always false
|
||||
int popped = 0;
|
||||
|
||||
assert !pqMember_scan(sq, popped) : "popped consumer must not be in SQ";
|
||||
assert !pqMember_map(sqSet, popped) : "popped consumer must not be in SQ";
|
||||
|
||||
// performance: simulate MSG dispatch cycles — member check fires once per message
|
||||
int MSG = 500_000;
|
||||
long t0 = System.nanoTime();
|
||||
for (int m = 0; m < MSG; m++) pqMember_scan(sq, popped);
|
||||
long tScan = System.nanoTime() - t0;
|
||||
|
||||
t0 = System.nanoTime();
|
||||
for (int m = 0; m < MSG; m++) pqMember_map(sqSet, popped);
|
||||
long tMap = System.nanoTime() - t0;
|
||||
|
||||
double ratio = (double) tScan / tMap;
|
||||
System.out.printf("rabbitmq-0001: scan=%.3fs map=%.3fs ratio=%.1f×%n",
|
||||
tScan / 1e9, tMap / 1e9, ratio);
|
||||
assert ratio > 10 : "Expected >10× speedup, got " + ratio;
|
||||
System.out.println("PASS rabbitmq-0001");
|
||||
}
|
||||
|
||||
// --- rabbitmq-0002 ---
|
||||
|
||||
static boolean isBlocked_pqMember(List<Integer> blocked, int consumer) {
|
||||
return blocked.contains(consumer); // O(B) — defect
|
||||
}
|
||||
|
||||
static boolean isBlocked_mapKey(Set<Integer> blockedSet, int consumer) {
|
||||
return blockedSet.contains(consumer); // O(1) — fix
|
||||
}
|
||||
|
||||
static void testRabbitMQ0002() throws Exception {
|
||||
int B = 300; // blocked consumers (high-prefetch setup)
|
||||
int MSG = 100_000;
|
||||
|
||||
List<Integer> blocked = new ArrayList<>(B);
|
||||
Set<Integer> blockedSet = new HashSet<>(B);
|
||||
for (int i = 0; i < B; i++) { blocked.add(i); blockedSet.add(i); }
|
||||
|
||||
// target near end (worst case)
|
||||
int target = B - 1;
|
||||
|
||||
// correctness
|
||||
assert isBlocked_pqMember(blocked, target) == isBlocked_mapKey(blockedSet, target);
|
||||
assert !isBlocked_pqMember(blocked, B + 99) && !isBlocked_mapKey(blockedSet, B + 99);
|
||||
|
||||
long t0 = System.nanoTime();
|
||||
for (int r = 0; r < MSG; r++) isBlocked_pqMember(blocked, target);
|
||||
long tMember = System.nanoTime() - t0;
|
||||
|
||||
t0 = System.nanoTime();
|
||||
for (int r = 0; r < MSG; r++) isBlocked_mapKey(blockedSet, target);
|
||||
long tMap = System.nanoTime() - t0;
|
||||
|
||||
double ratio = (double) tMember / tMap;
|
||||
System.out.printf("rabbitmq-0002: member=%.3fs map=%.3fs ratio=%.1f×%n",
|
||||
tMember / 1e9, tMap / 1e9, ratio);
|
||||
assert ratio > 5 : "Expected >5× speedup, got " + ratio;
|
||||
System.out.println("PASS rabbitmq-0002");
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testRabbitMQ0001();
|
||||
testRabbitMQ0002();
|
||||
System.out.println("ALL PASS");
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue