diff --git a/pylib/anki/collection.py b/pylib/anki/collection.py index 098b69854..c3113fa9b 100644 --- a/pylib/anki/collection.py +++ b/pylib/anki/collection.py @@ -195,23 +195,17 @@ class Collection: flush = setMod - def modified_after_begin(self) -> bool: + def modified_by_backend(self) -> bool: # Until we can move away from long-running transactions, the Python - # code needs to know if transaction should be committed, so we need + # code needs to know if the transaction should be committed, so we need # to check if the backend updated the modification time. return self.db.last_begin_at != self.mod def save(self, name: Optional[str] = None, trx: bool = True) -> None: "Flush, commit DB, and take out another write lock if trx=True." # commit needed? - if self.db.modified_in_python or self.modified_after_begin(): - if self.db.modified_in_python: - self.db.execute("update col set mod = ?", intTime(1000)) - self.db.modified_in_python = False - else: - # modifications made by the backend will have already bumped - # mtime - pass + if self.db.modified_in_python or self.modified_by_backend(): + self.db.modified_in_python = False self.db.commit() if trx: self.db.begin() diff --git a/rslib/src/backend/dbproxy.rs b/rslib/src/backend/dbproxy.rs index 49207d334..d6d2b6f41 100644 --- a/rslib/src/backend/dbproxy.rs +++ b/rslib/src/backend/dbproxy.rs @@ -75,7 +75,7 @@ pub(super) fn db_command_bytes(col: &mut Collection, input: &[u8]) -> Result { - maybe_clear_undo(col, &sql); + update_state_after_modification(col, &sql); if first_row_only { db_query_row(&col.storage, &sql, &args)? } else { @@ -87,6 +87,10 @@ pub(super) fn db_command_bytes(col: &mut Collection, input: &[u8]) -> Result { + if col.state.modified_by_dbproxy { + col.storage.set_modified()?; + col.state.modified_by_dbproxy = false; + } col.storage.commit_trx()?; DBResult::None } @@ -96,17 +100,17 @@ pub(super) fn db_command_bytes(col: &mut Collection, input: &[u8]) -> Result { - maybe_clear_undo(col, &sql); + update_state_after_modification(col, &sql); db_execute_many(&col.storage, &sql, &args)? } }; Ok(serde_json::to_vec(&resp)?) } -fn maybe_clear_undo(col: &mut Collection, sql: &str) { +fn update_state_after_modification(col: &mut Collection, sql: &str) { if !is_dql(sql) { println!("clearing undo+study due to {}", sql); - col.discard_undo_and_study_queues(); + col.update_state_after_dbproxy_modification(); } } diff --git a/rslib/src/collection.rs b/rslib/src/collection.rs index bb701f9b6..2e664b087 100644 --- a/rslib/src/collection.rs +++ b/rslib/src/collection.rs @@ -65,6 +65,9 @@ pub struct CollectionState { pub(crate) notetype_cache: HashMap>, pub(crate) deck_cache: HashMap>, pub(crate) card_queues: Option, + /// True if legacy Python code has executed SQL that has modified the + /// database, requiring modification time to be bumped. + pub(crate) modified_by_dbproxy: bool, } pub struct Collection { @@ -92,7 +95,7 @@ impl Collection { let mut res = func(self); if res.is_ok() { - if let Err(e) = self.storage.mark_modified() { + if let Err(e) = self.storage.set_modified() { res = Err(e); } else if let Err(e) = self.storage.commit_rust_trx() { res = Err(e); diff --git a/rslib/src/storage/sqlite.rs b/rslib/src/storage/sqlite.rs index bbc0e0ff0..9d4d20c7e 100644 --- a/rslib/src/storage/sqlite.rs +++ b/rslib/src/storage/sqlite.rs @@ -257,7 +257,7 @@ impl SqliteStorage { ////////////////////////////////////////// - pub(crate) fn mark_modified(&self) -> Result<()> { + pub(crate) fn set_modified(&self) -> Result<()> { self.set_modified_time(TimestampMillis::now()) } diff --git a/rslib/src/undo/mod.rs b/rslib/src/undo/mod.rs index 339db290a..55a8d2449 100644 --- a/rslib/src/undo/mod.rs +++ b/rslib/src/undo/mod.rs @@ -174,6 +174,11 @@ impl Collection { self.clear_study_queues(); } + pub(crate) fn update_state_after_dbproxy_modification(&mut self) { + self.discard_undo_and_study_queues(); + self.state.modified_by_dbproxy = true; + } + #[inline] pub(crate) fn save_undo(&mut self, item: impl Into) { self.state.undo.save(item.into());