578/240 — rustc-0004/vertx-0001/asterisk-0003/bitcoin-0001/actix-web-0003/hazelcast-0001+0002/rabbitmq-0005/nginx-0003/haproxy-0003/envoy-0003/istio-0003
This commit is contained in:
parent
dde5ec97fb
commit
e4ee168b1e
50 changed files with 4775 additions and 5 deletions
165
defects/rabbitmq/unit/ExportBindingAlgorithm.java
Normal file
165
defects/rabbitmq/unit/ExportBindingAlgorithm.java
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
package unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* rmq-0005: rabbit_mgmt_wm_definitions export_binding O(B×Q) → O(B+Q)
|
||||
*
|
||||
* Simulates the binding export scan in rabbit_mgmt_wm_definitions.erl.
|
||||
* SLOW: export_binding uses List.contains({name,vhost}) for each of B bindings.
|
||||
* FAST: pre-build a HashSet<String> of queue keys, then O(1) lookup per binding.
|
||||
*/
|
||||
public class ExportBindingAlgorithm {
|
||||
|
||||
// Simulated binding entry: destination name and vhost
|
||||
static final class BindingEntry {
|
||||
final String dest;
|
||||
final String vhost;
|
||||
final boolean isQueue; // dest_type == queue
|
||||
|
||||
BindingEntry(String dest, String vhost, boolean isQueue) {
|
||||
this.dest = dest;
|
||||
this.vhost = vhost;
|
||||
this.isQueue = isQueue;
|
||||
}
|
||||
}
|
||||
|
||||
// Simulated queue-name tuple: {name, vhost}
|
||||
static final class QueueKey {
|
||||
final String name;
|
||||
final String vhost;
|
||||
|
||||
QueueKey(String name, String vhost) {
|
||||
this.name = name;
|
||||
this.vhost = vhost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof QueueKey)) return false;
|
||||
QueueKey q = (QueueKey) o;
|
||||
return name.equals(q.name) && vhost.equals(q.vhost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * name.hashCode() + vhost.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
// SLOW: O(B×Q) — lists:member({Dest,VHost}, QNames) inside list comprehension
|
||||
static long slowOps = 0;
|
||||
|
||||
static boolean exportBindingSlow(BindingEntry b, List<QueueKey> qnames) {
|
||||
if (!b.isQueue) return true; // exchange binding, always export
|
||||
for (QueueKey q : qnames) {
|
||||
slowOps++;
|
||||
if (q.name.equals(b.dest) && q.vhost.equals(b.vhost)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static List<BindingEntry> slowExport(List<BindingEntry> bindings, List<QueueKey> qnames) {
|
||||
List<BindingEntry> result = new ArrayList<>();
|
||||
for (BindingEntry b : bindings) {
|
||||
if (exportBindingSlow(b, qnames)) {
|
||||
result.add(b);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// FAST: O(B+Q) — pre-build HashSet, then O(1) per binding
|
||||
static long fastOps = 0;
|
||||
|
||||
static Set<String> buildQNamesSet(List<QueueKey> qnames) {
|
||||
Set<String> s = new HashSet<>(qnames.size() * 2);
|
||||
for (QueueKey q : qnames) {
|
||||
fastOps++; // one insertion per queue
|
||||
s.add(q.name + "\0" + q.vhost);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static boolean exportBindingFast(BindingEntry b, Set<String> qnamesSet) {
|
||||
if (!b.isQueue) return true;
|
||||
fastOps++;
|
||||
return qnamesSet.contains(b.dest + "\0" + b.vhost);
|
||||
}
|
||||
|
||||
static List<BindingEntry> fastExport(List<BindingEntry> bindings, List<QueueKey> qnames) {
|
||||
Set<String> qnamesSet = buildQNamesSet(qnames);
|
||||
List<BindingEntry> result = new ArrayList<>();
|
||||
for (BindingEntry b : bindings) {
|
||||
if (exportBindingFast(b, qnamesSet)) {
|
||||
result.add(b);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// Build test data: Q queues, B bindings (all queue-type, all matching)
|
||||
int Q = 1000; // queue count
|
||||
int B = 5000; // binding count
|
||||
|
||||
List<QueueKey> qnames = new ArrayList<>(Q);
|
||||
for (int i = 0; i < Q; i++) {
|
||||
qnames.add(new QueueKey("queue-" + i, "vhost-" + (i % 5)));
|
||||
}
|
||||
|
||||
List<BindingEntry> bindings = new ArrayList<>(B);
|
||||
for (int i = 0; i < B; i++) {
|
||||
// Each binding points to a queue that exists — worst-case scan to find it
|
||||
int idx = (i * 7 + 3) % Q; // spread across queues
|
||||
bindings.add(new BindingEntry(
|
||||
qnames.get(idx).name,
|
||||
qnames.get(idx).vhost,
|
||||
true
|
||||
));
|
||||
}
|
||||
|
||||
// SLOW run
|
||||
slowOps = 0;
|
||||
List<BindingEntry> slowResult = slowExport(bindings, qnames);
|
||||
|
||||
// FAST run
|
||||
fastOps = 0;
|
||||
List<BindingEntry> fastResult = fastExport(bindings, qnames);
|
||||
|
||||
// Correctness check
|
||||
boolean pass = true;
|
||||
|
||||
if (slowResult.size() != fastResult.size()) {
|
||||
System.out.println("FAIL: result size mismatch: slow=" + slowResult.size() + " fast=" + fastResult.size());
|
||||
pass = false;
|
||||
}
|
||||
|
||||
// Verify same bindings exported (order may differ, but all B bindings match)
|
||||
if (slowResult.size() != B) {
|
||||
System.out.println("FAIL: expected all " + B + " bindings exported, got slow=" + slowResult.size());
|
||||
pass = false;
|
||||
}
|
||||
|
||||
// Ratio check
|
||||
double ratio = (double) slowOps / (double) fastOps;
|
||||
System.out.printf("N=%d/%d B=%d Q=%d slow=%d ops fast=%d ops ratio=%.1fx%n",
|
||||
B, Q, B, Q, slowOps, fastOps, ratio);
|
||||
|
||||
if (ratio < 5.0) {
|
||||
System.out.println("FAIL: ratio too low (expected >= 5x)");
|
||||
pass = false;
|
||||
}
|
||||
|
||||
if (pass) {
|
||||
System.out.println("1/1 PASS");
|
||||
} else {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue