From aefce204607300b13cca297cbf721e1ce3e5771e Mon Sep 17 00:00:00 2001 From: m0hossam Date: Sun, 4 May 2025 22:14:51 +0300 Subject: [PATCH 1/2] Try to coalesce free blocks before freeing --- core/storage/btree.rs | 48 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/core/storage/btree.rs b/core/storage/btree.rs index 0523edcb8..f93bccc86 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -4590,8 +4590,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(); @@ -4604,11 +4605,50 @@ 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; + let mut j = 0; + while j < number_of_cells_buffered { + if buffered_cells_offsets[j] == end { + buffered_cells_offsets[j] = offset; + break; + } else if buffered_cells_ends[j] == offset { + buffered_cells_ends[j] = end; + break; + } + j += 1; + } + if j >= number_of_cells_buffered { + 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; + } + 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( From 70b9438f80427f7257f16b457b1697c976f0c1f3 Mon Sep 17 00:00:00 2001 From: m0hossam Date: Mon, 12 May 2025 15:58:36 +0300 Subject: [PATCH 2/2] Add comments --- core/storage/btree.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/core/storage/btree.rs b/core/storage/btree.rs index f93bccc86..725ab3ad1 100644 --- a/core/storage/btree.rs +++ b/core/storage/btree.rs @@ -4607,18 +4607,28 @@ fn page_free_array( let len = (cell_pointer.end as usize - cell_pointer.start as usize) as u16; 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( @@ -4628,8 +4638,9 @@ fn page_free_array( usable_space, )?; } - number_of_cells_buffered = 0; + 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;