Skip to content

Commit df7be73

Browse files
authored
Merge pull request #541 from MDA2AV/actix-audit
fix actix cheating vectors
2 parents 3b7bdce + 14a8aeb commit df7be73

9 files changed

Lines changed: 88 additions & 160 deletions

File tree

frameworks/actix/src/main.rs

Lines changed: 3 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -87,35 +87,15 @@ struct JsonResponse {
8787
count: usize,
8888
}
8989

90-
// AppState is wrapped by web::Data which is already an Arc — no need to double-wrap
9190
struct AppState {
9291
dataset: Vec<DatasetItem>,
93-
json_cache: JsonCache,
9492
}
9593

96-
struct JsonCached {
97-
identity: Bytes,
98-
gzip: Bytes,
99-
brotli: Bytes,
100-
}
101-
102-
type JsonCache = HashMap<(usize, i64), JsonCached>;
103-
104-
// (count, m) pairs the benchmark + validation script fires. Precomputing covers
105-
// 100% of hot-path traffic; anything outside this set falls through to dynamic
106-
// serialization in json_endpoint.
107-
const JSON_CACHE_PAIRS: &[(usize, i64)] = &[
108-
// benchmark: json-gzip-{1,5,10,15,25,40,50}.raw
109-
(1, 3), (5, 7), (10, 2), (15, 5), (25, 4), (40, 8), (50, 6),
110-
// validation: validate.sh json-comp checks
111-
(12, 9), (31, 4), (50, 1),
112-
];
113-
11494
fn gzip_bytes(input: &[u8]) -> Bytes {
11595
use flate2::write::GzEncoder;
11696
use flate2::Compression;
11797
use std::io::Write;
118-
let mut enc = GzEncoder::new(Vec::with_capacity(input.len()), Compression::new(6));
98+
let mut enc = GzEncoder::new(Vec::with_capacity(input.len()), Compression::new(1));
11999
enc.write_all(input).ok();
120100
Bytes::from(enc.finish().unwrap_or_default())
121101
}
@@ -124,7 +104,7 @@ fn brotli_bytes(input: &[u8]) -> Bytes {
124104
use std::io::Write;
125105
let mut out = Vec::with_capacity(input.len());
126106
{
127-
let mut enc = brotli::CompressorWriter::new(&mut out, 4096, 11, 22);
107+
let mut enc = brotli::CompressorWriter::new(&mut out, 4096, 1, 22);
128108
enc.write_all(input).ok();
129109
enc.flush().ok();
130110
}
@@ -154,25 +134,6 @@ fn build_json_body(dataset: &[DatasetItem], count: usize, m: i64) -> Vec<u8> {
154134
serde_json::to_vec(&resp).unwrap_or_default()
155135
}
156136

157-
fn build_json_cache(dataset: &[DatasetItem]) -> JsonCache {
158-
let mut cache = HashMap::new();
159-
for &(count, m) in JSON_CACHE_PAIRS {
160-
let body = build_json_body(dataset, count, m);
161-
let identity = Bytes::from(body.clone());
162-
let gzip = gzip_bytes(&body);
163-
let brotli = brotli_bytes(&body);
164-
cache.insert(
165-
(count, m),
166-
JsonCached {
167-
identity,
168-
gzip,
169-
brotli,
170-
},
171-
);
172-
}
173-
cache
174-
}
175-
176137
fn load_dataset() -> Vec<DatasetItem> {
177138
let path = std::env::var("DATASET_PATH").unwrap_or_else(|_| "/data/dataset.json".to_string());
178139
match std::fs::read_to_string(&path) {
@@ -341,7 +302,6 @@ async fn upload(mut payload: web::Payload) -> HttpResponse {
341302
.body(size.to_string())
342303
}
343304

344-
// web::Data<AppState> — no Arc wrapping, web::Data handles it internally
345305
async fn json_endpoint(
346306
req: actix_web::HttpRequest,
347307
state: web::Data<AppState>,
@@ -356,35 +316,6 @@ async fn json_endpoint(
356316
.and_then(|v| v.to_str().ok())
357317
.unwrap_or("");
358318

359-
// Hot path: precomputed (count, m) pair. Serve bytes directly and skip both
360-
// JSON serialization and runtime compression.
361-
if let Some(cached) = state.json_cache.get(&(count, m)) {
362-
if ae.contains("br") {
363-
return HttpResponse::Ok()
364-
.insert_header((SERVER, SERVER_HDR.clone()))
365-
.insert_header(("Content-Type", "application/json"))
366-
.insert_header(("Content-Encoding", "br"))
367-
.insert_header(("Vary", "Accept-Encoding"))
368-
.body(cached.brotli.clone());
369-
}
370-
if ae.contains("gzip") {
371-
return HttpResponse::Ok()
372-
.insert_header((SERVER, SERVER_HDR.clone()))
373-
.insert_header(("Content-Type", "application/json"))
374-
.insert_header(("Content-Encoding", "gzip"))
375-
.insert_header(("Vary", "Accept-Encoding"))
376-
.body(cached.gzip.clone());
377-
}
378-
return HttpResponse::Ok()
379-
.insert_header((SERVER, SERVER_HDR.clone()))
380-
.insert_header(("Content-Type", "application/json"))
381-
.insert_header(("Vary", "Accept-Encoding"))
382-
.body(cached.identity.clone());
383-
}
384-
385-
// Fallback: dynamic serialization for non-cached queries (validation edge
386-
// cases, manual curl, etc.). Still honors Accept-Encoding by compressing
387-
// inline so the response is correct.
388319
let body = build_json_body(&state.dataset, count, m);
389320
if ae.contains("br") {
390321
return HttpResponse::Ok()
@@ -496,12 +427,7 @@ fn load_tls_config() -> Option<ServerConfig> {
496427
#[actix_web::main]
497428
async fn main() -> io::Result<()> {
498429
let dataset = load_dataset();
499-
let json_cache = build_json_cache(&dataset);
500-
501-
let state = web::Data::new(AppState {
502-
dataset,
503-
json_cache,
504-
});
430+
let state = web::Data::new(AppState { dataset });
505431

506432
let static_assets = web::Data::new(load_static_assets());
507433

site/data/current.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"date": "2026-04-16",
2+
"date": "2026-04-17",
33
"cpu": "AMD Ryzen Threadripper PRO 3995WX 64-Cores",
44
"cores": "64",
55
"threads": "128",
@@ -9,13 +9,13 @@
99
"kernel": "6.17.0-20-generic",
1010
"docker": "29.3.0",
1111
"docker_runtime": "runc",
12-
"governor": "powersave",
13-
"commit": "e5b3ac38",
12+
"governor": "performance",
13+
"commit": "3b7bdce6",
1414
"tcp": {
15-
"lo_mtu": "65536",
15+
"lo_mtu": "1500",
1616
"congestion": "cubic",
1717
"somaxconn": "65535",
1818
"rmem_max": "7500000",
1919
"wmem_max": "7500000"
2020
}
21-
}
21+
}

site/data/json-4096.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
{
33
"framework": "actix",
44
"language": "Rust",
5-
"rps": 1786503,
6-
"avg_latency": "1.79ms",
7-
"p99_latency": "29.90ms",
8-
"cpu": "6289.5%",
9-
"memory": "363.6MiB",
5+
"rps": 1221971,
6+
"avg_latency": "3.00ms",
7+
"p99_latency": "30.70ms",
8+
"cpu": "6657.6%",
9+
"memory": "294MiB",
1010
"connections": 4096,
1111
"threads": 64,
1212
"duration": "5s",
1313
"pipeline": 1,
14-
"bandwidth": "6.10GB/s",
15-
"input_bw": "85.19MB/s",
16-
"reconnects": 355422,
17-
"status_2xx": 8932518,
14+
"bandwidth": "4.17GB/s",
15+
"reconnects": 243075,
16+
"status_2xx": 6109857,
1817
"status_3xx": 0,
1918
"status_4xx": 0,
2019
"status_5xx": 0

site/data/json-comp-16384.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
{
33
"framework": "actix",
44
"language": "Rust",
5-
"rps": 1158892,
6-
"avg_latency": "10.63ms",
7-
"p99_latency": "33.00ms",
8-
"cpu": "3388.0%",
9-
"memory": "581.0MiB",
5+
"rps": 691184,
6+
"avg_latency": "20.23ms",
7+
"p99_latency": "60.00ms",
8+
"cpu": "5996.9%",
9+
"memory": "614MiB",
1010
"connections": 16384,
1111
"threads": 64,
1212
"duration": "5s",
1313
"pipeline": 1,
14-
"bandwidth": "866.04MB/s",
15-
"input_bw": "85.10MB/s",
16-
"reconnects": 224836,
17-
"status_2xx": 5806052,
14+
"bandwidth": "730.04MB/s",
15+
"reconnects": 130372,
16+
"status_2xx": 3455924,
1817
"status_3xx": 0,
1918
"status_4xx": 0,
2019
"status_5xx": 0

site/data/json-comp-4096.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
{
33
"framework": "actix",
44
"language": "Rust",
5-
"rps": 2270631,
6-
"avg_latency": "1.50ms",
7-
"p99_latency": "19.80ms",
8-
"cpu": "6282.5%",
9-
"memory": "362.6MiB",
5+
"rps": 732888,
6+
"avg_latency": "5.57ms",
7+
"p99_latency": "24.70ms",
8+
"cpu": "6632.4%",
9+
"memory": "235MiB",
1010
"connections": 4096,
1111
"threads": 64,
1212
"duration": "5s",
1313
"pipeline": 1,
14-
"bandwidth": "1.66GB/s",
15-
"input_bw": "166.74MB/s",
16-
"reconnects": 452367,
17-
"status_2xx": 11353159,
14+
"bandwidth": "774.37MB/s",
15+
"reconnects": 144745,
16+
"status_2xx": 3664444,
1817
"status_3xx": 0,
1918
"status_4xx": 0,
2019
"status_5xx": 0

site/data/json-comp-512.json

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@
22
{
33
"framework": "actix",
44
"language": "Rust",
5-
"rps": 1972569,
6-
"avg_latency": "131us",
7-
"p99_latency": "1.08ms",
8-
"cpu": "6154.7%",
9-
"memory": "109.7MiB",
5+
"rps": 728507,
6+
"avg_latency": "687us",
7+
"p99_latency": "3.82ms",
8+
"cpu": "6280.3%",
9+
"memory": "99MiB",
1010
"connections": 512,
1111
"threads": 64,
1212
"duration": "5s",
1313
"pipeline": 1,
14-
"bandwidth": "1.44GB/s",
15-
"input_bw": "144.85MB/s",
16-
"reconnects": 394513,
17-
"status_2xx": 9862847,
14+
"bandwidth": "769.81MB/s",
15+
"reconnects": 145502,
16+
"status_2xx": 3642539,
1817
"status_3xx": 0,
1918
"status_4xx": 0,
2019
"status_5xx": 0

site/data/static-1024.json

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -381,18 +381,19 @@
381381
{
382382
"framework": "rage",
383383
"language": "Ruby",
384-
"rps": 993470,
385-
"avg_latency": "1.09ms",
386-
"p99_latency": "1.09ms",
387-
"cpu": "6510.2%",
388-
"memory": "3.6GiB",
384+
"rps": 94201,
385+
"avg_latency": "11.13ms",
386+
"p99_latency": "11.13ms",
387+
"cpu": "8272.6%",
388+
"memory": "4.7GiB",
389389
"connections": 1024,
390390
"threads": 64,
391391
"duration": "5s",
392392
"pipeline": 1,
393-
"bandwidth": "17.05GB",
393+
"bandwidth": "5.59GB",
394+
"input_bw": "",
394395
"reconnects": 0,
395-
"status_2xx": 5024837,
396+
"status_2xx": 480457,
396397
"status_3xx": 0,
397398
"status_4xx": 0,
398399
"status_5xx": 0
@@ -460,18 +461,19 @@
460461
{
461462
"framework": "sinatra",
462463
"language": "Ruby",
463-
"rps": 209509,
464-
"avg_latency": "5.23ms",
465-
"p99_latency": "5.23ms",
466-
"cpu": "6421.5%",
467-
"memory": "9.1GiB",
464+
"rps": 187796,
465+
"avg_latency": "5.76ms",
466+
"p99_latency": "5.76ms",
467+
"cpu": "6366.8%",
468+
"memory": "7.5GiB",
468469
"connections": 1024,
469470
"threads": 64,
470471
"duration": "5s",
471472
"pipeline": 1,
472-
"bandwidth": "12.43GB",
473+
"bandwidth": "11.14GB",
474+
"input_bw": "",
473475
"reconnects": 0,
474-
"status_2xx": 1068394,
476+
"status_2xx": 954125,
475477
"status_3xx": 0,
476478
"status_4xx": 0,
477479
"status_5xx": 0

site/data/static-4096.json

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -381,18 +381,19 @@
381381
{
382382
"framework": "rage",
383383
"language": "Ruby",
384-
"rps": 961904,
385-
"avg_latency": "4.20ms",
386-
"p99_latency": "4.20ms",
387-
"cpu": "6438.4%",
388-
"memory": "3.6GiB",
384+
"rps": 92213,
385+
"avg_latency": "43.53ms",
386+
"p99_latency": "43.53ms",
387+
"cpu": "7315.3%",
388+
"memory": "4.6GiB",
389389
"connections": 4096,
390390
"threads": 64,
391391
"duration": "5s",
392392
"pipeline": 1,
393-
"bandwidth": "16.51GB",
393+
"bandwidth": "5.47GB",
394+
"input_bw": "",
394395
"reconnects": 0,
395-
"status_2xx": 4873051,
396+
"status_2xx": 471281,
396397
"status_3xx": 0,
397398
"status_4xx": 0,
398399
"status_5xx": 0
@@ -460,18 +461,19 @@
460461
{
461462
"framework": "sinatra",
462463
"language": "Ruby",
463-
"rps": 202168,
464-
"avg_latency": "19.71ms",
465-
"p99_latency": "19.71ms",
466-
"cpu": "6427.4%",
467-
"memory": "8.4GiB",
464+
"rps": 183177,
465+
"avg_latency": "21.55ms",
466+
"p99_latency": "21.55ms",
467+
"cpu": "6552.0%",
468+
"memory": "8.6GiB",
468469
"connections": 4096,
469470
"threads": 64,
470471
"duration": "5s",
471472
"pipeline": 1,
472-
"bandwidth": "12.00GB",
473+
"bandwidth": "10.86GB",
474+
"input_bw": "",
473475
"reconnects": 0,
474-
"status_2xx": 1032998,
476+
"status_2xx": 935378,
475477
"status_3xx": 0,
476478
"status_4xx": 0,
477479
"status_5xx": 0

0 commit comments

Comments
 (0)