Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions crates/commitlog/src/index/indexfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::{
mem,
};

use log::debug;
use log::{debug, trace};
use memmap2::MmapMut;
use spacetimedb_paths::server::OffsetIndexFile;

Expand Down Expand Up @@ -190,19 +190,32 @@ impl<Key: Into<u64> + From<u64>> IndexFileMut<Key> {
self.inner.flush_async()
}

/// Truncates the index file starting from the entry with a key greater than or equal to the given key.
/// Truncates the index file starting from the entry with a key greater than
/// or equal to the given key.
///
/// If successful, `key` will no longer be in the index.
pub(crate) fn truncate(&mut self, key: Key) -> Result<(), IndexError> {
let key = key.into();
let (found_key, index) = self.find_index(Key::from(key))?;
let (found_key, index) = self
.find_index(Key::from(key))
.map(|(found, index)| (found.into(), index))?;

// If returned key is smalled than asked key, truncate from next entry
self.num_entries = if found_key.into() == key {
// If returned key is smaller than asked key, truncate from next entry
self.num_entries = if found_key == key {
index as usize
} else {
index as usize + 1
};

let start = self.num_entries * ENTRY_SIZE;
trace!(
"truncate key={} found={} index={} num-entries={} start={}",
key,
found_key,
index,
self.num_entries,
start
);

if start < self.inner.len() {
self.inner[start..].fill(0);
Expand Down
35 changes: 24 additions & 11 deletions crates/commitlog/src/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,7 @@ mod tests {
use super::*;
use crate::{payload::ArrayDecoder, repo, Options};
use itertools::Itertools;
use pretty_assertions::assert_matches;
use proptest::prelude::*;
use spacetimedb_paths::server::CommitLogDir;
use tempfile::tempdir;
Expand Down Expand Up @@ -924,16 +925,28 @@ mod tests {

// Truncating to any offset in the written range or larger
// retains that offset - 1, or the max offset written.
let truncate_to: TxOffset = rand::random_range(1..=32);
let retained_key = truncate_to.saturating_sub(1).min(10);
let retained_val = retained_key * 128;
let retained = (retained_key, retained_val);

writer.ftruncate(truncate_to, rand::random()).unwrap();
assert_eq!(writer.head.key_lookup(truncate_to).unwrap(), retained);
// Make sure this also holds after reopen.
drop(writer);
let index = TxOffsetIndex::open_index_file(&index_path).unwrap();
assert_eq!(index.key_lookup(truncate_to).unwrap(), retained);
for truncate_to in (2..=10u64).rev() {
let retained_key = truncate_to.saturating_sub(1).min(10);
let retained_val = retained_key * 128;
let retained = (retained_key, retained_val);

writer.ftruncate(truncate_to, rand::random()).unwrap();
assert_matches!(
writer.head.key_lookup(truncate_to),
Ok(x) if x == retained,
"truncate to {truncate_to} should retain {retained:?}"
);
// Make sure this also holds after reopen.
let index = TxOffsetIndex::open_index_file(&index_path).unwrap();
assert_matches!(
index.key_lookup(truncate_to),
Ok(x) if x == retained,
"truncate to {truncate_to} should retain {retained:?} after reopen"
);
}

// Truncating to 1 leaves no entries in the index
writer.ftruncate(1, rand::random()).unwrap();
assert_matches!(writer.head.key_lookup(1), Err(IndexError::KeyNotFound));
}
}
Loading