@@ -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
9190struct 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-
11494fn 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-
176137fn 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
345305async 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]
497428async 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
0 commit comments