@@ -39,6 +39,7 @@ impl Builder<()> {
39
39
path: path. as_ref( ) . to_path_buf( ) ,
40
40
flags: crate :: OpenFlags :: default ( ) ,
41
41
encryption_config: None ,
42
+ skip_safety_assert: false ,
42
43
} ,
43
44
}
44
45
}
@@ -64,7 +65,8 @@ impl Builder<()> {
64
65
read_your_writes: true ,
65
66
sync_interval: None ,
66
67
http_request_callback: None ,
67
- namespace: None
68
+ namespace: None ,
69
+ skip_safety_assert: false ,
68
70
} ,
69
71
}
70
72
}
@@ -137,6 +139,7 @@ cfg_core! {
137
139
path: std:: path:: PathBuf ,
138
140
flags: crate :: OpenFlags ,
139
141
encryption_config: Option <EncryptionConfig >,
142
+ skip_safety_assert: bool ,
140
143
}
141
144
142
145
impl Builder <Local > {
@@ -155,10 +158,29 @@ cfg_core! {
155
158
self
156
159
}
157
160
161
+ /// Skip the saftey assert used to ensure that sqlite3 is configured correctly for the way
162
+ /// that libsql uses the ffi code. By default, libsql will try to use the SERIALIZED
163
+ /// threadsafe mode for sqlite3. This allows us to implement Send/Sync for all the types to
164
+ /// allow them to move between threads safely. Due to the fact that sqlite3 has a global
165
+ /// config this may conflict with other sqlite3 connections in the same process.
166
+ ///
167
+ /// Using this setting is very UNSAFE and you are expected to use the libsql in adherence
168
+ /// with the sqlite3 threadsafe rules or else you WILL create undefined behavior. Use at
169
+ /// your own risk.
170
+ pub unsafe fn skip_saftey_assert( mut self , skip: bool ) -> Builder <Local > {
171
+ self . inner. skip_safety_assert = skip;
172
+ self
173
+ }
174
+
158
175
/// Build the local database.
159
176
pub async fn build( self ) -> Result <Database > {
160
177
let db = if self . inner. path == std:: path:: Path :: new( ":memory:" ) {
161
- let db = crate :: local:: Database :: open( ":memory:" , crate :: OpenFlags :: default ( ) ) ?;
178
+ let db = if !self . inner. skip_safety_assert {
179
+ crate :: local:: Database :: open( ":memory:" , crate :: OpenFlags :: default ( ) ) ?
180
+ } else {
181
+ unsafe { crate :: local:: Database :: open_raw( ":memory:" , crate :: OpenFlags :: default ( ) ) ? }
182
+ } ;
183
+
162
184
Database {
163
185
db_type: DbType :: Memory { db } ,
164
186
max_write_replication_index: Default :: default ( ) ,
@@ -176,6 +198,7 @@ cfg_core! {
176
198
path,
177
199
flags: self . inner. flags,
178
200
encryption_config: self . inner. encryption_config,
201
+ skip_saftey_assert: self . inner. skip_safety_assert
179
202
} ,
180
203
max_write_replication_index: Default :: default ( ) ,
181
204
}
@@ -196,6 +219,7 @@ cfg_replication! {
196
219
sync_interval: Option <std:: time:: Duration >,
197
220
http_request_callback: Option <crate :: util:: HttpRequestCallback >,
198
221
namespace: Option <String >,
222
+ skip_safety_assert: bool ,
199
223
}
200
224
201
225
/// Local replica configuration type in [`Builder`].
@@ -270,6 +294,20 @@ cfg_replication! {
270
294
self
271
295
}
272
296
297
+ /// Skip the saftey assert used to ensure that sqlite3 is configured correctly for the way
298
+ /// that libsql uses the ffi code. By default, libsql will try to use the SERIALIZED
299
+ /// threadsafe mode for sqlite3. This allows us to implement Send/Sync for all the types to
300
+ /// allow them to move between threads safely. Due to the fact that sqlite3 has a global
301
+ /// config this may conflict with other sqlite3 connections in the same process.
302
+ ///
303
+ /// Using this setting is very UNSAFE and you are expected to use the libsql in adherence
304
+ /// with the sqlite3 threadsafe rules or else you WILL create undefined behavior. Use at
305
+ /// your own risk.
306
+ pub unsafe fn skip_saftey_assert( mut self , skip: bool ) -> Builder <RemoteReplica > {
307
+ self . inner. skip_safety_assert = skip;
308
+ self
309
+ }
310
+
273
311
/// Build the remote embedded replica database.
274
312
pub async fn build( self ) -> Result <Database > {
275
313
let RemoteReplica {
@@ -285,7 +323,8 @@ cfg_replication! {
285
323
read_your_writes,
286
324
sync_interval,
287
325
http_request_callback,
288
- namespace
326
+ namespace,
327
+ skip_safety_assert
289
328
} = self . inner;
290
329
291
330
let connector = if let Some ( connector) = connector {
@@ -303,19 +342,41 @@ cfg_replication! {
303
342
304
343
let path = path. to_str( ) . ok_or( crate :: Error :: InvalidUTF8Path ) ?. to_owned( ) ;
305
344
306
- let db = crate :: local:: Database :: open_http_sync_internal(
307
- connector,
308
- path,
309
- url,
310
- auth_token,
311
- version,
312
- read_your_writes,
313
- encryption_config. clone( ) ,
314
- sync_interval,
315
- http_request_callback,
316
- namespace,
317
- )
318
- . await ?;
345
+ let db = if !skip_safety_assert {
346
+ crate :: local:: Database :: open_http_sync_internal(
347
+ connector,
348
+ path,
349
+ url,
350
+ auth_token,
351
+ version,
352
+ read_your_writes,
353
+ encryption_config. clone( ) ,
354
+ sync_interval,
355
+ http_request_callback,
356
+ namespace,
357
+ )
358
+ . await ?
359
+ } else {
360
+ // SAFETY: this can only be enabled via the unsafe config function
361
+ // `skip_safety_assert`.
362
+ unsafe {
363
+ crate :: local:: Database :: open_http_sync_internal2(
364
+ connector,
365
+ path,
366
+ url,
367
+ auth_token,
368
+ version,
369
+ read_your_writes,
370
+ encryption_config. clone( ) ,
371
+ sync_interval,
372
+ http_request_callback,
373
+ namespace,
374
+ )
375
+ . await ?
376
+ }
377
+
378
+ } ;
379
+
319
380
320
381
Ok ( Database {
321
382
db_type: DbType :: Sync { db, encryption_config } ,
0 commit comments