@@ -28,7 +28,7 @@ use futures::StreamExt;
28
28
use futures_util:: Future ;
29
29
use http:: StatusCode ;
30
30
use serde:: { Deserialize , Serialize } ;
31
- use serde_json:: { json, Value } ;
31
+ use serde_json:: json;
32
32
use std:: collections:: HashMap ;
33
33
use std:: pin:: Pin ;
34
34
use std:: sync:: Arc ;
@@ -43,15 +43,14 @@ use crate::metrics::QUERY_EXECUTE_TIME;
43
43
use crate :: option:: Mode ;
44
44
use crate :: parseable:: { StreamNotFound , PARSEABLE } ;
45
45
use crate :: query:: error:: ExecuteError ;
46
- use crate :: query:: { execute_stream, CountsRequest , CountsResponse , Query as LogicalQuery } ;
46
+ use crate :: query:: { execute , execute_stream, CountsRequest , CountsResponse , Query as LogicalQuery } ;
47
47
use crate :: query:: { TableScanVisitor , QUERY_SESSION } ;
48
48
use crate :: rbac:: Users ;
49
49
use crate :: response:: { QueryResponse , TIME_ELAPSED_HEADER } ;
50
50
use crate :: storage:: ObjectStorageError ;
51
51
use crate :: utils:: actix:: extract_session_key_from_req;
52
52
use crate :: utils:: time:: { TimeParseError , TimeRange } ;
53
53
use crate :: utils:: user_auth_for_datasets;
54
- use futures_core:: Stream as CoreStream ;
55
54
/// Query Request through http endpoint.
56
55
#[ derive( Debug , Deserialize , Serialize , Clone ) ]
57
56
#[ serde( rename_all = "camelCase" ) ]
@@ -64,6 +63,8 @@ pub struct Query {
64
63
#[ serde( skip) ]
65
64
pub fields : bool ,
66
65
#[ serde( skip) ]
66
+ pub streaming : bool ,
67
+ #[ serde( skip) ]
67
68
pub filter_tags : Option < Vec < String > > ,
68
69
}
69
70
@@ -75,7 +76,6 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<HttpRespons
75
76
{
76
77
Ok ( raw_logical_plan) => raw_logical_plan,
77
78
Err ( _) => {
78
- //if logical plan creation fails, create streams and try again
79
79
create_streams_for_querier ( ) . await ;
80
80
session_state
81
81
. create_logical_plan ( & query_request. query )
@@ -85,10 +85,8 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<HttpRespons
85
85
let time_range =
86
86
TimeRange :: parse_human_time ( & query_request. start_time , & query_request. end_time ) ?;
87
87
88
- // Create a visitor to extract the table names present in query
89
88
let mut visitor = TableScanVisitor :: default ( ) ;
90
89
let _ = raw_logical_plan. visit ( & mut visitor) ;
91
-
92
90
let tables = visitor. into_inner ( ) ;
93
91
update_schema_when_distributed ( & tables) . await ?;
94
92
let query: LogicalQuery = into_query ( & query_request, & session_state, time_range) . await ?;
@@ -103,65 +101,118 @@ pub async fn query(req: HttpRequest, query_request: Query) -> Result<HttpRespons
103
101
user_auth_for_datasets ( & permissions, & tables) ?;
104
102
105
103
let time = Instant :: now ( ) ;
106
- // Intercept `count(*)`` queries and use the counts API
104
+
107
105
if let Some ( column_name) = query. is_logical_plan_count_without_filters ( ) {
108
- let counts_req = CountsRequest {
109
- stream : table_name. clone ( ) ,
110
- start_time : query_request. start_time . clone ( ) ,
111
- end_time : query_request. end_time . clone ( ) ,
112
- num_bins : 1 ,
113
- } ;
114
- let count_records = counts_req. get_bin_density ( ) . await ?;
115
- // NOTE: this should not panic, since there is atleast one bin, always
116
- let count = count_records[ 0 ] . count ;
117
- let response = if query_request. fields {
118
- json ! ( {
119
- "fields" : [ & column_name] ,
120
- "records" : [ json!( { column_name: count} ) ]
121
- } )
122
- } else {
123
- Value :: Array ( vec ! [ json!( { column_name: count} ) ] )
124
- } ;
106
+ return handle_count_query ( & query_request, & table_name, column_name, time) . await ;
107
+ }
125
108
126
- let total_time = format ! ( "{:?}" , time. elapsed( ) ) ;
127
- let time = time. elapsed ( ) . as_secs_f64 ( ) ;
109
+ if !query_request. streaming {
110
+ return handle_non_streaming_query ( query, & table_name, & query_request, time) . await ;
111
+ }
112
+
113
+ handle_streaming_query ( query, & table_name, & query_request, time) . await
114
+ }
128
115
129
- QUERY_EXECUTE_TIME
130
- . with_label_values ( & [ & table_name] )
131
- . observe ( time) ;
116
+ async fn handle_count_query (
117
+ query_request : & Query ,
118
+ table_name : & str ,
119
+ column_name : & str ,
120
+ time : Instant ,
121
+ ) -> Result < HttpResponse , QueryError > {
122
+ let counts_req = CountsRequest {
123
+ stream : table_name. to_string ( ) ,
124
+ start_time : query_request. start_time . clone ( ) ,
125
+ end_time : query_request. end_time . clone ( ) ,
126
+ num_bins : 1 ,
127
+ } ;
128
+ let count_records = counts_req. get_bin_density ( ) . await ?;
129
+ let count = count_records[ 0 ] . count ;
130
+ let response = if query_request. fields {
131
+ json ! ( {
132
+ "fields" : [ column_name] ,
133
+ "records" : [ json!( { column_name: count} ) ]
134
+ } )
135
+ } else {
136
+ serde_json:: Value :: Array ( vec ! [ json!( { column_name: count} ) ] )
137
+ } ;
132
138
133
- return Ok ( HttpResponse :: Ok ( )
134
- . insert_header ( ( TIME_ELAPSED_HEADER , total_time. as_str ( ) ) )
135
- . json ( response) ) ;
139
+ let total_time = format ! ( "{:?}" , time. elapsed( ) ) ;
140
+ let time = time. elapsed ( ) . as_secs_f64 ( ) ;
141
+
142
+ QUERY_EXECUTE_TIME
143
+ . with_label_values ( & [ table_name] )
144
+ . observe ( time) ;
145
+
146
+ Ok ( HttpResponse :: Ok ( )
147
+ . insert_header ( ( TIME_ELAPSED_HEADER , total_time. as_str ( ) ) )
148
+ . json ( response) )
149
+ }
150
+
151
+ async fn handle_non_streaming_query (
152
+ query : LogicalQuery ,
153
+ table_name : & str ,
154
+ query_request : & Query ,
155
+ time : Instant ,
156
+ ) -> Result < HttpResponse , QueryError > {
157
+ let ( records, fields) = execute ( query, table_name) . await ?;
158
+ let total_time = format ! ( "{:?}" , time. elapsed( ) ) ;
159
+ let time = time. elapsed ( ) . as_secs_f64 ( ) ;
160
+
161
+ QUERY_EXECUTE_TIME
162
+ . with_label_values ( & [ table_name] )
163
+ . observe ( time) ;
164
+ let response = QueryResponse {
165
+ records,
166
+ fields,
167
+ fill_null : query_request. send_null ,
168
+ with_fields : query_request. fields ,
136
169
}
137
- let ( records_stream, fields) = execute_stream ( query, & table_name) . await ?;
170
+ . to_http ( ) ?;
171
+ Ok ( HttpResponse :: Ok ( )
172
+ . insert_header ( ( TIME_ELAPSED_HEADER , total_time. as_str ( ) ) )
173
+ . json ( response) )
174
+ }
175
+
176
+ async fn handle_streaming_query (
177
+ query : LogicalQuery ,
178
+ table_name : & str ,
179
+ query_request : & Query ,
180
+ time : Instant ,
181
+ ) -> Result < HttpResponse , QueryError > {
182
+ let ( records_stream, fields) = execute_stream ( query, table_name) . await ?;
138
183
let fields = fields. clone ( ) ;
139
- let stream = records_stream . map ( move |batch_result| {
140
- match batch_result {
141
- Ok ( batch ) => {
142
- // convert record batch to JSON
143
- let response = QueryResponse {
144
- records : vec ! [ batch ] ,
145
- fields : fields . clone ( ) ,
146
- fill_null : query_request. send_null ,
147
- with_fields : query_request . fields ,
148
- }
149
- . to_http ( )
150
- . unwrap_or_else ( |e| {
151
- error ! ( "Failed to parse record batch into JSON: {}" , e ) ;
152
- json ! ( { } )
153
- } ) ;
154
- Ok ( Bytes :: from ( format ! ( "{} \n " , response . to_string ( ) ) ) )
184
+ let total_time = format ! ( "{:?}" , time . elapsed ( ) ) ;
185
+ let time = time . elapsed ( ) . as_secs_f64 ( ) ;
186
+ QUERY_EXECUTE_TIME
187
+ . with_label_values ( & [ table_name ] )
188
+ . observe ( time ) ;
189
+
190
+ let send_null = query_request . send_null ;
191
+ let with_fields = query_request. fields ;
192
+
193
+ let stream = records_stream . map ( move |batch_result| match batch_result {
194
+ Ok ( batch ) => {
195
+ let response = QueryResponse {
196
+ records : vec ! [ batch] ,
197
+ fields : fields . clone ( ) ,
198
+ fill_null : send_null ,
199
+ with_fields ,
155
200
}
156
- Err ( e) => Err ( actix_web:: error:: ErrorInternalServerError ( e) ) ,
201
+ . to_http ( )
202
+ . unwrap_or_else ( |e| {
203
+ error ! ( "Failed to parse record batch into JSON: {}" , e) ;
204
+ json ! ( { } )
205
+ } ) ;
206
+ Ok ( Bytes :: from ( format ! ( "{}\n " , response) ) )
157
207
}
208
+ Err ( e) => Err ( actix_web:: error:: ErrorInternalServerError ( e) ) ,
158
209
} ) ;
159
210
160
- let boxed_stream =
161
- Box :: pin ( stream) as Pin < Box < dyn CoreStream < Item = Result < Bytes , actix_web:: Error > > + Send > > ;
211
+ let boxed_stream = Box :: pin ( stream) ;
162
212
163
213
Ok ( HttpResponse :: Ok ( )
164
214
. content_type ( "application/json" )
215
+ . insert_header ( ( TIME_ELAPSED_HEADER , total_time. as_str ( ) ) )
165
216
. streaming ( boxed_stream) )
166
217
}
167
218
@@ -234,6 +285,10 @@ impl FromRequest for Query {
234
285
query. send_null = params. get ( "sendNull" ) . cloned ( ) . unwrap_or ( false ) ;
235
286
}
236
287
288
+ if !query. streaming {
289
+ query. streaming = params. get ( "streaming" ) . cloned ( ) . unwrap_or ( false ) ;
290
+ }
291
+
237
292
Ok ( query)
238
293
} ;
239
294
@@ -297,6 +352,7 @@ fn transform_query_for_ingestor(query: &Query) -> Option<Query> {
297
352
send_null : query. send_null ,
298
353
start_time : start_time. to_rfc3339 ( ) ,
299
354
end_time : end_time. to_rfc3339 ( ) ,
355
+ streaming : query. streaming ,
300
356
} ;
301
357
302
358
Some ( q)
0 commit comments