Skip to content

Commit

Permalink
Fixing new file edge case + config builder fns
Browse files Browse the repository at this point in the history
Working on integrating with Sediment, I discovered an edge case when
shutdown happens directly after a checkpoint operation before more data
has been written. The header was stuck in a buffer, and the buffer was
never flushed.

The rest of the changes are adding more methods to the configuration
type to allow builder-style configuration.
  • Loading branch information
ecton committed Dec 31, 2022
1 parent 3e84a36 commit 77b2764
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::{LogManager, WriteAheadLog};

/// A [`WriteAheadLog`] configuration.
#[derive(Debug)]
#[must_use]
pub struct Configuration {
/// The directory to store the log files in.
pub directory: PathBuf,
Expand Down Expand Up @@ -56,6 +57,37 @@ impl Configuration {
}
}

/// Sets the number of bytes to preallocate for each segment file. Returns self.
///
/// Preallocating disk space allows for more consistent performance. This
/// number should be large enough to allow batching multiple entries into
/// one checkpointing operation.
pub fn preallocate_bytes(mut self, bytes: u32) -> Self {
self.preallocate_bytes = bytes;
self
}

/// Sets the number of bytes written required to begin a checkpoint
/// operation. Returns self.
///
/// This value should be smaller than `preallocate_bytes` tp ensure
/// checkpoint operations begin before too much data is written in a log
/// entry. If more data is written before a checkpoint occurs, the segment
/// will grow to accomodate the extra data, but that write will not be as
/// fast due to needing to allocate more space from the filesystem to
/// perform the write.
pub fn checkpoint_after_bytes(mut self, bytes: u64) -> Self {
self.checkpoint_after_bytes = bytes;
self
}

/// Sets the number of bytes to use for internal buffers when reading and
/// writing data to the log.
pub fn buffer_bytes(mut self, bytes: usize) -> Self {
self.buffer_bytes = bytes;
self
}

/// Opens the log using the provided log manager with this configuration.
pub fn open<Manager: LogManager>(self, manager: Manager) -> io::Result<WriteAheadLog> {
WriteAheadLog::open(self, manager)
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,9 @@ impl WriteAheadLog {
/// - The file cannot be read.
/// - The position refers to data that has been checkpointed.
pub fn read_at(&self, position: LogPosition) -> io::Result<ChunkReader> {
// TODO we should keep track of how many readers we have open for a
// given wal file to prevent the truncation operation in a checkpoint if
// a reader is still open.
let mut file = File::open(
self.data
.config
Expand Down
1 change: 1 addition & 0 deletions src/log_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl LogFileWriter {

if validated_length == 0 {
Self::write_header(&mut file, &config.version_info, false)?;
file.flush()?;
}

Ok(Self {
Expand Down

0 comments on commit 77b2764

Please sign in to comment.