mj_controller/
database.rs1pub use mj_core::storage::*;
2use std::collections::{BTreeMap, BTreeSet, HashSet};
5use std::fs;
6use std::path::{Path, PathBuf};
7use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
8use std::sync::mpsc::{Receiver, SyncSender, sync_channel};
9use std::sync::{Arc, Mutex, OnceLock, PoisonError};
10use std::thread::{self, JoinHandle};
11use std::time::Duration;
12
13use anyhow::{Context, Result, bail, ensure};
14use chrono::Utc;
15use rusqlite::types::Type;
16use rusqlite::{Connection, OptionalExtension, Transaction, params};
17
18use mj_core::config::data_dir;
19use mj_core::state::{
20 CheckpointMetadata, HostContainerSize, ManagedWorktree, MaterializedExecutionState,
21 MaterializedQueuedPrompt, MaterializedSession, MaterializedSessionSummary, MaterializedTurn,
22 MaterializedTurnOutcome, ProjectionWindow, SessionRecord, SessionResourceAllocation,
23 SessionState, State, TargetLocator, TranscriptBody, TranscriptItem,
24 validate_relay_event_digest, validate_relay_event_frontier,
25};
26use mj_core::subagent::SubagentRecord;
27
28use crate::targets::{AdditionalMount, MountAccess};
29use mj_core::workspace::{
30 ConversationLayout, DEFAULT_WORKSPACE_ID, DetachedDraft, PaneSize, PaneSizes, WorkspaceRecord,
31 new_workspace_id, normalize_workspace_name,
32};
33
34const SCHEMA_VERSION: i64 = 74;
35
36mod session_move;
37pub use session_move::*;
38mod session_restart;
39pub(crate) use session_restart::*;
40
41mod legacy_schema;
42mod schema;
43mod usage;
44pub use usage::*;
45mod events;
46pub use events::*;
47
48#[cfg(test)]
49use schema::forget_verified_schema;
50pub use schema::{check_read_compatibility, database_path};
51use schema::{open, open_reader};
52
53mod writer;
54pub use writer::*;
55mod committed;
56pub use committed::{CommittedState, CommittedTurn};
57mod workspaces;
58pub use workspaces::*;
59mod client_state;
60pub use client_state::*;
61mod state_io;
62pub use state_io::*;
63mod sessions;
64pub use sessions::*;
65mod native_agents;
66pub use native_agents::*;
67mod materialized;
68pub use materialized::*;
69mod mounts;
70pub use mounts::*;
71mod reviews;
72pub use reviews::*;
73mod startup;
74pub(crate) use startup::*;
75mod delegation;
76pub(crate) use delegation::*;
77mod worker_restart;
78pub(crate) use worker_restart::*;
79mod prompts;
80pub use prompts::*;
81mod values;
82use values::*;
83mod profile_cache;
84pub use profile_cache::*;
85mod projects;
86pub(crate) use projects::*;
87
88#[cfg(test)]
89mod tests;
90#[cfg(test)]
91pub(crate) fn test_session(id: &str, bundle: &str) -> SessionRecord {
92 tests::session(id, bundle)
93}
94
95mod quota_cache;
96pub(crate) use quota_cache::*;
97
98pub(crate) fn is_busy_error(error: &anyhow::Error) -> bool {
101 error.chain().any(|cause| {
102 matches!(
103 cause.downcast_ref::<rusqlite::Error>(),
104 Some(rusqlite::Error::SqliteFailure(failure, _))
105 if matches!(
106 failure.code,
107 rusqlite::ErrorCode::DatabaseBusy | rusqlite::ErrorCode::DatabaseLocked
108 )
109 )
110 })
111}