@@ -3,11 +3,26 @@ use pyo3::create_exception;
3
3
use pyo3:: exceptions:: PyValueError ;
4
4
use pyo3:: prelude:: * ;
5
5
use pyo3:: types:: { PyList , PyTuple } ;
6
- use std:: cell:: RefCell ;
7
- use std:: sync:: Arc ;
6
+ use std:: cell:: { OnceCell , RefCell } ;
7
+ use std:: sync:: { Arc , OnceLock } ;
8
+ use tokio:: runtime:: { Handle , Runtime } ;
8
9
9
10
const LEGACY_TRANSACTION_CONTROL : i32 = -1 ;
10
11
12
+ fn rt ( ) -> Handle {
13
+ static RT : OnceLock < Runtime > = OnceLock :: new ( ) ;
14
+
15
+ RT . get_or_init ( || {
16
+ tokio:: runtime:: Builder :: new_multi_thread ( )
17
+ . worker_threads ( 1 )
18
+ . enable_all ( )
19
+ . build ( )
20
+ . unwrap ( )
21
+ } )
22
+ . handle ( )
23
+ . clone ( )
24
+ }
25
+
11
26
fn to_py_err ( error : libsql_core:: errors:: Error ) -> PyErr {
12
27
let msg = match error {
13
28
libsql:: Error :: SqliteFailure ( _, err) => err,
@@ -99,7 +114,7 @@ fn _connect_core(
99
114
) -> PyResult < Connection > {
100
115
let ver = env ! ( "CARGO_PKG_VERSION" ) ;
101
116
let ver = format ! ( "libsql-python-rpc-{ver}" ) ;
102
- let rt = tokio :: runtime :: Runtime :: new ( ) . unwrap ( ) ;
117
+ let rt = rt ( ) ;
103
118
let encryption_config = match encryption_key {
104
119
Some ( key) => {
105
120
let cipher = libsql:: Cipher :: default ( ) ;
@@ -147,9 +162,8 @@ fn _connect_core(
147
162
db,
148
163
conn : Arc :: new ( ConnectionGuard {
149
164
conn : Some ( conn) ,
150
- handle : rt. handle ( ) . clone ( ) ,
165
+ handle : rt. clone ( ) ,
151
166
} ) ,
152
- rt,
153
167
isolation_level,
154
168
autocommit,
155
169
} )
@@ -186,7 +200,6 @@ impl Drop for ConnectionGuard {
186
200
pub struct Connection {
187
201
db : libsql_core:: Database ,
188
202
conn : Arc < ConnectionGuard > ,
189
- rt : tokio:: runtime:: Runtime ,
190
203
isolation_level : Option < String > ,
191
204
autocommit : i32 ,
192
205
}
@@ -199,7 +212,6 @@ impl Connection {
199
212
fn cursor ( & self ) -> PyResult < Cursor > {
200
213
Ok ( Cursor {
201
214
arraysize : 1 ,
202
- rt : self . rt . handle ( ) . clone ( ) ,
203
215
conn : self . conn . clone ( ) ,
204
216
stmt : RefCell :: new ( None ) ,
205
217
rows : RefCell :: new ( None ) ,
@@ -212,24 +224,19 @@ impl Connection {
212
224
213
225
fn sync ( self_ : PyRef < ' _ , Self > , py : Python < ' _ > ) -> PyResult < ( ) > {
214
226
let fut = {
215
- let _enter = self_ . rt . enter ( ) ;
227
+ let _enter = rt ( ) . enter ( ) ;
216
228
self_. db . sync ( )
217
229
} ;
218
230
tokio:: pin!( fut) ;
219
231
220
- self_
221
- . rt
222
- . block_on ( check_signals ( py, fut) )
223
- . map_err ( to_py_err) ?;
232
+ rt ( ) . block_on ( check_signals ( py, fut) ) . map_err ( to_py_err) ?;
224
233
Ok ( ( ) )
225
234
}
226
235
227
236
fn commit ( self_ : PyRef < ' _ , Self > ) -> PyResult < ( ) > {
228
237
// TODO: Switch to libSQL transaction API
229
238
if !self_. conn . is_autocommit ( ) {
230
- self_
231
- . rt
232
- . block_on ( async { self_. conn . execute ( "COMMIT" , ( ) ) . await } )
239
+ rt ( ) . block_on ( async { self_. conn . execute ( "COMMIT" , ( ) ) . await } )
233
240
. map_err ( to_py_err) ?;
234
241
}
235
242
Ok ( ( ) )
@@ -238,9 +245,7 @@ impl Connection {
238
245
fn rollback ( self_ : PyRef < ' _ , Self > ) -> PyResult < ( ) > {
239
246
// TODO: Switch to libSQL transaction API
240
247
if !self_. conn . is_autocommit ( ) {
241
- self_
242
- . rt
243
- . block_on ( async { self_. conn . execute ( "ROLLBACK" , ( ) ) . await } )
248
+ rt ( ) . block_on ( async { self_. conn . execute ( "ROLLBACK" , ( ) ) . await } )
244
249
. map_err ( to_py_err) ?;
245
250
}
246
251
Ok ( ( ) )
@@ -252,8 +257,7 @@ impl Connection {
252
257
parameters : Option < & PyTuple > ,
253
258
) -> PyResult < Cursor > {
254
259
let cursor = Connection :: cursor ( & self_) ?;
255
- let rt = self_. rt . handle ( ) ;
256
- rt. block_on ( async { execute ( & cursor, sql, parameters) . await } ) ?;
260
+ rt ( ) . block_on ( async { execute ( & cursor, sql, parameters) . await } ) ?;
257
261
Ok ( cursor)
258
262
}
259
263
@@ -265,17 +269,15 @@ impl Connection {
265
269
let cursor = Connection :: cursor ( & self_) ?;
266
270
for parameters in parameters. unwrap ( ) . iter ( ) {
267
271
let parameters = parameters. extract :: < & PyTuple > ( ) ?;
268
- self_
269
- . rt
270
- . block_on ( async { execute ( & cursor, sql. clone ( ) , Some ( parameters) ) . await } ) ?;
272
+ rt ( ) . block_on ( async { execute ( & cursor, sql. clone ( ) , Some ( parameters) ) . await } ) ?;
271
273
}
272
274
Ok ( cursor)
273
275
}
274
276
275
277
fn executescript ( self_ : PyRef < ' _ , Self > , script : String ) -> PyResult < ( ) > {
276
- let _ = self_ . rt . block_on ( async {
277
- self_. conn . execute_batch ( & script) . await
278
- } ) . map_err ( to_py_err) ;
278
+ let _ = rt ( )
279
+ . block_on ( async { self_. conn . execute_batch ( & script) . await } )
280
+ . map_err ( to_py_err) ;
279
281
Ok ( ( ) )
280
282
}
281
283
@@ -316,7 +318,6 @@ impl Connection {
316
318
pub struct Cursor {
317
319
#[ pyo3( get, set) ]
318
320
arraysize : usize ,
319
- rt : tokio:: runtime:: Handle ,
320
321
conn : Arc < ConnectionGuard > ,
321
322
stmt : RefCell < Option < libsql_core:: Statement > > ,
322
323
rows : RefCell < Option < libsql_core:: Rows > > ,
@@ -336,9 +337,7 @@ impl Cursor {
336
337
sql : String ,
337
338
parameters : Option < & PyTuple > ,
338
339
) -> PyResult < pyo3:: PyRef < ' a , Self > > {
339
- self_
340
- . rt
341
- . block_on ( async { execute ( & self_, sql, parameters) . await } ) ?;
340
+ rt ( ) . block_on ( async { execute ( & self_, sql, parameters) . await } ) ?;
342
341
Ok ( self_)
343
342
}
344
343
@@ -349,9 +348,7 @@ impl Cursor {
349
348
) -> PyResult < pyo3:: PyRef < ' a , Cursor > > {
350
349
for parameters in parameters. unwrap ( ) . iter ( ) {
351
350
let parameters = parameters. extract :: < & PyTuple > ( ) ?;
352
- self_
353
- . rt
354
- . block_on ( async { execute ( & self_, sql. clone ( ) , Some ( parameters) ) . await } ) ?;
351
+ rt ( ) . block_on ( async { execute ( & self_, sql. clone ( ) , Some ( parameters) ) . await } ) ?;
355
352
}
356
353
Ok ( self_)
357
354
}
@@ -360,9 +357,7 @@ impl Cursor {
360
357
self_ : PyRef < ' a , Self > ,
361
358
script : String ,
362
359
) -> PyResult < pyo3:: PyRef < ' a , Self > > {
363
- self_
364
- . rt
365
- . block_on ( async { self_. conn . execute_batch ( & script) . await } )
360
+ rt ( ) . block_on ( async { self_. conn . execute_batch ( & script) . await } )
366
361
. map_err ( to_py_err) ?;
367
362
Ok ( self_)
368
363
}
@@ -398,7 +393,7 @@ impl Cursor {
398
393
let mut rows = self_. rows . borrow_mut ( ) ;
399
394
match rows. as_mut ( ) {
400
395
Some ( rows) => {
401
- let row = self_ . rt . block_on ( rows. next ( ) ) . map_err ( to_py_err) ?;
396
+ let row = rt ( ) . block_on ( rows. next ( ) ) . map_err ( to_py_err) ?;
402
397
match row {
403
398
Some ( row) => {
404
399
let row = convert_row ( self_. py ( ) , row, rows. column_count ( ) ) ?;
@@ -422,8 +417,7 @@ impl Cursor {
422
417
// done before iterating.
423
418
if !* self_. done . borrow ( ) {
424
419
for _ in 0 ..size {
425
- let row = self_
426
- . rt
420
+ let row = rt ( )
427
421
. block_on ( async { rows. next ( ) . await } )
428
422
. map_err ( to_py_err) ?;
429
423
match row {
@@ -450,8 +444,7 @@ impl Cursor {
450
444
Some ( rows) => {
451
445
let mut elements: Vec < Py < PyAny > > = vec ! [ ] ;
452
446
loop {
453
- let row = self_
454
- . rt
447
+ let row = rt ( )
455
448
. block_on ( async { rows. next ( ) . await } )
456
449
. map_err ( to_py_err) ?;
457
450
match row {
0 commit comments