pub mod endpoint; pub mod error; pub mod format; mod local; pub const RUSTFS_META_BUCKET: &str = ".rustfs.sys"; pub const RUSTFS_META_MULTIPART_BUCKET: &str = ".rustfs.sys/multipart"; pub const RUSTFS_META_TMP_BUCKET: &str = ".rustfs.sys/tmp"; pub const RUSTFS_META_TMP_DELETED_BUCKET: &str = ".rustfs.sys/tmp/.trash"; pub const BUCKET_META_PREFIX: &str = "buckets"; pub const FORMAT_CONFIG_FILE: &str = "format.json"; const STORAGE_FORMAT_FILE: &str = "xl.meta"; use crate::{ erasure::ReadAt, error::Result, store_api::{FileInfo, RawFileInfo}, }; use bytes::Bytes; use std::{fmt::Debug, io::SeekFrom, pin::Pin, sync::Arc}; use time::OffsetDateTime; use tokio::{ fs::File, io::{AsyncReadExt, AsyncSeekExt, AsyncWrite}, }; use uuid::Uuid; pub type DiskStore = Arc>; pub async fn new_disk(ep: &endpoint::Endpoint, opt: &DiskOption) -> Result { if ep.is_local { let s = local::LocalDisk::new(ep, opt.cleanup).await?; Ok(Arc::new(Box::new(s))) } else { let _ = opt.health_check; unimplemented!() } } #[async_trait::async_trait] pub trait DiskAPI: Debug + Send + Sync + 'static { fn is_local(&self) -> bool; fn id(&self) -> Uuid; async fn delete(&self, volume: &str, path: &str, opt: DeleteOptions) -> Result<()>; async fn read_all(&self, volume: &str, path: &str) -> Result; async fn write_all(&self, volume: &str, path: &str, data: Vec) -> Result<()>; async fn rename_file(&self, src_volume: &str, src_path: &str, dst_volume: &str, dst_path: &str) -> Result<()>; async fn create_file(&self, origvolume: &str, volume: &str, path: &str, file_size: usize) -> Result; async fn append_file(&self, volume: &str, path: &str) -> Result; async fn read_file(&self, volume: &str, path: &str) -> Result; // 读目录下的所有文件、目录 async fn list_dir(&self, origvolume: &str, volume: &str, dir_path: &str, count: usize) -> Result>; // 读目录下的所有xl.meta async fn walk_dir(&self) -> Result>; async fn rename_data( &self, src_volume: &str, src_path: &str, file_info: FileInfo, dst_volume: &str, dst_path: &str, ) -> Result; async fn make_volumes(&self, volume: Vec<&str>) -> Result<()>; async fn delete_volume(&self, volume: &str) -> Result<()>; async fn list_volumes(&self) -> Result>; async fn make_volume(&self, volume: &str) -> Result<()>; async fn stat_volume(&self, volume: &str) -> Result; async fn write_metadata(&self, org_volume: &str, volume: &str, path: &str, fi: FileInfo) -> Result<()>; async fn read_version( &self, org_volume: &str, volume: &str, path: &str, version_id: &str, opts: &ReadOptions, ) -> Result; async fn read_xl(&self, volume: &str, path: &str, read_data: bool) -> Result; async fn read_multiple(&self, req: ReadMultipleReq) -> Result>; } pub struct DiskOption { pub cleanup: bool, pub health_check: bool, } pub struct RenameDataResp { pub old_data_dir: String, } #[derive(Debug, Clone, Default)] pub struct DeleteOptions { pub recursive: bool, pub immediate: bool, } #[derive(Debug, Clone)] pub struct ReadMultipleReq { pub bucket: String, pub prefix: String, pub files: Vec, pub max_size: usize, pub metadata_only: bool, pub abort404: bool, pub max_results: usize, } #[derive(Debug, Clone)] pub struct ReadMultipleResp { pub bucket: String, pub prefix: String, pub file: String, pub exists: bool, pub error: String, pub data: Vec, pub mod_time: OffsetDateTime, } impl Default for ReadMultipleResp { fn default() -> Self { Self { bucket: String::new(), prefix: String::new(), file: String::new(), exists: false, error: String::new(), data: Vec::new(), mod_time: OffsetDateTime::UNIX_EPOCH, } } } pub struct VolumeInfo { pub name: String, pub created: OffsetDateTime, } pub struct ReadOptions { pub read_data: bool, pub healing: bool, } pub struct FileWriter { pub inner: Pin>, } impl AsyncWrite for FileWriter { fn poll_write( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, buf: &[u8], ) -> std::task::Poll> { Pin::new(&mut self.inner).poll_write(cx, buf) } fn poll_flush( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { Pin::new(&mut self.inner).poll_flush(cx) } fn poll_shutdown( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { Pin::new(&mut self.inner).poll_shutdown(cx) } } impl FileWriter { pub fn new(inner: W) -> Self where W: AsyncWrite + Send + Sync + 'static, { Self { inner: Box::pin(inner) } } } #[derive(Debug)] pub struct FileReader { pub inner: File, } impl FileReader { pub fn new(inner: File) -> Self { Self { inner } } } impl ReadAt for FileReader { async fn read_at(&mut self, offset: usize, length: usize) -> Result<(Vec, usize)> { self.inner.seek(SeekFrom::Start(offset as u64)).await?; let mut buffer = vec![0; length]; let bytes_read = self.inner.read(&mut buffer).await?; buffer.truncate(bytes_read); Ok((buffer, bytes_read)) } }