Skip to content

Commit 68d63ca

Browse files
committed
Add truncate test, also asserting flush offset behavior
1 parent 90c5f7c commit 68d63ca

File tree

1 file changed

+86
-3
lines changed

1 file changed

+86
-3
lines changed

src/segment.rs

Lines changed: 86 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use log::{debug, error, log_enabled, trace};
2-
use std::cmp::{min, Ordering};
2+
use std::cmp::{Ordering, min};
33
use std::fmt;
44
use std::fs::{self, OpenOptions};
55
use std::io::{Error, ErrorKind, Result};
@@ -698,6 +698,21 @@ fn padding(len: usize) -> usize {
698698
4usize.wrapping_sub(len) & 7
699699
}
700700

701+
/// Returns total number of bytes used on disk to store an entry of length `len`.
702+
///
703+
/// Includes header, padding and CRC.
704+
///
705+
/// | component | type |
706+
/// | ---------------------------- | ---- |
707+
/// | length | u64 |
708+
/// | data | |
709+
/// | padding | |
710+
/// | CRC(length + data + padding) | u32 |
711+
#[cfg(test)]
712+
pub fn entry_size_disk(len: usize) -> usize {
713+
len + entry_overhead(len)
714+
}
715+
701716
/// Returns the overhead of storing an entry of length `len`.
702717
pub fn entry_overhead(len: usize) -> usize {
703718
padding(len) + HEADER_LEN + CRC_LEN
@@ -710,12 +725,15 @@ pub fn segment_overhead() -> usize {
710725

711726
#[cfg(test)]
712727
mod test {
713-
use std::io::ErrorKind;
728+
use std::{io::ErrorKind, path::Path};
714729
use tempfile::{Builder, TempDir};
715730

716731
use super::{Segment, padding};
717732

718-
use crate::test_utils::EntryGenerator;
733+
use crate::{
734+
segment::{HEADER_LEN, entry_size_disk},
735+
test_utils::EntryGenerator,
736+
};
719737

720738
#[test]
721739
fn test_pad_len() {
@@ -745,6 +763,12 @@ mod test {
745763
(Segment::create(path, len).unwrap(), dir)
746764
}
747765

766+
fn load_segment(dir: impl AsRef<Path>) -> Segment {
767+
let mut path = dir.as_ref().to_path_buf();
768+
path.push("sync-segment");
769+
Segment::open(path).unwrap()
770+
}
771+
748772
fn init_logger() {
749773
let _ = env_logger::builder().is_test(true).try_init();
750774
}
@@ -780,6 +804,65 @@ mod test {
780804
check_append(&mut create_segment(8 * 1024 * 1024).0);
781805
}
782806

807+
#[test]
808+
fn test_truncate() {
809+
init_logger();
810+
let (mut segment, dir) = create_segment(4096);
811+
812+
segment.append(&b"0".as_slice()).unwrap();
813+
segment.append(&b"1".as_slice()).unwrap();
814+
segment.append(&b"2".as_slice()).unwrap();
815+
segment.append(&b"3".as_slice()).unwrap();
816+
817+
// Truncate beyond the end is a no-op
818+
assert_eq!(segment.len(), 4);
819+
segment.truncate(4);
820+
assert_eq!(segment.len(), 4);
821+
822+
// Until we flush, flush offset remains zero
823+
assert_eq!(segment.flush_offset, 0);
824+
segment.flush().unwrap();
825+
assert_eq!(segment.flush_offset, HEADER_LEN + entry_size_disk(1) * 4);
826+
827+
// Truncate to keep one entry
828+
segment.truncate(1);
829+
assert_eq!(segment.len(), 1);
830+
assert_eq!(segment.flush_offset, HEADER_LEN + entry_size_disk(1));
831+
832+
// Add a new items (index 2, 3), flush offset remains at index 1 until we flush
833+
segment.append(&b"12345".as_slice()).unwrap();
834+
segment.append(&b"67890".as_slice()).unwrap();
835+
assert_eq!(segment.len(), 3);
836+
assert_eq!(segment.flush_offset, HEADER_LEN + entry_size_disk(1));
837+
838+
// Flush and reload
839+
// This was broken before <https://github.com/qdrant/wal/pull/99>, as it wouldn't fully
840+
// flush the last two appended operations
841+
segment.flush().unwrap();
842+
assert_eq!(
843+
segment.flush_offset,
844+
HEADER_LEN + entry_size_disk(1) + entry_size_disk(5) * 2,
845+
);
846+
let mut segment = load_segment(&dir);
847+
assert_eq!(segment.len(), 3);
848+
assert_eq!(
849+
segment.flush_offset,
850+
HEADER_LEN + entry_size_disk(1) + entry_size_disk(5) * 2,
851+
);
852+
853+
// Truncate all (clear) and assert flush offset is bumped
854+
segment.truncate(0);
855+
assert_eq!(segment.len(), 0);
856+
assert_eq!(segment.flush_offset, HEADER_LEN);
857+
858+
// Flush and reload
859+
segment.flush().unwrap();
860+
assert_eq!(segment.flush_offset, HEADER_LEN);
861+
let segment = load_segment(&dir);
862+
assert_eq!(segment.len(), 0);
863+
assert_eq!(segment.flush_offset, HEADER_LEN);
864+
}
865+
783866
#[test]
784867
fn test_create_dir_path() {
785868
init_logger();

0 commit comments

Comments
 (0)