mod local;
mod rocksdb;
mod split;
mod tracking;
pub use self::rocksdb::RocksDBFileSystem;
pub use local::LocalFileSystem;
pub use split::SplitFileSystem;
pub use tracking::TrackingFileSystem;
#[cfg(feature = "opendal")]
mod opendal;
#[cfg(feature = "opendal")]
pub use self::opendal::OpenDALFileSystem;
use super::{time, FileFlags, FileId};
use crate::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::sync::Arc;
type ArcRawFileSystem = Arc<dyn RawFileSystem + Send + Sync>;
pub trait RawFileSystem {
fn open(&self, id: FileId, flags: FileFlags) -> Result<Box<dyn RawFile + Send + Sync>>;
fn create(&self, id: FileId) -> Result<()>;
fn exists(&self, id: FileId) -> Result<bool>;
fn unlink(&self, id: FileId) -> Result<()>;
fn stat(&self, _id: FileId) -> Result<RawFileMeta> {
panic!(
"This filesystem does not support stat. You should wrap it in a TrackingFileSystem."
)
}
fn write(&self, id: FileId, data: &[u8]) -> Result<()> {
self.open(id, FileFlags::WRITE | FileFlags::TRUNCATE)?
.write_block(data, data.len(), 0)
}
}
pub trait RawFile {
fn read_block(&self, data: &mut [u8], block: u64) -> Result<u64>;
fn write_block(&mut self, data: &[u8], block_end: usize, block: u64) -> Result<()>;
fn set_len(&mut self, len: u64, block_size: u64) -> Result<()>;
fn set_metadata(&self, _meta: RawFileMeta) -> Result<()> {
panic!("This filesystem does not support persisting metadata. You should wrap it in a TrackingFileSystem.");
}
fn metadata(&self) -> Result<RawFileMeta> {
unimplemented!()
}
}
impl RawFileSystem for ArcRawFileSystem {
fn open(&self, id: FileId, flags: FileFlags) -> Result<Box<dyn RawFile + Send + Sync>> {
self.as_ref().open(id, flags)
}
fn create(&self, id: FileId) -> Result<()> {
self.as_ref().create(id)
}
fn exists(&self, id: FileId) -> Result<bool> {
self.as_ref().exists(id)
}
fn unlink(&self, id: FileId) -> Result<()> {
self.as_ref().unlink(id)
}
fn stat(&self, id: FileId) -> Result<RawFileMeta> {
self.as_ref().stat(id)
}
fn write(&self, id: FileId, data: &[u8]) -> Result<()> {
self.as_ref().write(id, data)
}
}
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
pub struct RawFileMeta {
pub size: u64,
#[serde(with = "time::opt_compact_date_time")]
pub accessed: Option<DateTime<Utc>>,
#[serde(with = "time::opt_compact_date_time")]
pub modified: Option<DateTime<Utc>>,
}
impl RawFileMeta {
pub fn create() -> Self {
let now = Utc::now();
Self {
size: 0,
accessed: Some(now),
modified: Some(now),
}
}
pub fn from_std(meta: std::fs::Metadata) -> Self {
Self {
size: meta.len(),
accessed: meta
.accessed()
.ok()
.as_ref()
.map(time::system_time_to_date_time),
modified: meta
.modified()
.ok()
.as_ref()
.map(time::system_time_to_date_time),
}
}
#[cfg(feature = "opendal")]
pub fn from_opendal(meta: ::opendal::Metadata) -> Self {
Self {
size: meta.content_length(),
accessed: None,
modified: meta.last_modified(),
}
}
}
fn write_vec_at(vec: &mut Vec<u8>, data: &[u8], block_end: usize, block: u64) {
let offset = data.len() * block as usize;
if offset > vec.len() {
vec.resize(offset + block_end, 0);
}
vec[offset..offset + block_end].copy_from_slice(data);
}