Ensure we purge caches when rolling back

Fixes #1056
This commit is contained in:
Damien Elmes 2021-03-08 10:39:18 +10:00
parent e1bf19b6ee
commit b81e2c0265
4 changed files with 21 additions and 11 deletions

View file

@ -245,7 +245,7 @@ class Collection:
self.save(trx=False) self.save(trx=False)
else: else:
self.db.rollback() self.db.rollback()
self.models._clear_cache() self._clear_caches()
self._backend.close_collection(downgrade_to_schema11=downgrade) self._backend.close_collection(downgrade_to_schema11=downgrade)
self.db = None self.db = None
self.media.close() self.media.close()
@ -255,15 +255,19 @@ class Collection:
# save and cleanup, but backend will take care of collection close # save and cleanup, but backend will take care of collection close
if self.db: if self.db:
self.save(trx=False) self.save(trx=False)
self.models._clear_cache() self._clear_caches()
self.db = None self.db = None
self.media.close() self.media.close()
self._closeLog() self._closeLog()
def rollback(self) -> None: def rollback(self) -> None:
self._clear_caches()
self.db.rollback() self.db.rollback()
self.db.begin() self.db.begin()
def _clear_caches(self) -> None:
self.models._clear_cache()
def reopen(self, after_full_sync: bool = False) -> None: def reopen(self, after_full_sync: bool = False) -> None:
assert not self.db assert not self.db
assert self.path.endswith(".anki2") assert self.path.endswith(".anki2")

View file

@ -1,8 +1,8 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
use crate::err::Result;
use crate::storage::SqliteStorage; use crate::storage::SqliteStorage;
use crate::{collection::Collection, err::Result};
use rusqlite::types::{FromSql, FromSqlError, ToSql, ToSqlOutput, ValueRef}; use rusqlite::types::{FromSql, FromSqlError, ToSql, ToSqlOutput, ValueRef};
use rusqlite::OptionalExtension; use rusqlite::OptionalExtension;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -67,7 +67,7 @@ impl FromSql for SqlValue {
} }
} }
pub(super) fn db_command_bytes(ctx: &SqliteStorage, input: &[u8]) -> Result<Vec<u8>> { pub(super) fn db_command_bytes(col: &mut Collection, input: &[u8]) -> Result<Vec<u8>> {
let req: DBRequest = serde_json::from_slice(input)?; let req: DBRequest = serde_json::from_slice(input)?;
let resp = match req { let resp = match req {
DBRequest::Query { DBRequest::Query {
@ -76,24 +76,25 @@ pub(super) fn db_command_bytes(ctx: &SqliteStorage, input: &[u8]) -> Result<Vec<
first_row_only, first_row_only,
} => { } => {
if first_row_only { if first_row_only {
db_query_row(ctx, &sql, &args)? db_query_row(&col.storage, &sql, &args)?
} else { } else {
db_query(ctx, &sql, &args)? db_query(&col.storage, &sql, &args)?
} }
} }
DBRequest::Begin => { DBRequest::Begin => {
ctx.begin_trx()?; col.storage.begin_trx()?;
DBResult::None DBResult::None
} }
DBRequest::Commit => { DBRequest::Commit => {
ctx.commit_trx()?; col.storage.commit_trx()?;
DBResult::None DBResult::None
} }
DBRequest::Rollback => { DBRequest::Rollback => {
ctx.rollback_trx()?; col.clear_caches();
col.storage.rollback_trx()?;
DBResult::None DBResult::None
} }
DBRequest::ExecuteMany { sql, args } => db_execute_many(ctx, &sql, &args)?, DBRequest::ExecuteMany { sql, args } => db_execute_many(&col.storage, &sql, &args)?,
}; };
Ok(serde_json::to_vec(&resp)?) Ok(serde_json::to_vec(&resp)?)
} }

View file

@ -1851,7 +1851,7 @@ impl Backend {
} }
pub fn db_command(&self, input: &[u8]) -> Result<Vec<u8>> { pub fn db_command(&self, input: &[u8]) -> Result<Vec<u8>> {
self.with_col(|col| db_command_bytes(&col.storage, input)) self.with_col(|col| db_command_bytes(col, input))
} }
pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result<Vec<u8>, Vec<u8>> { pub fn run_db_command_bytes(&self, input: &[u8]) -> std::result::Result<Vec<u8>, Vec<u8>> {

View file

@ -139,4 +139,9 @@ impl Collection {
})?; })?;
self.storage.optimize() self.storage.optimize()
} }
pub(crate) fn clear_caches(&mut self) {
self.state.deck_cache.clear();
self.state.notetype_cache.clear();
}
} }