cfx_storage/impls/storage_db/
sqlite.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5pub const SQLITE_NO_PARAM: &[SqlBindableRef] = &[];
6pub type SqlBindableRef<'a> = &'a (dyn SqlBindable + 'a);
7pub type SqlBindableBox<'a> = Box<dyn SqlBindable + 'a>;
8
9pub struct SqliteConnection {
10    info: SqliteConnectionInfo,
11    connection: Mutex<Connection>,
12    cached_statements: Mutex<StatementCache>,
13}
14
15impl MallocSizeOf for SqliteConnection {
16    fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { unimplemented!() }
17}
18
19pub struct SqliteConnectionInfo {
20    pub readonly: bool,
21    pub path: PathBuf,
22    pub open_flags: OpenFlags,
23}
24
25type StatementCache = HashMap<String, ScopedStatement>;
26
27impl Drop for SqliteConnection {
28    fn drop(&mut self) {
29        // Clear all associated statement otherwise the sqlite connection will
30        // be left open because sqlite3_close returns BUSY.
31        // https://www.sqlite.org/c3ref/close.html
32        self.cached_statements.get_mut().clear();
33        // We would like to check return value of sqlite close, and run close_v2
34        // when necessary. After that we'd like to prevent Connection's drop
35        // from running. To do so we open a new Connection and overwrite
36        // self.connection.
37        //
38        // When we can't open a new connection successfully, give up and simply
39        // let Connection close the db. However we lose the ability to
40        // run close_v2() if close fails.
41        unsafe {
42            if let Ok(new_connection) = Connection::open_with_flags(
43                self.info.path.clone(),
44                Self::default_open_flags().set_read_write(),
45            ) {
46                self.connection.get_mut().remove_busy_handler().ok();
47                if self.close().is_err() {
48                    error!(
49                        "Closing sqlite connection while still being used.
50                         The sqlite connection will be closed when all pending
51                         resources are released. However it suggests that the
52                         code may not managing object ownership and lifetime
53                         of sqlite execution well."
54                    );
55                    self.close_v2().ok();
56                }
57
58                std::ptr::write(self.connection.get_mut(), new_connection);
59            }
60        }
61    }
62}
63
64unsafe impl Send for SqliteConnection {}
65unsafe impl Sync for SqliteConnection {}
66
67impl SqliteConnection {
68    pub fn close(&mut self) -> Result<()> {
69        match unsafe { sqlite_ffi::sqlite3_close(self.get_db_mut().as_raw()) } {
70            sqlite_ffi::SQLITE_OK => Ok(()),
71            code => bail!(sqlite::Error {
72                code: Some(code as isize),
73                message: None
74            }),
75        }
76    }
77
78    pub fn close_v2(&mut self) -> Result<()> {
79        match unsafe {
80            sqlite_ffi::sqlite3_close_v2(self.get_db_mut().as_raw())
81        } {
82            sqlite_ffi::SQLITE_OK => Ok(()),
83            code => bail!(sqlite::Error {
84                code: Some(code as isize),
85                message: None
86            }),
87        }
88    }
89
90    pub fn default_open_flags() -> OpenFlags {
91        // The sqlite library didn't provide a function to construct customary
92        // open_flags.
93        unsafe {
94            std::mem::transmute::<i32, OpenFlags>(
95                sqlite_ffi::SQLITE_OPEN_NOMUTEX
96                    // TODO: check if SHARED_CACHE improves the performance or not.
97                    | sqlite_ffi::SQLITE_OPEN_SHAREDCACHE
98                    | sqlite_ffi::SQLITE_OPEN_URI,
99            )
100        }
101    }
102
103    /// If `unsafe_mode` is true, data loss or database corruption may happen if
104    /// the process crashes, so it should only be used for write-once
105    /// databases where an unfinished temporary database will be removed
106    /// after process restart.
107    pub fn create_and_init<P: AsRef<Path>>(
108        path: P, unsafe_mode: bool,
109    ) -> Result<()> {
110        let conn = Connection::open_with_flags(
111            &path,
112            Self::default_open_flags().set_read_write().set_create(),
113        )?;
114        if unsafe_mode {
115            conn.execute("PRAGMA journal_mode=OFF")?;
116            conn.execute("PRAGMA synchronous=OFF")?;
117        } else {
118            conn.execute("PRAGMA journal_mode=WAL")?;
119        }
120        // Prevent other processes from accessing the db.
121        // The "-shm" file will not be created,
122        // see https://www.sqlite.org/tempfiles.html#shared_memory_files.
123        conn.execute("PRAGMA locking_mode=EXCLUSIVE")?;
124        Ok(())
125    }
126
127    pub fn create_and_open<P: AsRef<Path>>(
128        path: P, open_flags: OpenFlags, unsafe_mode: bool,
129    ) -> Result<Self> {
130        Self::create_and_init(path.as_ref(), unsafe_mode)?;
131        Self::open(path, false, open_flags)
132    }
133
134    pub fn open<P: AsRef<Path>>(
135        path: P, readonly: bool, open_flags: OpenFlags,
136    ) -> Result<Self> {
137        let conn_open_flags = if readonly {
138            open_flags.set_read_only()
139        } else {
140            open_flags.set_read_write()
141        };
142
143        Ok(Self {
144            info: SqliteConnectionInfo {
145                readonly,
146                path: path.as_ref().to_path_buf(),
147                open_flags,
148            },
149            connection: Mutex::new(Connection::open_with_flags(
150                path,
151                conn_open_flags,
152            )?),
153            cached_statements: Mutex::new(HashMap::new()),
154        })
155    }
156
157    pub fn try_clone(&self) -> Result<Self> {
158        Self::open(&self.info.path, self.info.readonly, self.info.open_flags)
159    }
160
161    pub fn prepare<'db>(
162        db: &'db mut Connection, statement_cache: &'db mut StatementCache,
163        sql: &str,
164    ) -> Result<&'db mut ScopedStatement> {
165        // Actually safe. I don't want an unnecessary to_string() for the sql.
166        // But the borrow-checker doesn't seem to understand branch very well.
167        Ok(unsafe {
168            let maybe_statement = statement_cache
169                .get_mut(sql)
170                .map(|x| x as *mut ScopedStatement);
171            if maybe_statement.is_some() {
172                &mut *maybe_statement.unwrap()
173            } else {
174                statement_cache.entry(sql.to_string()).or_insert(
175                    // This is safe because we store the
176                    // ScopedStatement in the same struct where the
177                    // connection is.
178                    ScopedStatement::new(db.prepare(sql)?),
179                )
180            }
181        })
182    }
183
184    /// The statement must be created with the db. Then the statement is a mut
185    /// borrow of db, so it's guaranteed that the db is only used by one
186    /// thread.
187    pub fn execute_locked<'db, 'p, Param: Borrow<dyn SqlBindable + 'p>>(
188        statement: &'db mut ScopedStatement, params: &[Param],
189    ) -> Result<MaybeRows<'db>> {
190        Ok(MaybeRows(statement.execute(params)?))
191    }
192
193    pub fn execute<'p, Param: Borrow<dyn SqlBindable + 'p>>(
194        &mut self, sql: &str, params: &[Param],
195    ) -> Result<MaybeRows<'_>> {
196        let db = self.connection.get_mut();
197        let statement =
198            Self::prepare(db, self.cached_statements.get_mut(), sql)?;
199
200        Self::execute_locked(statement, params)
201    }
202
203    pub fn get_db_mut(&mut self) -> &mut Connection {
204        self.connection.get_mut()
205    }
206
207    pub fn lock_db(&self) -> MutexGuard<'_, Connection> {
208        self.connection.lock()
209    }
210
211    pub fn lock_statement_cache(&self) -> MutexGuard<'_, StatementCache> {
212        self.cached_statements.lock()
213    }
214
215    pub fn possible_temporary_files(db_path: &str) -> Vec<String> {
216        let mut paths = vec![];
217        paths.push(Self::wal_path(db_path));
218        paths.push(Self::shm_path(db_path));
219
220        paths
221    }
222
223    fn wal_path(db_path: &str) -> String { db_path.to_string() + "-wal" }
224
225    fn shm_path(db_path: &str) -> String { db_path.to_string() + "-shm" }
226}
227
228/// Upstream didn't implement Bindable for trait object, which makes passing
229/// an array of params impossible. Therefore we define a new trait and implement
230/// Bindable for its trait object.
231pub trait SqlBindable {
232    fn bind(&self, statement: &mut Statement, i: usize) -> sqlite::Result<()>;
233}
234
235/// To implement SqlBindable for String, Vec<[u8]>, etc, whichever is Deref to a
236/// Bindable.
237pub trait SqlDerefBindable<'a> {
238    type Type: Bindable;
239
240    fn as_bindable(&'a self) -> Self::Type;
241}
242
243impl<'a, T: ?Sized + 'a + Deref> SqlDerefBindable<'a> for T
244where &'a T::Target: Bindable
245{
246    type Type = &'a T::Target;
247
248    fn as_bindable(&'a self) -> Self::Type { self.deref() }
249}
250
251impl SqlBindable for i64 {
252    fn bind(&self, statement: &mut Statement, i: usize) -> sqlite::Result<()> {
253        Bindable::bind(*self as i64, statement, i)
254    }
255}
256
257impl<'a, T: 'a + Deref> SqlBindable for Pin<T>
258where for<'x> &'x T::Target: Bindable
259{
260    fn bind(&self, statement: &mut Statement, i: usize) -> sqlite::Result<()> {
261        Bindable::bind(&**self, statement, i)
262    }
263}
264
265impl<'a, T: 'a + ?Sized> SqlBindable for &'a T
266where T: SqlDerefBindable<'a>
267{
268    fn bind(&self, statement: &mut Statement, i: usize) -> sqlite::Result<()> {
269        Bindable::bind(self.as_bindable(), statement, i)
270    }
271}
272
273pub trait SqlReadable: SqlReadableIntoSelf + Sized {
274    fn from_column(row: &Statement<'_>, column: usize) -> Result<Self>;
275}
276
277impl SqlReadable for Vec<u8> {
278    fn from_column(row: &Statement<'_>, column: usize) -> Result<Self> {
279        Ok(Self::read(row, column)?)
280    }
281}
282
283impl SqlReadable for Box<[u8]> {
284    fn from_column(row: &Statement<'_>, column: usize) -> Result<Self> {
285        Ok(Vec::<u8>::read(row, column)?.into_boxed_slice())
286    }
287}
288
289impl SqlReadable for i64 {
290    fn from_column(row: &Statement<'_>, column: usize) -> Result<Self> {
291        Ok(i64::read(row, column)?)
292    }
293}
294
295/// This trait can be made into trait object.
296pub trait SqlReadableIntoSelf {
297    fn read_into_self(
298        &mut self, row: &Statement<'_>, column: usize,
299    ) -> Result<()>;
300}
301
302impl<T: SqlReadable> SqlReadableIntoSelf for T {
303    fn read_into_self(
304        &mut self, row: &Statement<'_>, column: usize,
305    ) -> Result<()> {
306        Ok(*self = Self::from_column(row, column)?)
307    }
308}
309
310impl<'a> Bindable for &'a dyn SqlBindable {
311    fn bind(self, statement: &mut Statement, i: usize) -> sqlite::Result<()> {
312        self.bind(statement, i)
313    }
314}
315
316type MaybeUnfinishedStatement<'db> = Option<&'db mut Statement<'db>>;
317
318#[derive(Default)]
319pub struct MaybeRows<'db>(MaybeUnfinishedStatement<'db>);
320
321impl<'db> MaybeRows<'db> {
322    pub fn finish_ignore_rows(&mut self) -> Result<()> {
323        while Self::next(&mut self.0)?.is_some() {}
324        Ok(())
325    }
326
327    pub fn map<Item, F: FnMut(&Statement<'db>) -> Item>(
328        mut self, f: F,
329    ) -> MappedRows<'db, F> {
330        MappedRows {
331            maybe_rows: self.0.take(),
332            f,
333        }
334    }
335
336    pub fn statement_ref<'a>(
337        maybe_statement: &'a mut MaybeUnfinishedStatement<'db>,
338    ) -> &'a Statement<'db> {
339        maybe_statement.as_ref().unwrap()
340    }
341
342    pub fn next<'a>(
343        maybe_statement: &'a mut MaybeUnfinishedStatement<'db>,
344    ) -> Result<Option<&'a Statement<'db>>> {
345        let state = match maybe_statement {
346            None => return Ok(None),
347            Some(statement) => statement.next()?,
348        };
349
350        match state {
351            State::Row => Ok(Some(Self::statement_ref(maybe_statement))),
352            State::Done => {
353                *maybe_statement = None;
354                Ok(None)
355            }
356        }
357    }
358}
359
360#[allow(dead_code)]
361pub struct ConnectionWithRowParser<Connection, RowParser>(
362    pub Connection,
363    pub RowParser,
364);
365
366pub struct MappedRows<'db, F> {
367    /// If Rows is default constructible, we could remove the option and
368    /// default construct it for the empty database.
369    maybe_rows: MaybeUnfinishedStatement<'db>,
370    f: F,
371}
372
373impl<'db, Item, F: FnMut(&Statement<'db>) -> Item> MappedRows<'db, F> {
374    pub fn expect_one_row(&mut self) -> Result<Option<Item>> {
375        if self.maybe_rows.is_none() {
376            Ok(None)
377        } else {
378            let row_mapped =
379                (self.f)(MaybeRows::statement_ref(&mut self.maybe_rows));
380            if MaybeRows::next(&mut self.maybe_rows)?.is_none() {
381                Ok(Some(row_mapped))
382            } else {
383                bail!(Error::DbValueError)
384            }
385        }
386    }
387}
388
389impl<'db, Item, F: FnMut(&Statement<'db>) -> Result<Item>> FallibleIterator
390    for MappedRows<'db, F>
391{
392    type Error = Error;
393    type Item = Item;
394
395    fn next(&mut self) -> Result<Option<Self::Item>> {
396        if self.maybe_rows.is_none() {
397            Ok(None)
398        } else {
399            let value =
400                (self.f)(MaybeRows::statement_ref(&mut self.maybe_rows))?;
401            MaybeRows::next(&mut self.maybe_rows)?;
402            Ok(Some(value))
403        }
404    }
405}
406
407/// The ScopedStatement struct is a wrapper solely meant to store
408/// cached statement object together with the connection because it's
409/// otherwise too painful for the user to maintain especially in multi-threaded
410/// environment.
411///
412/// The ScopedStatement should only be stored in the struct where the
413/// corresponding sqlite Connection is.
414///
415/// The ScopedStatement should in general not be extended. Any more code added
416/// should examined carefully so that the database connection can not be used in
417/// more than one thread at the same time.
418pub struct ScopedStatement {
419    stmt: Statement<'static>,
420}
421
422impl ScopedStatement {
423    /// This method is unsafe because it extended the lifetime of Statement to
424    /// infinity.
425    unsafe fn new<'a>(scoped_statement: Statement<'a>) -> Self {
426        Self {
427            stmt: std::mem::transmute::<Statement<'a>, Statement<'static>>(
428                scoped_statement,
429            ),
430        }
431    }
432
433    fn as_mut(&mut self) -> &mut Statement<'_> {
434        unsafe {
435            std::mem::transmute::<&mut Statement<'static>, &mut Statement<'_>>(
436                &mut self.stmt,
437            )
438        }
439    }
440
441    /// It is essential to have `&mut self` in order to execute. As required by
442    /// sqlite "Multi-thread mode" https://sqlite.org/threadsafe.html, there can
443    /// be only one active use of a database connection.
444    ///
445    /// Even binding an variable modifies the error field in database
446    /// connection.
447    ///
448    /// We should never allow a mutable Statement returned from a
449    /// SqliteConnection reference because then we can not prevent using
450    /// database connection from multiple threads.
451    fn bind<'p, Param: Borrow<dyn SqlBindable + 'p>>(
452        &mut self, params: &[Param],
453    ) -> Result<()> {
454        self.stmt.reset().ok();
455        for i in 0..params.len() {
456            // Sqlite index starts at 1.
457            self.stmt.bind(i + 1, params[i].borrow())?
458        }
459        Ok(())
460    }
461
462    fn execute<'p, Param: Borrow<dyn SqlBindable + 'p>>(
463        &mut self, params: &[Param],
464    ) -> Result<MaybeUnfinishedStatement<'_>> {
465        self.bind(params)?;
466
467        // FIXME: Should we wait for the first row to become available?
468        let result = self.stmt.next();
469        match result {
470            Ok(State::Done) => Ok(None),
471            Ok(State::Row) => Ok(Some(self.as_mut())),
472            Err(e) => {
473                bail!(e);
474            }
475        }
476    }
477}
478
479pub trait ValueReadImpl<Kind: ?Sized>: Sized {
480    fn from_row_impl(row: &Statement<'_>, value_column: usize) -> Result<Self>;
481    fn from_kv_row_impl(
482        row: &Statement<'_>, key: &mut dyn SqlReadableIntoSelf,
483    ) -> Result<Self>;
484}
485
486pub trait ValueRead {
487    type Kind: ?Sized;
488}
489
490impl ValueRead for () {
491    type Kind = ();
492}
493
494impl ValueRead for Box<[u8]> {
495    type Kind = dyn SqlReadableIntoSelf;
496}
497
498impl ValueReadImpl<()> for () {
499    fn from_row_impl(
500        _row: &Statement<'_>, _value_column: usize,
501    ) -> Result<Self> {
502        Ok(())
503    }
504
505    fn from_kv_row_impl(
506        row: &Statement<'_>, key: &mut dyn SqlReadableIntoSelf,
507    ) -> Result<Self> {
508        key.read_into_self(row, 0)?;
509        Ok(())
510    }
511}
512
513impl<ValueType: SqlReadable> ValueReadImpl<dyn SqlReadableIntoSelf>
514    for ValueType
515{
516    fn from_row_impl(row: &Statement<'_>, value_column: usize) -> Result<Self> {
517        ValueType::from_column(row, value_column)
518    }
519
520    fn from_kv_row_impl(
521        row: &Statement<'_>, key: &mut dyn SqlReadableIntoSelf,
522    ) -> Result<Self> {
523        key.read_into_self(row, 0)?;
524        ValueType::from_column(row, 1)
525    }
526}
527
528impl<
529        ValueType: Default + TupleIndexExt + TupleIterate<dyn SqlReadableIntoSelf>,
530    > ValueRead for ValueType
531{
532    type Kind = dyn ElementSatisfy<dyn SqlReadableIntoSelf>;
533}
534
535impl<
536        ValueType: Default + TupleIndexExt + TupleIterate<dyn SqlReadableIntoSelf>,
537    > ValueReadImpl<dyn ElementSatisfy<dyn SqlReadableIntoSelf>> for ValueType
538{
539    fn from_row_impl(
540        row: &Statement<'_>, value_column: usize,
541    ) -> Result<ValueType> {
542        let mut result = Ok(ValueType::default());
543
544        struct Load<'r, 'db, ValueType> {
545            t: &'r mut ValueType,
546            row: &'r Statement<'db>,
547            error: Option<Error>,
548            value_column: usize,
549        }
550
551        impl<ValueType: TupleIndexExt>
552            IterCallFamilyTrait<ValueType, dyn SqlReadableIntoSelf>
553            for &mut Load<'_, '_, ValueType>
554        {
555            fn iter_step<
556                Index: OfElementSatisfiesOnTuple<ValueType, dyn SqlReadableIntoSelf>,
557            >(
558                &mut self, _: &'static Index, index: usize,
559            ) {
560                match self.error {
561                    None => {
562                        let column_read_result = ElementSatisfy::<
563                            dyn SqlReadableIntoSelf,
564                        >::to_constrain_object_mut(
565                            Index::getter_for_tuple_mut(self.t).get_mut_impl(),
566                        )
567                        .read_into_self(self.row, index + self.value_column);
568
569                        if column_read_result.is_err() {
570                            self.error = column_read_result.err()
571                        }
572                    }
573                    _ => { /* Skip */ }
574                }
575            }
576        }
577
578        let mut loader = Load {
579            t: result.as_mut().unwrap(),
580            row,
581            error: None,
582            value_column,
583        };
584        ValueType::iterate(&mut loader);
585
586        match loader.error {
587            Some(e) => bail!(e),
588            None => result,
589        }
590    }
591
592    fn from_kv_row_impl(
593        row: &Statement<'_>, key: &mut dyn SqlReadableIntoSelf,
594    ) -> Result<Self> {
595        key.read_into_self(row, 0)?;
596        Self::from_row_impl(row, 1)
597    }
598}
599
600pub trait SqlBindableValue {
601    type Kind: ?Sized;
602}
603
604impl SqlBindableValue for () {
605    type Kind = ();
606}
607
608impl SqlBindableValue for [u8] {
609    /// Use SqlBindable for all single element.
610    type Kind = dyn SqlBindable;
611}
612
613impl SqlBindableValue for i64 {
614    type Kind = dyn SqlBindable;
615}
616
617impl<
618        ValueType: Default + TupleIndexExt + TupleIterate<dyn SqlReadableIntoSelf>,
619    > SqlBindableValue for ValueType
620{
621    type Kind = dyn ElementSatisfy<dyn BindValueAppendImpl<dyn SqlBindable>>;
622}
623
624impl<
625        ValueType: Default + TupleIndexExt + TupleIterate<dyn SqlReadableIntoSelf>,
626    > DbValueType for ValueType
627{
628    type Type = ValueType;
629}
630
631/// This trait should be implemented for all types implement SqlBindableValue.
632pub trait BindValueAppendImpl<Kind: ?Sized> {
633    fn make_bind_list(&self) -> Vec<SqlBindableBox<'_>>;
634}
635
636// FIXME: Clone? Is it possible to impl it for &T?
637impl<T: 'static + SqlBindableValue + SqlBindable + Clone>
638    BindValueAppendImpl<dyn SqlBindable> for T
639{
640    fn make_bind_list(&self) -> Vec<SqlBindableBox<'_>> {
641        vec![Box::new(self.clone())]
642    }
643}
644
645impl BindValueAppendImpl<()> for () {
646    fn make_bind_list(&self) -> Vec<Box<dyn SqlBindable>> { vec![] }
647}
648
649impl BindValueAppendImpl<dyn SqlBindable> for [u8] {
650    fn make_bind_list(&self) -> Vec<SqlBindableBox<'_>> {
651        vec![Box::new(Pin::new(self))]
652    }
653}
654
655impl BindValueAppendImpl<dyn SqlBindable> for Box<[u8]> {
656    fn make_bind_list(&self) -> Vec<SqlBindableBox<'_>> {
657        vec![Box::new(Pin::new(self.deref()))]
658    }
659}
660
661impl<
662        ValueType: TupleIndexExt + TupleIterate<dyn BindValueAppendImpl<dyn SqlBindable>>,
663    >
664    BindValueAppendImpl<
665        dyn ElementSatisfy<dyn BindValueAppendImpl<dyn SqlBindable>>,
666    > for ValueType
667{
668    fn make_bind_list(&self) -> Vec<SqlBindableBox<'_>> {
669        struct Append<'x, ValueType> {
670            v: &'x ValueType,
671            l: *mut Vec<SqlBindableBox<'x>>,
672        }
673
674        impl<'x, ValueType>
675            IterCallFamilyTrait<
676                ValueType,
677                dyn BindValueAppendImpl<dyn SqlBindable>,
678            > for Append<'x, ValueType>
679        {
680            // FIXME: we shoull note that, if Self contains a mut pointer of
681            // FIXME: a Tuple, then iter_step can only return a
682            // FIXME: contrain object of the current lifetime.
683            // FIXME: we must find a way to make it possible to get an
684            // FIXME: constrain_object from the same lifetime.
685            fn iter_step<
686                Index: OfElementSatisfiesOnTuple<
687                    ValueType,
688                    dyn BindValueAppendImpl<dyn SqlBindable>,
689                >,
690            >(
691                &mut self, _: &'static Index, _: usize,
692            ) {
693                let mut to_append = ElementSatisfy::<
694                    dyn BindValueAppendImpl<dyn SqlBindable>,
695                >::to_constrain_object(
696                    Index::getter_for_tuple(self.v).get_impl(),
697                )
698                .make_bind_list();
699                unsafe { &mut *self.l }.append(&mut to_append);
700            }
701        }
702
703        let mut bind_list =
704            Vec::<SqlBindableBox<'_>>::with_capacity(ValueType::size_tuple());
705        {
706            let append = Append {
707                v: self,
708                l: &mut bind_list,
709            };
710            ValueType::iterate(append);
711        }
712
713        bind_list
714    }
715}
716
717use super::super::{
718    super::{storage_db::key_value_db::DbValueType, utils::tuple::*},
719    errors::*,
720};
721use fallible_iterator::FallibleIterator;
722use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
723use parking_lot::{Mutex, MutexGuard};
724use sqlite::{Bindable, Connection, OpenFlags, Readable, State, Statement};
725use sqlite3_sys as sqlite_ffi;
726use std::{
727    borrow::Borrow,
728    collections::HashMap,
729    ops::Deref,
730    path::{Path, PathBuf},
731    pin::Pin,
732};