@@ -35,7 +35,6 @@ use futures::stream::once;
3535use futures:: { Stream , StreamExt , future} ;
3636use futures_util:: Future ;
3737use http:: StatusCode ;
38- use itertools:: Itertools ;
3938use serde:: { Deserialize , Serialize } ;
4039use serde_json:: { Value , json} ;
4140use std:: collections:: HashMap ;
@@ -52,7 +51,7 @@ use crate::query::error::ExecuteError;
5251use crate :: query:: { CountsRequest , Query as LogicalQuery , execute} ;
5352use crate :: query:: { QUERY_SESSION , resolve_stream_names} ;
5453use crate :: rbac:: Users ;
55- use crate :: response:: QueryResponse ;
54+ use crate :: response:: { QueryResponse , force_memory_release } ;
5655use crate :: storage:: ObjectStorageError ;
5756use crate :: utils:: actix:: extract_session_key_from_req;
5857use crate :: utils:: time:: { TimeParseError , TimeRange } ;
@@ -241,9 +240,15 @@ async fn handle_non_streaming_query(
241240 with_fields : query_request. fields ,
242241 }
243242 . to_json ( ) ?;
244- Ok ( HttpResponse :: Ok ( )
243+
244+ let http_response = HttpResponse :: Ok ( )
245245 . insert_header ( ( TIME_ELAPSED_HEADER , total_time. as_str ( ) ) )
246- . json ( response) )
246+ . json ( response) ;
247+
248+ // Force memory release after HTTP response is fully created
249+ force_memory_release ( ) ;
250+
251+ Ok ( http_response)
247252}
248253
249254/// Handles streaming queries, returning results as newline-delimited JSON (NDJSON).
@@ -324,18 +329,26 @@ fn create_batch_processor(
324329) -> impl FnMut ( Result < RecordBatch , QueryError > ) -> Result < Bytes , actix_web:: Error > {
325330 move |batch_result| match batch_result {
326331 Ok ( batch) => {
327- let response = QueryResponse {
332+ // Create response and immediately process to reduce memory retention
333+ let query_response = QueryResponse {
328334 records : vec ! [ batch] ,
329335 fields : Vec :: new ( ) ,
330336 fill_null : send_null,
331337 with_fields : false ,
332- }
333- . to_json ( )
334- . map_err ( |e| {
338+ } ;
339+
340+ let response = query_response . to_json ( ) . map_err ( |e| {
335341 error ! ( "Failed to parse record batch into JSON: {}" , e) ;
336342 actix_web:: error:: ErrorInternalServerError ( e)
337343 } ) ?;
338- Ok ( Bytes :: from ( format ! ( "{response}\n " ) ) )
344+
345+ // Convert to bytes and explicitly drop the response object
346+ let bytes_result = Bytes :: from ( format ! ( "{response}\n " ) ) ;
347+ drop ( response) ; // Explicit cleanup
348+
349+ force_memory_release ( ) ;
350+
351+ Ok ( bytes_result)
339352 }
340353 Err ( e) => Err ( actix_web:: error:: ErrorInternalServerError ( e) ) ,
341354 }
@@ -380,12 +393,19 @@ pub async fn get_counts(
380393 let ( records, _) = get_records_and_fields ( & query_request, & creds) . await ?;
381394
382395 if let Some ( records) = records {
383- let json_records = record_batches_to_json ( & records) ?;
384- let records = json_records. into_iter ( ) . map ( Value :: Object ) . collect_vec ( ) ;
396+ // Use optimized JSON conversion with explicit memory management
397+ let json_records = {
398+ let converted = record_batches_to_json ( & records) ?;
399+ drop ( records) ; // Explicitly drop the original records early
400+ converted
401+ } ;
402+
403+ let processed_records: Vec < Value > =
404+ json_records. into_iter ( ) . map ( Value :: Object ) . collect ( ) ;
385405
386406 let res = json ! ( {
387407 "fields" : vec![ "start_time" , "endTime" , "count" ] ,
388- "records" : records ,
408+ "records" : processed_records ,
389409 } ) ;
390410
391411 return Ok ( web:: Json ( res) ) ;
0 commit comments