@@ -6,7 +6,7 @@ use crate::ipc::{
6
6
} ;
7
7
use crate :: protocol:: {
8
8
consume_header, prepare_metadata, read_params, read_query, request_params, send_error,
9
- send_table_refs, Direction , Flag , Header , Packet ,
9
+ send_table_refs, write_header , Direction , Flag , Header , Packet ,
10
10
} ;
11
11
use crate :: sql:: Catalog ;
12
12
use anyhow:: Result ;
@@ -84,6 +84,21 @@ impl WorkerContext {
84
84
}
85
85
}
86
86
87
+ fn init_slots ( ) -> Result < ( ) > {
88
+ for locked_slot in Bus :: new ( ) . into_iter ( ) . flatten ( ) {
89
+ let mut stream = SlotStream :: from ( locked_slot) ;
90
+ stream. reset ( ) ;
91
+ let header = Header {
92
+ direction : Direction :: ToBackend ,
93
+ packet : Packet :: None ,
94
+ length : 0 ,
95
+ flag : Flag :: Last ,
96
+ } ;
97
+ write_header ( & mut stream, & header) ?;
98
+ }
99
+ Ok ( ( ) )
100
+ }
101
+
87
102
#[ pg_guard]
88
103
#[ no_mangle]
89
104
pub extern "C" fn worker_main ( _arg : pg_sys:: Datum ) {
@@ -98,10 +113,13 @@ pub extern "C" fn worker_main(_arg: pg_sys::Datum) {
98
113
let mut do_retry = false ;
99
114
let mut slots_with_error: Vec < ( SlotNumber , SmolStr ) > =
100
115
vec ! [ ( INVALID_SLOT_NUMBER , "" . into( ) ) ; max_backends( ) as usize ] ;
116
+ init_slots ( ) . expect ( "Failed to initialize slots" ) ;
101
117
102
- rt. block_on ( async {
103
- log ! ( "DataFusion worker is running" ) ;
104
- while do_retry || BackgroundWorker :: wait_latch ( Some ( WORKER_WAIT_TIMEOUT ) ) {
118
+ log ! ( "DataFusion worker is running" ) ;
119
+ while do_retry || BackgroundWorker :: wait_latch ( Some ( WORKER_WAIT_TIMEOUT ) ) {
120
+ // Do not use any pgrx API in this loop: it is multithreaded while PostgreSQL
121
+ // functions can work only in the main thread.
122
+ rt. block_on ( async {
105
123
do_retry = false ;
106
124
for ( id, locked_slot) in Bus :: new ( ) . into_iter ( ) . enumerate ( ) {
107
125
let Some ( slot) = locked_slot else {
@@ -191,16 +209,15 @@ pub extern "C" fn worker_main(_arg: pg_sys::Datum) {
191
209
response_error ( * slot_id, & mut ctx, stream, msg) ;
192
210
}
193
211
}
194
- }
195
- } ) ;
212
+ } ) ;
213
+ }
196
214
}
197
215
198
216
async fn parse ( header : Header , mut stream : SlotStream ) -> Result < TaskResult > {
199
217
assert_eq ! ( header. packet, Packet :: Parse ) ;
200
218
// TODO: handle long queries that span multiple packets.
201
219
assert_eq ! ( header. flag, Flag :: Last ) ;
202
220
let ( query, _) = read_query ( & mut stream) ?;
203
- log ! ( "Received query: {}" , query) ;
204
221
205
222
let stmts = DFParser :: parse_sql ( query) ?;
206
223
let Some ( stmt) = stmts. into_iter ( ) . next ( ) else {
@@ -234,26 +251,7 @@ async fn bind(
234
251
Ok ( TaskResult :: Bind ( plan) )
235
252
}
236
253
237
- #[ inline]
238
- fn slot_warning ( ) {
239
- // The slot should be locked before sending the response.
240
- // Normally this operation can not fail because its backend
241
- // is waiting for response and should not hold any locks.
242
- // But if it does it means that the old backend was terminated
243
- // and some other one acquired the same slot. So, fsm should
244
- // be reset to initial value.
245
- warning ! (
246
- "{} {} {} {}" ,
247
- "Failed to lock the slot for error response." ,
248
- "Looks like the old backend was terminated" ,
249
- "and the slot is acquired by another backend." ,
250
- "The state machine will be reset to the initial state." ,
251
- ) ;
252
- }
253
-
254
254
fn response_error ( id : SlotNumber , ctx : & mut WorkerContext , stream : SlotStream , message : & str ) {
255
255
ctx. flush ( id) ;
256
- if let Err ( err) = send_error ( id, stream, message) {
257
- warning ! ( "Failed to send the error message: {}" , err) ;
258
- }
256
+ send_error ( id, stream, message) . expect ( "Failed to send error response" ) ;
259
257
}
0 commit comments