aboutsummaryrefslogtreecommitdiffstats
path: root/log_db/src/common.rs
diff options
context:
space:
mode:
authorJan Tuomi <jan@jantuomi.fi>2024-11-02 16:58:01 +0200
committerJan Tuomi <jan@jantuomi.fi>2024-11-02 17:39:22 +0200
commit912c32f762ee7585e20fde57c7c5dca1f9b0478d (patch)
treeafad7b189adb3a5189174e1fd9b44823cf63b3fa /log_db/src/common.rs
parent3838cd9ee68ff5433f00a52feed04a9682b79161 (diff)
Refactor in preparation to larger changes
Diffstat (limited to 'log_db/src/common.rs')
-rw-r--r--log_db/src/common.rs116
1 files changed, 110 insertions, 6 deletions
diff --git a/log_db/src/common.rs b/log_db/src/common.rs
index c2af766..0a1179e 100644
--- a/log_db/src/common.rs
+++ b/log_db/src/common.rs
@@ -1,7 +1,9 @@
+use std::cmp::Ordering;
+use std::collections::HashSet;
use std::fmt::Display;
use std::fs::{metadata, File};
use std::io::{self};
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
// For Unix-like systems
#[cfg(unix)]
@@ -11,7 +13,7 @@ use std::os::unix::fs::MetadataExt;
#[cfg(windows)]
use std::os::windows::fs::MetadataExt;
-pub const ACTIVE_LOG_FILENAME: &str = "db";
+pub const ACTIVE_SYMLINK_FILENAME: &str = "active";
pub const EXCL_LOCK_REQUEST_FILENAME: &str = "excl_lock_req";
pub const DEFAULT_READ_BUF_SIZE: usize = 1024 * 1024; // 1 MB
pub const FIELD_SEPARATOR: u8 = b'\x1C';
@@ -63,11 +65,93 @@ pub enum SpecialSequence {
LiteralEscape,
}
+/// LogKey is a packed struct that contains:
+/// - a log segment number (16 bits)
+/// - a log index within the segment (48 bits)
+#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
+pub struct LogKey(u64);
+
+impl LogKey {
+ pub fn new(segment_num: u16, index: u64) -> Self {
+ assert!(index < (1 << 48), "Index must fit in 48 bits");
+ LogKey((segment_num as u64) << 48 | index)
+ }
+
+ pub fn segment_num(&self) -> u16 {
+ (self.0 >> 48) as u16
+ }
+
+ pub fn index(&self) -> u64 {
+ self.0 & 0x0000_FFFF_FFFF_FFFF
+ }
+}
+
+/// LogKeySet is a non-empty set of LogKeys.
#[derive(Debug, Clone, Eq, PartialEq)]
-pub enum MemtableEvictPolicy {
- LeastWritten,
- LeastRead,
- LeastReadOrWritten,
+pub struct LogKeySet {
+ set: HashSet<LogKey>,
+}
+
+impl PartialOrd for LogKeySet {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ let self_max_elem = self.set.iter().max()?;
+ let other_max_elem = other.set.iter().max()?;
+ Some(self_max_elem.cmp(other_max_elem))
+ }
+}
+
+impl LogKeySet {
+ /// Create a new LogKeySet with an initial LogKey.
+ /// The initial LogKey is required since LogKeySet must be non-empty.
+ pub fn new_with_initial(key: &LogKey) -> Self {
+ let mut set = HashSet::new();
+ set.insert(key.clone());
+ LogKeySet { set }
+ }
+
+ /// Insert a LogKey into the set.
+ pub fn insert(&mut self, key: LogKey) {
+ self.set.insert(key);
+ }
+
+ /// Remove a LogKey from the set. Return Ok(()) if the key was found and removed.
+ /// Return io::Error::InvalidInput if trying to remove the last element.
+ /// Return io::Error::NotFound if the key was not found.
+ pub fn remove(&mut self, key: &LogKey) -> Result<(), io::Error> {
+ if self.set.len() == 1 {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "Cannot remove the last element from LogKeySet",
+ ));
+ }
+ let removed = self.set.remove(key);
+
+ if !removed {
+ return Err(io::Error::new(
+ io::ErrorKind::NotFound,
+ "LogKey not found in LogKeySet",
+ ));
+ }
+
+ assert!(
+ self.set.len() > 0,
+ "LogKeySet should not be empty after removal"
+ );
+
+ Ok(())
+ }
+
+ /// Get a reference to the set of LogKeys.
+ pub fn log_keys(&self) -> &HashSet<LogKey> {
+ &self.set
+ }
+}
+
+impl Ord for LogKeySet {
+ fn cmp(&self, other: &Self) -> Ordering {
+ self.partial_cmp(other)
+ .expect("LogKeySet comparison failed, possibly due to empty set")
+ }
}
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -284,6 +368,14 @@ pub fn escape_bytes(buf: &[u8]) -> Vec<u8> {
result
}
+/// A path to a log segment file along with its type
+pub enum SegmentPath {
+ /// A symbolic link to the active log file
+ ActiveSymlink(String),
+ /// A compacted segment that is no longer being written to
+ Compacted(String),
+}
+
pub fn is_file_same_as_path(file: &File, path: &PathBuf) -> io::Result<bool> {
// Get the metadata for the open file handle
let file_metadata = file.metadata()?;
@@ -306,3 +398,15 @@ pub fn is_file_same_as_path(file: &File, path: &PathBuf) -> io::Result<bool> {
&& file_metadata.volume_serial_number() == path_metadata.volume_serial_number())
}
}
+
+pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+ #[cfg(unix)]
+ {
+ std::os::unix::fs::symlink(original, link)
+ }
+
+ #[cfg(windows)]
+ {
+ std::os::windows::fs::symlink_file(original, link)
+ }
+}