mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 10:08:20 +00:00
Merge 'btree: Coalesce free blocks in page_free_array()
' from Mohamed Hossam
Coalesce adjacent free blocks during `page_free_array()` in `core/storage/btree`. Instead of immediately passing free cells to `free_cell_range()`, buffer up to 10 free cells and try to merge adjacent free blocks. Break on the first merge to avoid time complexity, `free_cell_range()` coalesces blocks afterwards anyways. This follows SQLite's [`pageFreeArray()`](htt ps://github.com/sqlite/sqlite/blob/d7324103b196c572a98724a5658970b4000b8 c39/src/btree.c#L7729) implementation. Removed this TODO: ```rust fn page_free_array( . . ) . . // TODO: implement fancy smart free block coalescing procedure instead of dumb free to // then defragment ``` Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com> Closes #1448
This commit is contained in:
commit
2b6b09d435
1 changed files with 55 additions and 4 deletions
|
@ -4699,8 +4699,9 @@ fn page_free_array(
|
|||
let buf = &mut page.as_ptr()[page.offset..usable_space as usize];
|
||||
let buf_range = buf.as_ptr_range();
|
||||
let mut number_of_cells_removed = 0;
|
||||
// TODO: implement fancy smart free block coalescing procedure instead of dumb free to
|
||||
// then defragment
|
||||
let mut number_of_cells_buffered = 0;
|
||||
let mut buffered_cells_offsets: [u16; 10] = [0; 10];
|
||||
let mut buffered_cells_ends: [u16; 10] = [0; 10];
|
||||
for i in first..first + count {
|
||||
let cell = &cell_array.cells[i];
|
||||
let cell_pointer = cell.as_ptr_range();
|
||||
|
@ -4713,11 +4714,61 @@ fn page_free_array(
|
|||
// TODO: remove pointer too
|
||||
let offset = (cell_pointer.start as usize - buf_range.start as usize) as u16;
|
||||
let len = (cell_pointer.end as usize - cell_pointer.start as usize) as u16;
|
||||
free_cell_range(page, offset, len, usable_space)?;
|
||||
page.write_u16(offset::BTREE_CELL_COUNT, page.cell_count() as u16 - 1);
|
||||
assert!(len > 0, "cell size should be greater than 0");
|
||||
let end = offset + len;
|
||||
|
||||
/* Try to merge the current cell with a contiguous buffered cell to reduce the number of
|
||||
* `free_cell_range()` operations. Break on the first merge to avoid consuming too much time,
|
||||
* `free_cell_range()` will try to merge contiguous cells anyway. */
|
||||
let mut j = 0;
|
||||
while j < number_of_cells_buffered {
|
||||
// If the buffered cell is immediately after the current cell
|
||||
if buffered_cells_offsets[j] == end {
|
||||
// Merge them by updating the buffered cell's offset to the current cell's offset
|
||||
buffered_cells_offsets[j] = offset;
|
||||
break;
|
||||
// If the buffered cell is immediately before the current cell
|
||||
} else if buffered_cells_ends[j] == offset {
|
||||
// Merge them by updating the buffered cell's end offset to the current cell's end offset
|
||||
buffered_cells_ends[j] = end;
|
||||
break;
|
||||
}
|
||||
j += 1;
|
||||
}
|
||||
// If no cells were merged
|
||||
if j >= number_of_cells_buffered {
|
||||
// If the buffered cells array is full, flush the buffered cells using `free_cell_range()` to empty the array
|
||||
if number_of_cells_buffered >= buffered_cells_offsets.len() {
|
||||
for j in 0..number_of_cells_buffered {
|
||||
free_cell_range(
|
||||
page,
|
||||
buffered_cells_offsets[j],
|
||||
buffered_cells_ends[j] - buffered_cells_offsets[j],
|
||||
usable_space,
|
||||
)?;
|
||||
}
|
||||
number_of_cells_buffered = 0; // Reset array counter
|
||||
}
|
||||
// Buffer the current cell
|
||||
buffered_cells_offsets[number_of_cells_buffered] = offset;
|
||||
buffered_cells_ends[number_of_cells_buffered] = end;
|
||||
number_of_cells_buffered += 1;
|
||||
}
|
||||
number_of_cells_removed += 1;
|
||||
}
|
||||
}
|
||||
for j in 0..number_of_cells_buffered {
|
||||
free_cell_range(
|
||||
page,
|
||||
buffered_cells_offsets[j],
|
||||
buffered_cells_ends[j] - buffered_cells_offsets[j],
|
||||
usable_space,
|
||||
)?;
|
||||
}
|
||||
page.write_u16(
|
||||
offset::BTREE_CELL_COUNT,
|
||||
page.cell_count() as u16 - number_of_cells_removed as u16,
|
||||
);
|
||||
Ok(number_of_cells_removed)
|
||||
}
|
||||
fn page_insert_array(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue