mithril_aggregator/dependency_injection/builder/support/
sqlite.rs

1use anyhow::Context;
2
3use mithril_persistence::database::{ApplicationNodeType, SqlMigration};
4use mithril_persistence::sqlite::{
5    ConnectionBuilder, ConnectionOptions, SqliteConnection, SqliteConnectionPool,
6};
7use std::sync::Arc;
8
9use crate::dependency_injection::builder::{
10    SQLITE_FILE, SQLITE_FILE_CARDANO_TRANSACTION, SQLITE_MONITORING_FILE,
11};
12use crate::dependency_injection::{DependenciesBuilder, DependenciesBuilderError, Result};
13use crate::ExecutionEnvironment;
14
15impl DependenciesBuilder {
16    fn build_sqlite_connection(
17        &self,
18        sqlite_file_name: &str,
19        migrations: Vec<SqlMigration>,
20    ) -> Result<SqliteConnection> {
21        let logger = self.root_logger();
22        let connection_builder = match self.configuration.environment {
23            ExecutionEnvironment::Test
24                if self.configuration.data_stores_directory.to_string_lossy() == ":memory:" =>
25            {
26                ConnectionBuilder::open_memory()
27            }
28            _ => ConnectionBuilder::open_file(
29                &self.configuration.get_sqlite_dir().join(sqlite_file_name),
30            ),
31        };
32
33        let connection = connection_builder
34            .with_node_type(ApplicationNodeType::Aggregator)
35            .with_options(&[
36                ConnectionOptions::EnableForeignKeys,
37                ConnectionOptions::EnableWriteAheadLog,
38            ])
39            .with_logger(logger.clone())
40            .with_migrations(migrations)
41            .build()
42            .map_err(|e| DependenciesBuilderError::Initialization {
43                message: "SQLite initialization: failed to build connection.".to_string(),
44                error: Some(e),
45            })?;
46
47        Ok(connection)
48    }
49
50    /// Execute cleanup operations on SQLite connections
51    pub async fn drop_sqlite_connections(&self) {
52        if let Some(connection) = &self.sqlite_connection {
53            let _ = connection.execute("pragma analysis_limit=400; pragma optimize;");
54        }
55
56        if let Some(pool) = &self.sqlite_connection_cardano_transaction_pool {
57            if let Ok(connection) = pool.connection() {
58                let _ = connection.execute("pragma analysis_limit=400; pragma optimize;");
59            }
60        }
61    }
62
63    /// Get SQLite connection
64    pub async fn get_sqlite_connection(&mut self) -> Result<Arc<SqliteConnection>> {
65        if self.sqlite_connection.is_none() {
66            self.sqlite_connection = Some(Arc::new(self.build_sqlite_connection(
67                SQLITE_FILE,
68                crate::database::migration::get_migrations(),
69            )?));
70        }
71
72        Ok(self.sqlite_connection.as_ref().cloned().unwrap())
73    }
74    /// Get EventStore SQLite connection
75    pub async fn get_event_store_sqlite_connection(&mut self) -> Result<Arc<SqliteConnection>> {
76        if self.sqlite_connection_event_store.is_none() {
77            self.sqlite_connection_event_store = Some(Arc::new(self.build_sqlite_connection(
78                SQLITE_MONITORING_FILE,
79                crate::event_store::database::migration::get_migrations(),
80            )?));
81        }
82
83        Ok(self
84            .sqlite_connection_event_store
85            .as_ref()
86            .cloned()
87            .unwrap())
88    }
89
90    async fn build_sqlite_connection_cardano_transaction_pool(
91        &mut self,
92    ) -> Result<Arc<SqliteConnectionPool>> {
93        let connection_pool_size = self
94            .configuration
95            .cardano_transactions_database_connection_pool_size;
96        // little hack to apply migrations to the cardano transaction database
97        // todo: add capacity to create a connection pool to the `ConnectionBuilder`
98        let _connection = self.build_sqlite_connection(
99            SQLITE_FILE_CARDANO_TRANSACTION,
100            mithril_persistence::database::cardano_transaction_migration::get_migrations(),
101            // Don't vacuum the Cardano transactions database as it can be very large
102        )?;
103
104        let connection_pool = Arc::new(SqliteConnectionPool::build(connection_pool_size, || {
105            self.build_sqlite_connection(SQLITE_FILE_CARDANO_TRANSACTION, vec![])
106                .with_context(|| {
107                    "Dependencies Builder can not build SQLite connection for Cardano transactions"
108                })
109        })?);
110
111        Ok(connection_pool)
112    }
113
114    /// Get SQLite connection pool for the cardano transactions store
115    pub async fn get_sqlite_connection_cardano_transaction_pool(
116        &mut self,
117    ) -> Result<Arc<SqliteConnectionPool>> {
118        if self.sqlite_connection_cardano_transaction_pool.is_none() {
119            self.sqlite_connection_cardano_transaction_pool = Some(
120                self.build_sqlite_connection_cardano_transaction_pool()
121                    .await?,
122            );
123        }
124
125        Ok(self
126            .sqlite_connection_cardano_transaction_pool
127            .as_ref()
128            .cloned()
129            .unwrap())
130    }
131}