cacheflush move dirty page to new snapshot

After inserting a page into the wal, we dispose of the modified page.
This is unnecessary as we can simply move new page to the newest
snapshot where this page can be read.
This commit is contained in:
Pere Diaz Bou 2025-05-19 15:00:32 +02:00
parent 9677997c63
commit 35e2088b7e

View file

@ -461,6 +461,9 @@ impl Pager {
Some(wal) => wal.borrow().get_max_frame(),
None => 0,
};
let max_frame_after_append = self.wal.as_ref().map(|wal| {
wal.borrow().get_max_frame() + self.dirty_pages.borrow().len() as u64
});
for page_id in self.dirty_pages.borrow().iter() {
let mut cache = self.page_cache.write();
let page_key = PageCacheKey::new(*page_id, Some(max_frame));
@ -473,6 +476,17 @@ impl Pager {
db_size,
self.flush_info.borrow().in_flight_writes.clone(),
)?;
// Assuming writer will always end append frames at frameid == this_transaction.max_frame + dirty_pages,
// we can insert this page with a new key into that new "snapshot" that has the newest max frame. We don't
// simply clone the page and insert with new key because next cache.delete will invalidate the contents of the page,
// therefore we need to clone the contents itself and place them on the new page. Cloning contents should be fast because
// buffer is wrapped around an Arc.
let new_page = Page::new(*page_id);
new_page.get().contents = Some(page.get_contents().clone());
new_page.set_loaded();
let new_page: Arc<Page> = Arc::new(new_page);
let new_page_key = PageCacheKey::new(*page_id, max_frame_after_append);
cache.insert(new_page_key, new_page).map_err(|e| {LimboError::InternalError(format!("Failed to delete page {:?} from cache during flush: {:?}. Might be actively referenced.", page_id, e))})?;
}
page.clear_dirty();
// This page is no longer valid.