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::{get_dependency, 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        get_dependency!(
66            self.sqlite_connection = Arc::new(self.build_sqlite_connection(
67                SQLITE_FILE,
68                crate::database::migration::get_migrations(),
69            )?)
70        )
71    }
72    /// Get EventStore SQLite connection
73    pub async fn get_event_store_sqlite_connection(&mut self) -> Result<Arc<SqliteConnection>> {
74        get_dependency!(
75            self.sqlite_connection_event_store = Arc::new(self.build_sqlite_connection(
76                SQLITE_MONITORING_FILE,
77                crate::event_store::database::migration::get_migrations(),
78            )?)
79        )
80    }
81
82    async fn build_sqlite_connection_cardano_transaction_pool(
83        &mut self,
84    ) -> Result<Arc<SqliteConnectionPool>> {
85        let connection_pool_size = self
86            .configuration
87            .cardano_transactions_database_connection_pool_size();
88        // little hack to apply migrations to the cardano transaction database
89        // todo: add capacity to create a connection pool to the `ConnectionBuilder`
90        let _connection = self.build_sqlite_connection(
91            SQLITE_FILE_CARDANO_TRANSACTION,
92            mithril_persistence::database::cardano_transaction_migration::get_migrations(),
93            // Don't vacuum the Cardano transactions database as it can be very large
94        )?;
95
96        let connection_pool = Arc::new(SqliteConnectionPool::build(connection_pool_size, || {
97            self.build_sqlite_connection(SQLITE_FILE_CARDANO_TRANSACTION, vec![])
98                .with_context(|| {
99                    "Dependencies Builder can not build SQLite connection for Cardano transactions"
100                })
101        })?);
102
103        Ok(connection_pool)
104    }
105
106    /// Get SQLite connection pool for the cardano transactions store
107    pub async fn get_sqlite_connection_cardano_transaction_pool(
108        &mut self,
109    ) -> Result<Arc<SqliteConnectionPool>> {
110        get_dependency!(self.sqlite_connection_cardano_transaction_pool)
111    }
112}