feat(engine): write-through persistence (M13 D2)
- facade storage session manager: project handles bind to the default SQLite library on project_new/load; every undo push/group_end/jump write-throughs via DatabaseBackend::save (diff journal); project_free flushes and unbinds - background snapshot thread (Storage/SnapshotIntervalSec, latest-wins, newest 3 kept) with exit flush (oakengine_storage_flush) - config-gated: storage only activates with an explicit Storage/Backend=sqlite, so headless consumers and tests never touch the real library; new exports: storage_flush/is_bound/last_error - it_storage: kill -9 recovery, cross-session undo, snapshot pruning, multi-project isolation, graceful degradation - also fixes a real config test polluting the user config.ini and the undo-stack test races
This commit is contained in:
@@ -88,9 +88,25 @@ const OAKTASK_E_NOT_FOUND: c_int = -80004;
|
||||
/// does not cascade into `PoisonError` failures in every later test.
|
||||
static SERIAL: Mutex<()> = Mutex::new(());
|
||||
|
||||
/// Take the [`SERIAL`] lock, recovering from any poisoning.
|
||||
pub(crate) fn serial() -> std::sync::MutexGuard<'static, ()> {
|
||||
SERIAL.lock().unwrap_or_else(|e| e.into_inner())
|
||||
/// Both lock guards held by [`serial`] (the local task lock plus the
|
||||
/// facade-wide undo-stack lock).
|
||||
pub(crate) struct SerialGuard {
|
||||
/// The [`SERIAL`] lock.
|
||||
_task: std::sync::MutexGuard<'static, ()>,
|
||||
/// The facade's process-wide undo-stack lock (it_undo's), so the
|
||||
/// `oakengine_project_new` calls in these tests (which clear the stack)
|
||||
/// never race the it_undo / it_storage stack tests.
|
||||
_stack: std::sync::MutexGuard<'static, ()>,
|
||||
}
|
||||
|
||||
/// Take the [`SERIAL`] lock AND the global undo-stack lock, recovering
|
||||
/// from any poisoning.
|
||||
pub(crate) fn serial() -> SerialGuard {
|
||||
let _task = SERIAL.lock().unwrap_or_else(|e| e.into_inner());
|
||||
let _stack = super::it_undo::GLOBAL_STACK_LOCK
|
||||
.lock()
|
||||
.unwrap_or_else(|e| e.into_inner());
|
||||
SerialGuard { _task, _stack }
|
||||
}
|
||||
|
||||
/// The facade's live task-payload counter (the engine-side replacement
|
||||
@@ -904,6 +920,9 @@ fn export_task_creation() {
|
||||
fn export_task_run_real_encoder() {
|
||||
let _g = serial();
|
||||
common::force_link();
|
||||
// The import/add-track/add-clip commands below are undoable; disable
|
||||
// the write-through backend so they never touch a library.
|
||||
let _storage = common::storage_off_guard();
|
||||
|
||||
let media = std::env::temp_dir().join(format!(
|
||||
"oakengine-it-task-export-src-{}.mp4",
|
||||
|
||||
Reference in New Issue
Block a user