85 lines
2.4 KiB
Rust
85 lines
2.4 KiB
Rust
|
use std::{
|
||
|
env::temp_dir,
|
||
|
path::{Path, PathBuf},
|
||
|
time::{SystemTime, UNIX_EPOCH},
|
||
|
};
|
||
|
|
||
|
use anyhow::Context;
|
||
|
use tokio::io::AsyncWriteExt;
|
||
|
|
||
|
pub struct StorageBackend {
|
||
|
location: PathBuf,
|
||
|
}
|
||
|
|
||
|
impl StorageBackend {
|
||
|
pub fn new(location: &Path) -> Self {
|
||
|
Self {
|
||
|
location: location.into(),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pub fn temp() -> Self {
|
||
|
Self::new(&temp_dir().join("nodata"))
|
||
|
}
|
||
|
|
||
|
pub async fn flush_segment(&self, topic: &str, buffer: &[u8]) -> anyhow::Result<String> {
|
||
|
let segment_key = uuid::Uuid::now_v7();
|
||
|
let segment_path = PathBuf::from("logs")
|
||
|
.join(topic)
|
||
|
.join(segment_key.to_string());
|
||
|
tracing::trace!("writing segment file: {}", segment_path.display());
|
||
|
let file_location = self.location.join(&segment_path);
|
||
|
if let Some(parent) = file_location.parent() {
|
||
|
tokio::fs::create_dir_all(parent)
|
||
|
.await
|
||
|
.context("failed to create storage backend dir")?;
|
||
|
}
|
||
|
|
||
|
let mut segment_file = tokio::fs::File::create(&file_location).await?;
|
||
|
segment_file.write_all(buffer).await?;
|
||
|
segment_file.flush().await?;
|
||
|
|
||
|
Ok(segment_key.to_string())
|
||
|
}
|
||
|
|
||
|
pub async fn append_index(
|
||
|
&self,
|
||
|
topic: &str,
|
||
|
segment_file: &str,
|
||
|
time: SystemTime,
|
||
|
) -> anyhow::Result<()> {
|
||
|
let index_path = PathBuf::from("indexes").join(topic);
|
||
|
tracing::trace!("writing index file: {}", index_path.display());
|
||
|
let file_location = self.location.join(&index_path);
|
||
|
if let Some(parent) = file_location.parent() {
|
||
|
tokio::fs::create_dir_all(parent)
|
||
|
.await
|
||
|
.context("failed to create storage backend dir, index")?;
|
||
|
}
|
||
|
|
||
|
if !file_location.exists() {
|
||
|
tokio::fs::File::create(&file_location).await?;
|
||
|
}
|
||
|
|
||
|
let mut index_file = tokio::fs::File::options()
|
||
|
.append(true)
|
||
|
.open(&file_location)
|
||
|
.await?;
|
||
|
index_file
|
||
|
.write_all(
|
||
|
format!(
|
||
|
"{},{}\n",
|
||
|
time.duration_since(UNIX_EPOCH)
|
||
|
.expect("to be able to get time")
|
||
|
.as_secs(),
|
||
|
segment_file
|
||
|
)
|
||
|
.as_bytes(),
|
||
|
)
|
||
|
.await?;
|
||
|
index_file.flush().await?;
|
||
|
|
||
|
Ok(())
|
||
|
}
|
||
|
}
|