mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-25 03:54:21 +01:00
Merge 'Fix clear_page_cache method and rollback' from Preston Thorpe
Previously we were iterating over every entry in the page cache, clearing the dirty flag from each page. Reviewed-by: Pere Diaz Bou <pere-altea@homail.com> Reviewed-by: Nikita Sivukhin (@sivukhin) Closes #2988
This commit is contained in:
@@ -528,20 +528,36 @@ impl PageCache {
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) -> Result<(), CacheError> {
|
||||
for e in self.entries.iter() {
|
||||
if self.map.len() == 0 {
|
||||
// Fast path: nothing to do.
|
||||
self.clock_hand = NULL;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for node in self.map.iter() {
|
||||
let e = &self.entries[node.slot_index];
|
||||
if let Some(ref p) = e.page {
|
||||
if p.is_dirty() {
|
||||
return Err(CacheError::Dirty { pgno: p.get().id });
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut used_slots = Vec::with_capacity(self.map.len());
|
||||
for node in self.map.iter() {
|
||||
used_slots.push(node.slot_index);
|
||||
}
|
||||
// don't touch already-free slots at all.
|
||||
for &i in &used_slots {
|
||||
if let Some(p) = self.entries[i].page.take() {
|
||||
p.clear_loaded();
|
||||
let _ = p.get().contents.take();
|
||||
}
|
||||
self.entries[i].clear_ref();
|
||||
self.entries[i].reset_links();
|
||||
}
|
||||
self.entries.fill(PageCacheEntry::empty());
|
||||
self.map.clear();
|
||||
self.clock_hand = NULL;
|
||||
self.freelist.clear();
|
||||
for i in (0..self.capacity).rev() {
|
||||
self.map = PageHashMap::new(self.capacity);
|
||||
for &i in used_slots.iter().rev() {
|
||||
self.freelist.push(i);
|
||||
}
|
||||
Ok(())
|
||||
@@ -631,16 +647,6 @@ impl PageCache {
|
||||
self.capacity
|
||||
}
|
||||
|
||||
pub fn unset_dirty_all_pages(&mut self) {
|
||||
let entries = &self.entries;
|
||||
for entry in entries.iter() {
|
||||
if entry.page.is_none() {
|
||||
continue;
|
||||
}
|
||||
entry.page.as_ref().unwrap().clear_dirty();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn verify_cache_integrity(&self) {
|
||||
let map = &self.map;
|
||||
|
||||
@@ -1563,12 +1563,15 @@ impl Pager {
|
||||
/// of a rollback or in case we want to invalidate page cache after starting a read transaction
|
||||
/// right after new writes happened which would invalidate current page cache.
|
||||
pub fn clear_page_cache(&self) {
|
||||
self.dirty_pages.borrow_mut().clear();
|
||||
self.page_cache.write().unset_dirty_all_pages();
|
||||
self.page_cache
|
||||
.write()
|
||||
.clear()
|
||||
.expect("Failed to clear page cache");
|
||||
let dirty_pages = self.dirty_pages.borrow();
|
||||
let mut cache = self.page_cache.write();
|
||||
for page_id in dirty_pages.iter() {
|
||||
let page_key = PageCacheKey::new(*page_id);
|
||||
if let Some(page) = cache.get(&page_key).unwrap_or(None) {
|
||||
page.clear_dirty();
|
||||
}
|
||||
}
|
||||
cache.clear().expect("Failed to clear page cache");
|
||||
}
|
||||
|
||||
/// Checkpoint in Truncate mode and delete the WAL file. This method is _only_ to be called
|
||||
@@ -2118,6 +2121,7 @@ impl Pager {
|
||||
is_write: bool,
|
||||
) -> Result<(), LimboError> {
|
||||
tracing::debug!(schema_did_change);
|
||||
self.clear_page_cache();
|
||||
if is_write {
|
||||
self.dirty_pages.borrow_mut().clear();
|
||||
} else {
|
||||
@@ -2126,12 +2130,7 @@ impl Pager {
|
||||
"dirty pages should be empty for read txn"
|
||||
);
|
||||
}
|
||||
let mut cache = self.page_cache.write();
|
||||
|
||||
self.reset_internal_states();
|
||||
|
||||
cache.unset_dirty_all_pages();
|
||||
cache.clear().expect("failed to clear page cache");
|
||||
if schema_did_change {
|
||||
connection.schema.replace(connection._db.clone_schema()?);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user