17
17
*/
18
18
19
19
use arrow_array:: RecordBatch ;
20
- use arrow_flight:: encode:: FlightDataEncoderBuilder ;
21
20
use arrow_flight:: flight_service_server:: FlightServiceServer ;
22
21
use arrow_flight:: PollInfo ;
23
22
use arrow_schema:: ArrowError ;
24
23
25
24
use datafusion:: common:: tree_node:: TreeNode ;
26
25
use serde_json:: json;
27
26
use std:: net:: SocketAddr ;
28
- use std:: sync:: Arc ;
29
27
use std:: time:: Instant ;
30
28
use tonic:: codec:: CompressionEncoding ;
31
29
@@ -34,34 +32,38 @@ use futures_util::{Future, TryFutureExt};
34
32
use tonic:: transport:: { Identity , Server , ServerTlsConfig } ;
35
33
use tonic_web:: GrpcWebLayer ;
36
34
37
- use crate :: event:: commit_schema;
38
35
use crate :: handlers:: http:: cluster:: get_ingestor_info;
39
- use crate :: handlers:: http:: fetch_schema;
40
36
37
+ use crate :: handlers:: { CACHE_RESULTS_HEADER_KEY , CACHE_VIEW_HEADER_KEY , USER_ID_HEADER_KEY } ;
41
38
use crate :: metrics:: QUERY_EXECUTE_TIME ;
42
- use crate :: option:: { Mode , CONFIG } ;
39
+ use crate :: option:: CONFIG ;
43
40
44
41
use crate :: handlers:: livetail:: cross_origin_config;
45
42
46
- use crate :: handlers:: http:: query:: { authorize_and_set_filter_tags, into_query} ;
43
+ use crate :: handlers:: http:: query:: {
44
+ authorize_and_set_filter_tags, into_query, put_results_in_cache, update_schema_when_distributed,
45
+ } ;
47
46
use crate :: query:: { TableScanVisitor , QUERY_SESSION } ;
48
- use crate :: storage :: object_storage :: commit_schema_to_storage ;
47
+ use crate :: querycache :: QueryCacheManager ;
49
48
use crate :: utils:: arrow:: flight:: {
50
- append_temporary_events, get_query_from_ticket, run_do_get_rpc, send_to_ingester,
49
+ append_temporary_events, get_query_from_ticket, into_flight_data, run_do_get_rpc,
50
+ send_to_ingester,
51
51
} ;
52
52
use arrow_flight:: {
53
53
flight_service_server:: FlightService , Action , ActionType , Criteria , Empty , FlightData ,
54
54
FlightDescriptor , FlightInfo , HandshakeRequest , HandshakeResponse , PutResult , SchemaAsIpc ,
55
55
SchemaResult , Ticket ,
56
56
} ;
57
57
use arrow_ipc:: writer:: IpcWriteOptions ;
58
- use futures:: { stream, TryStreamExt } ;
58
+ use futures:: stream;
59
59
use tonic:: { Request , Response , Status , Streaming } ;
60
60
61
61
use crate :: handlers:: livetail:: extract_session_key;
62
62
use crate :: metadata:: STREAM_INFO ;
63
63
use crate :: rbac:: Users ;
64
64
65
+ use super :: http:: query:: get_results_from_cache;
66
+
65
67
#[ derive( Clone , Debug ) ]
66
68
pub struct AirServiceImpl { }
67
69
@@ -130,7 +132,7 @@ impl FlightService for AirServiceImpl {
130
132
async fn do_get ( & self , req : Request < Ticket > ) -> Result < Response < Self :: DoGetStream > , Status > {
131
133
let key = extract_session_key ( req. metadata ( ) ) ?;
132
134
133
- let ticket = get_query_from_ticket ( req) ?;
135
+ let ticket = get_query_from_ticket ( & req) ?;
134
136
135
137
log:: info!( "query requested to airplane: {:?}" , ticket) ;
136
138
@@ -150,32 +152,57 @@ impl FlightService for AirServiceImpl {
150
152
let mut visitor = TableScanVisitor :: default ( ) ;
151
153
let _ = raw_logical_plan. visit ( & mut visitor) ;
152
154
153
- let tables = visitor. into_inner ( ) ;
154
-
155
- if CONFIG . parseable . mode == Mode :: Query {
156
- // using http to get the schema. may update to use flight later
157
- for table in tables {
158
- if let Ok ( new_schema) = fetch_schema ( & table) . await {
159
- // commit schema merges the schema internally and updates the schema in storage.
160
- commit_schema_to_storage ( & table, new_schema. clone ( ) )
161
- . await
162
- . map_err ( |err| Status :: internal ( err. to_string ( ) ) ) ?;
163
- commit_schema ( & table, Arc :: new ( new_schema) )
164
- . map_err ( |err| Status :: internal ( err. to_string ( ) ) ) ?;
165
- }
166
- }
155
+ let streams = visitor. into_inner ( ) ;
156
+
157
+ let query_cache_manager = QueryCacheManager :: global ( CONFIG . parseable . query_cache_size )
158
+ . await
159
+ . unwrap_or ( None ) ;
160
+
161
+ let cache_results = req
162
+ . metadata ( )
163
+ . get ( CACHE_RESULTS_HEADER_KEY )
164
+ . and_then ( |value| value. to_str ( ) . ok ( ) ) ; // I dont think we need to own this.
165
+
166
+ let show_cached = req
167
+ . metadata ( )
168
+ . get ( CACHE_VIEW_HEADER_KEY )
169
+ . and_then ( |value| value. to_str ( ) . ok ( ) ) ;
170
+
171
+ let user_id = req
172
+ . metadata ( )
173
+ . get ( USER_ID_HEADER_KEY )
174
+ . and_then ( |value| value. to_str ( ) . ok ( ) ) ;
175
+ let stream_name = streams
176
+ . first ( )
177
+ . ok_or_else ( || Status :: aborted ( "Malformed SQL Provided, Table Name Not Found" ) ) ?
178
+ . to_owned ( ) ;
179
+
180
+ // send the cached results
181
+ if let Ok ( cache_results) = get_results_from_cache (
182
+ show_cached,
183
+ query_cache_manager,
184
+ & stream_name,
185
+ user_id,
186
+ & ticket. start_time ,
187
+ & ticket. end_time ,
188
+ & ticket. query ,
189
+ ticket. send_null ,
190
+ ticket. fields ,
191
+ )
192
+ . await
193
+ {
194
+ return cache_results. into_flight ( ) ;
167
195
}
168
196
197
+ update_schema_when_distributed ( streams)
198
+ . await
199
+ . map_err ( |err| Status :: internal ( err. to_string ( ) ) ) ?;
200
+
169
201
// map payload to query
170
202
let mut query = into_query ( & ticket, & session_state)
171
203
. await
172
204
. map_err ( |_| Status :: internal ( "Failed to parse query" ) ) ?;
173
205
174
- // if table name is not present it is a Malformed Query
175
- let stream_name = query
176
- . first_table_name ( )
177
- . ok_or_else ( || Status :: invalid_argument ( "Malformed Query" ) ) ?;
178
-
179
206
let event =
180
207
if send_to_ingester ( query. start . timestamp_millis ( ) , query. end . timestamp_millis ( ) ) {
181
208
let sql = format ! ( "select * from {}" , & stream_name) ;
@@ -210,11 +237,23 @@ impl FlightService for AirServiceImpl {
210
237
Status :: permission_denied ( "User Does not have permission to access this" )
211
238
} ) ?;
212
239
let time = Instant :: now ( ) ;
213
- let ( results , _) = query
240
+ let ( records , _) = query
214
241
. execute ( stream_name. clone ( ) )
215
242
. await
216
243
. map_err ( |err| Status :: internal ( err. to_string ( ) ) ) ?;
217
244
245
+ put_results_in_cache (
246
+ cache_results,
247
+ user_id,
248
+ query_cache_manager,
249
+ & stream_name,
250
+ & records,
251
+ query. start . to_rfc3339 ( ) ,
252
+ query. end . to_rfc3339 ( ) ,
253
+ ticket. query ,
254
+ )
255
+ . await ;
256
+
218
257
/*
219
258
* INFO: No returning the schema with the data.
220
259
* kept it in case it needs to be sent in the future.
@@ -226,18 +265,7 @@ impl FlightService for AirServiceImpl {
226
265
.collect::<Vec<_>>();
227
266
let schema = Schema::try_merge(schemas).map_err(|err| Status::internal(err.to_string()))?;
228
267
*/
229
- let input_stream = futures:: stream:: iter ( results. into_iter ( ) . map ( Ok ) ) ;
230
- let write_options = IpcWriteOptions :: default ( )
231
- . try_with_compression ( Some ( arrow_ipc:: CompressionType ( 1 ) ) )
232
- . map_err ( |err| Status :: failed_precondition ( err. to_string ( ) ) ) ?;
233
-
234
- let flight_data_stream = FlightDataEncoderBuilder :: new ( )
235
- . with_max_flight_data_size ( usize:: MAX )
236
- . with_options ( write_options)
237
- // .with_schema(schema.into())
238
- . build ( input_stream) ;
239
-
240
- let flight_data_stream = flight_data_stream. map_err ( |err| Status :: unknown ( err. to_string ( ) ) ) ;
268
+ let out = into_flight_data ( records) ;
241
269
242
270
if let Some ( event) = event {
243
271
event. clear ( & stream_name) ;
@@ -248,9 +276,7 @@ impl FlightService for AirServiceImpl {
248
276
. with_label_values ( & [ & format ! ( "flight-query-{}" , stream_name) ] )
249
277
. observe ( time) ;
250
278
251
- Ok ( Response :: new (
252
- Box :: pin ( flight_data_stream) as Self :: DoGetStream
253
- ) )
279
+ out
254
280
}
255
281
256
282
async fn do_put (
0 commit comments