khive_db/backend/
code_map.rs1use std::path::Path;
4use std::sync::atomic::AtomicUsize;
5use std::sync::Arc;
6
7use super::{StorageBackend, StoreSchemaGate};
8use crate::error::SqliteError;
9use crate::pool::{ConnectionPool, PoolConfig};
10use crate::stores::blob::DatabaseGcOwnerGuard;
11
12impl StorageBackend {
13 pub fn sqlite_code_map(
20 path: impl AsRef<Path>,
21 protected_main: &[std::path::PathBuf],
22 protected_events: &[std::path::PathBuf],
23 ) -> Result<Self, SqliteError> {
24 let policy = crate::migrations::MigrationWritePolicy::from_environment()?;
25 Self::sqlite_code_map_with_policies(
26 path,
27 protected_main,
28 protected_events,
29 policy.disk_guard_config(),
30 policy.volume_lock_dir().to_path_buf(),
31 )
32 }
33
34 pub fn sqlite_code_map_with_policies(
37 path: impl AsRef<Path>,
38 protected_main: &[std::path::PathBuf],
39 protected_events: &[std::path::PathBuf],
40 disk_guard_config: crate::EffectiveDiskGuardConfig,
41 volume_lock_dir: std::path::PathBuf,
42 ) -> Result<Self, SqliteError> {
43 let policy =
44 crate::migrations::MigrationWritePolicy::new(disk_guard_config, volume_lock_dir)?;
45 crate::extension::ensure_extensions_loaded();
46 let resolved = path.as_ref().to_path_buf();
47 let protected: Vec<_> = protected_main
48 .iter()
49 .map(|path| crate::code_map_vfs::ProductionBase {
50 path: path.clone(),
51 kind: crate::code_map_vfs::ProductionKind::Main,
52 })
53 .chain(
54 protected_events
55 .iter()
56 .map(|path| crate::code_map_vfs::ProductionBase {
57 path: path.clone(),
58 kind: crate::code_map_vfs::ProductionKind::Events,
59 }),
60 )
61 .collect();
62 crate::code_map_vfs::prepare_rollback_target(resolved.clone(), protected.clone()).map_err(
63 |error| {
64 let detail = if error.is_busy() {
65 format!("{error}; retry after other SQLite clients release the target")
66 } else {
67 error.to_string()
68 };
69 SqliteError::InvalidData(detail)
70 },
71 )?;
72 let vfs_name = crate::code_map_vfs::register_rollback(resolved.clone(), protected)
73 .map_err(|error| SqliteError::InvalidData(error.to_string()))?;
74 let pool = ConnectionPool::new(PoolConfig {
75 path: Some(resolved.clone()),
76 code_map_vfs: Some(vfs_name),
77 wal_mode: false,
78 disk_guard_config: Some(policy.disk_guard_config()),
79 volume_lock_dir: Some(policy.volume_lock_dir().to_path_buf()),
80 ..PoolConfig::default()
81 })?;
82 Ok(Self {
83 pool: Arc::new(pool),
84 is_file_backed: true,
85 path: Some(resolved),
86 vector_tables_ready: Default::default(),
87 notes_seq_repair_runs: AtomicUsize::new(0),
88 store_schemas: std::array::from_fn(|_| Arc::new(StoreSchemaGate::default())),
89 })
90 }
91
92 pub(super) fn run_core_migrations(
95 &self,
96 owner: &DatabaseGcOwnerGuard,
97 ) -> Result<u32, SqliteError> {
98 let admission = self.pool.write_admission();
99 let run = || {
100 crate::migrations::run_migrations_with_database_gc_owner(
101 &mut self.pool.migration_transactions(),
102 owner,
103 &admission,
104 )
105 };
106 match self.pool.config().code_map_vfs.as_deref() {
107 Some(vfs) => crate::code_map_vfs::naming_refusal(vfs, run),
110 None => run(),
111 }
112 }
113}