Skip to content

Commit 1aa3142

Browse files
matlikjackpot51
authored andcommittedMar 1, 2025
Add alloc log GC
1 parent ec5f32e commit 1aa3142

File tree

3 files changed

+18
-13
lines changed

3 files changed

+18
-13
lines changed
 

‎src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ extern crate alloc;
99

1010
use core::sync::atomic::AtomicUsize;
1111

12+
// The alloc log grows by 1 block about every 21 generations
13+
pub const ALLOC_GC_THRESHOLD: u64 = 1024;
1214
pub const BLOCK_SIZE: u64 = 4096;
1315
// A record is 4KiB << 5 = 128KiB
1416
pub const RECORD_LEVEL: usize = 5;

‎src/tests.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{unmount_path, DiskSparse, FileSystem, Node, TreePtr};
1+
use crate::{unmount_path, DiskSparse, FileSystem, Node, TreePtr, ALLOC_GC_THRESHOLD};
22
use std::path::Path;
33
use std::process::Command;
44
use std::sync::atomic::AtomicUsize;
@@ -166,7 +166,11 @@ fn many_create_remove_should_not_increase_size() {
166166
let name = "test";
167167

168168
// Iterate over 255 times to prove deleted files don't retain space within the node tree
169-
for i in 0..600 {
169+
// Iterate to an ALLOC_GC_THRESHOLD boundary to ensure the allocator GC reclaims space
170+
let start = fs.header.generation.to_ne();
171+
let end = start + ALLOC_GC_THRESHOLD;
172+
let end = end - (end % ALLOC_GC_THRESHOLD) + 1 + ALLOC_GC_THRESHOLD;
173+
for i in start..end {
170174
let _ = fs
171175
.tx(|tx| {
172176
tx.create_node(
@@ -181,9 +185,6 @@ fn many_create_remove_should_not_increase_size() {
181185
.unwrap();
182186
}
183187

184-
// Sync with squash to exclude the allocation log growth from the assertion
185-
let _ = fs.tx(|tx| tx.sync(true));
186-
187188
// Any value greater than 0 indicates a storage leak
188189
let diff = initially_free - fs.allocator().free();
189190
assert_eq!(diff, 0);

‎src/transaction.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use syscall::error::{
1515
use crate::{
1616
AllocEntry, AllocList, Allocator, BlockAddr, BlockData, BlockLevel, BlockPtr, BlockTrait,
1717
DirEntry, DirList, Disk, FileSystem, Header, Node, NodeLevel, RecordRaw, TreeData, TreePtr,
18-
ALLOC_LIST_ENTRIES, DIR_ENTRY_MAX_LENGTH, HEADER_RING,
18+
ALLOC_GC_THRESHOLD, ALLOC_LIST_ENTRIES, DIR_ENTRY_MAX_LENGTH, HEADER_RING,
1919
};
2020

2121
pub struct Transaction<'a, D: Disk> {
@@ -113,11 +113,14 @@ impl<'a, D: Disk> Transaction<'a, D> {
113113
/// This method does not write anything to disk,
114114
/// all writes are cached.
115115
///
116-
/// If `squash` is true, fully rebuild the allocator log
117-
/// using the state of `self.allocator`.
118-
fn sync_allocator(&mut self, squash: bool) -> Result<bool> {
116+
/// To keep the allocator log from growing excessively, it will
117+
/// periodically be fully rebuilt using the state of `self.allocator`.
118+
/// This rebuild can be forced by setting `force_squash` to `true`.
119+
fn sync_allocator(&mut self, force_squash: bool) -> Result<bool> {
119120
let mut prev_ptr = BlockPtr::default();
120-
if squash {
121+
let should_gc = self.header.generation() % ALLOC_GC_THRESHOLD == 0
122+
&& self.header.generation() >= ALLOC_GC_THRESHOLD;
123+
if force_squash || should_gc {
121124
// Clear and rebuild alloc log
122125
self.allocator_log.clear();
123126
let levels = self.allocator.levels();
@@ -204,11 +207,10 @@ impl<'a, D: Disk> Transaction<'a, D> {
204207
Ok(true)
205208
}
206209

207-
// TODO: change this function, provide another way to squash, only write header in commit
208210
/// Write all changes cached in this [`Transaction`] to disk.
209-
pub fn sync(&mut self, squash: bool) -> Result<bool> {
211+
pub fn sync(&mut self, force_squash: bool) -> Result<bool> {
210212
// Make sure alloc is synced
211-
self.sync_allocator(squash)?;
213+
self.sync_allocator(force_squash)?;
212214

213215
// Write all items in write cache
214216
for (addr, raw) in self.write_cache.iter_mut() {

0 commit comments

Comments
 (0)
Please sign in to comment.