mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-10 07:06:53 +00:00
merge versioning, fix bug todo
This commit is contained in:
@@ -260,6 +260,17 @@ pub fn os_err_to_file_err(e: io::Error) -> Error {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_err_file_not_found(err: &Error) -> bool {
|
||||
if let Some(e) = err.downcast_ref::<DiskError>() {
|
||||
match e {
|
||||
DiskError::FileNotFound => true,
|
||||
_ => false,
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_sys_err_no_space(e: &io::Error) -> bool {
|
||||
if let Some(no) = e.raw_os_error() {
|
||||
return no == 28;
|
||||
|
||||
+47
-28
@@ -1,4 +1,6 @@
|
||||
use super::error::{is_sys_err_io, is_sys_err_not_empty, is_sys_err_too_many_files, os_is_not_exist, os_is_permission};
|
||||
use super::error::{
|
||||
is_err_file_not_found, is_sys_err_io, is_sys_err_not_empty, is_sys_err_too_many_files, os_is_not_exist, os_is_permission,
|
||||
};
|
||||
use super::os::is_root_disk;
|
||||
use super::{endpoint::Endpoint, error::DiskError, format::FormatV3};
|
||||
use super::{
|
||||
@@ -16,17 +18,21 @@ use crate::disk::os::check_path_length;
|
||||
use crate::disk::{LocalFileReader, LocalFileWriter, STORAGE_FORMAT_FILE};
|
||||
use crate::error::{Error, Result};
|
||||
use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold};
|
||||
use crate::set_disk::{conv_part_err_to_int, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS, CHECK_PART_UNKNOWN, CHECK_PART_VOLUME_NOT_FOUND};
|
||||
use crate::set_disk::{
|
||||
conv_part_err_to_int, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS, CHECK_PART_UNKNOWN,
|
||||
CHECK_PART_VOLUME_NOT_FOUND,
|
||||
};
|
||||
use crate::store_api::BitrotAlgorithm;
|
||||
use crate::utils::fs::{access, lstat, O_APPEND, O_CREATE, O_RDONLY, O_WRONLY};
|
||||
use crate::utils::os::get_info;
|
||||
use crate::utils::path::{clean, has_suffix, SLASH_SEPARATOR};
|
||||
use crate::utils::path::{clean, has_suffix, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR};
|
||||
use crate::{
|
||||
file_meta::FileMeta,
|
||||
store_api::{FileInfo, RawFileInfo},
|
||||
utils,
|
||||
};
|
||||
use path_absolutize::Absolutize;
|
||||
use std::collections::HashSet;
|
||||
use std::fmt::Debug;
|
||||
use std::io::Cursor;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
@@ -411,7 +417,7 @@ impl LocalDisk {
|
||||
async fn read_metadata_with_dmtime(&self, file_path: impl AsRef<Path>) -> Result<(Vec<u8>, Option<OffsetDateTime>)> {
|
||||
check_path_length(file_path.as_ref().to_string_lossy().as_ref())?;
|
||||
|
||||
let mut f = utils::fs::open_file(file_path, O_RDONLY).await?;
|
||||
let mut f = utils::fs::open_file(file_path.as_ref(), O_RDONLY).await?;
|
||||
|
||||
let meta = f.metadata().await?;
|
||||
|
||||
@@ -682,7 +688,7 @@ pub async fn read_file_exists(path: impl AsRef<Path>) -> Result<(Vec<u8>, Option
|
||||
let (data, meta) = match read_file_all(&p).await {
|
||||
Ok((data, meta)) => (data, Some(meta)),
|
||||
Err(e) => {
|
||||
if DiskError::FileNotFound.is(&e) {
|
||||
if is_err_file_not_found(&e) {
|
||||
(Vec::new(), None)
|
||||
} else {
|
||||
return Err(e);
|
||||
@@ -939,7 +945,7 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
|
||||
resp.results[i] = CHECK_PART_SUCCESS;
|
||||
},
|
||||
}
|
||||
Err(err) => {
|
||||
match os_err_to_file_err(err).downcast_ref() {
|
||||
Some(DiskError::FileNotFound) => {
|
||||
@@ -949,20 +955,20 @@ impl DiskAPI for LocalDisk {
|
||||
ErrorKind::NotFound => {
|
||||
resp.results[i] = CHECK_PART_VOLUME_NOT_FOUND;
|
||||
continue;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
resp.results[i] = CHECK_PART_FILE_NOT_FOUND;
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
@@ -1229,7 +1235,7 @@ impl DiskAPI for LocalDisk {
|
||||
let entries = match os::read_dir(&dir_path_abs, count).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if DiskError::FileNotFound.is(&e) && !skip_access_checks(volume) {
|
||||
if is_err_file_not_found(&e) && !skip_access_checks(volume) {
|
||||
if let Err(e) = utils::fs::access(&volume_dir).await {
|
||||
return Err(convert_access_error(e, DiskError::VolumeAccessDenied));
|
||||
}
|
||||
@@ -1246,12 +1252,12 @@ impl DiskAPI for LocalDisk {
|
||||
let mut entries = match self.list_dir("", &opts.bucket, &opts.base_dir, -1).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => {
|
||||
if !DiskError::VolumeNotFound.is(&e) && !DiskError::FileNotFound.is(&e) {
|
||||
if !DiskError::VolumeNotFound.is(&e) && !is_err_file_not_found(&e) {
|
||||
error!("list_dir err {:?}", &e);
|
||||
}
|
||||
|
||||
if opts.report_notfound && DiskError::FileNotFound.is(&e) {
|
||||
return Err(Error::new(DiskError::FileNotFound));
|
||||
if opts.report_notfound && is_err_file_not_found(&e) {
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
@@ -1270,6 +1276,8 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
let mut metas = Vec::new();
|
||||
|
||||
let mut dir_objes = HashSet::new();
|
||||
|
||||
// 第一层过滤
|
||||
for entry in entries.iter() {
|
||||
// check limit
|
||||
@@ -1283,14 +1291,24 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
// warn!("walk_dir entry {}", entry);
|
||||
|
||||
let mut meta = MetaCacheEntry {
|
||||
name: entry.clone(),
|
||||
..Default::default()
|
||||
};
|
||||
let mut meta = MetaCacheEntry { ..Default::default() };
|
||||
|
||||
let fpath = self.get_object_path(bucket, format!("{}/{}", &meta.name, STORAGE_FORMAT_FILE).as_str())?;
|
||||
let fpath = self.get_object_path(bucket, format!("{}/{}", &entry, STORAGE_FORMAT_FILE).as_str())?;
|
||||
|
||||
meta.metadata = self.read_metadata(&fpath).await.unwrap_or_default();
|
||||
if let Ok(data) = self.read_metadata(&fpath).await {
|
||||
meta.metadata = data;
|
||||
}
|
||||
|
||||
let mut name = entry.clone();
|
||||
if name.ends_with(SLASH_SEPARATOR) {
|
||||
if name.ends_with(GLOBAL_DIR_SUFFIX_WITH_SLASH) {
|
||||
name = format!("{}{}", name.as_str().trim_end_matches(GLOBAL_DIR_SUFFIX_WITH_SLASH), SLASH_SEPARATOR);
|
||||
dir_objes.insert(name.clone());
|
||||
} else {
|
||||
name = name.as_str().trim_end_matches(SLASH_SEPARATOR).to_owned();
|
||||
}
|
||||
}
|
||||
meta.name = name;
|
||||
|
||||
metas.push(meta);
|
||||
}
|
||||
@@ -1535,7 +1553,7 @@ impl DiskAPI for LocalDisk {
|
||||
let mut volumes = Vec::new();
|
||||
|
||||
let entries = os::read_dir(&self.root, -1).await.map_err(|e| {
|
||||
if DiskError::FileAccessDenied.is(&e) || DiskError::FileNotFound.is(&e) {
|
||||
if DiskError::FileAccessDenied.is(&e) || is_err_file_not_found(&e) {
|
||||
Error::new(DiskError::DiskAccessDenied)
|
||||
} else {
|
||||
e
|
||||
@@ -1543,7 +1561,7 @@ impl DiskAPI for LocalDisk {
|
||||
})?;
|
||||
|
||||
for entry in entries {
|
||||
if !utils::path::has_suffix(&entry, SLASH_SEPARATOR) || !Self::is_valid_volname(&entry) {
|
||||
if !utils::path::has_suffix(&entry, SLASH_SEPARATOR) || !Self::is_valid_volname(utils::path::clean(&entry).as_str()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1600,7 +1618,7 @@ impl DiskAPI for LocalDisk {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: UpdateMetadataOpts) -> Result<()> {
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: &UpdateMetadataOpts) -> Result<()> {
|
||||
if fi.metadata.is_some() {
|
||||
let volume_dir = self.get_bucket_path(volume)?;
|
||||
let file_path = volume_dir.join(Path::new(&path));
|
||||
@@ -1611,7 +1629,7 @@ impl DiskAPI for LocalDisk {
|
||||
.read_all(volume, format!("{}/{}", &path, super::STORAGE_FORMAT_FILE).as_str())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if DiskError::FileNotFound.is(&e) && fi.version_id.is_some() {
|
||||
if is_err_file_not_found(&e) && fi.version_id.is_some() {
|
||||
Error::new(DiskError::FileVersionNotFound)
|
||||
} else {
|
||||
e
|
||||
@@ -1665,6 +1683,7 @@ impl DiskAPI for LocalDisk {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self))]
|
||||
async fn read_version(
|
||||
&self,
|
||||
_org_volume: &str,
|
||||
@@ -1683,7 +1702,7 @@ impl DiskAPI for LocalDisk {
|
||||
let mut meta = FileMeta::default();
|
||||
meta.unmarshal_msg(&data)?;
|
||||
|
||||
let fi = meta.into_fileinfo(volume, path, version_id, false, true)?;
|
||||
let fi = meta.into_fileinfo(volume, path, version_id, read_data, true)?;
|
||||
Ok(fi)
|
||||
}
|
||||
async fn read_xl(&self, volume: &str, path: &str, read_data: bool) -> Result<RawFileInfo> {
|
||||
@@ -1770,7 +1789,7 @@ impl DiskAPI for LocalDisk {
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if !(DiskError::FileNotFound.is(&e) || DiskError::VolumeNotFound.is(&e)) {
|
||||
if !(is_err_file_not_found(&e) || DiskError::VolumeNotFound.is(&e)) {
|
||||
res.exists = true;
|
||||
res.error = e.to_string();
|
||||
}
|
||||
@@ -1827,7 +1846,7 @@ async fn get_disk_info(drive_path: PathBuf) -> Result<(Info, bool)> {
|
||||
let drive_path = drive_path.to_string_lossy().to_string();
|
||||
check_path_length(&drive_path)?;
|
||||
|
||||
let disk_info = get_info(&drive_path, false)?;
|
||||
let disk_info = get_info(&drive_path)?;
|
||||
let root_drive = if !*GLOBAL_IsErasureSD.read().await {
|
||||
let root_disk_threshold = *GLOBAL_RootDiskThreshold.read().await;
|
||||
if root_disk_threshold > 0 {
|
||||
|
||||
+14
-4
@@ -19,7 +19,6 @@ use crate::{
|
||||
file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion},
|
||||
store_api::{FileInfo, RawFileInfo},
|
||||
};
|
||||
|
||||
use endpoint::Endpoint;
|
||||
use futures::StreamExt;
|
||||
use protos::proto_gen::node_service::{
|
||||
@@ -35,6 +34,7 @@ use tokio::{
|
||||
};
|
||||
use tokio_stream::wrappers::ReceiverStream;
|
||||
use tonic::{service::interceptor::InterceptedService, transport::Channel, Request, Status, Streaming};
|
||||
use tracing::error;
|
||||
use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -96,7 +96,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static {
|
||||
) -> Result<Vec<Option<Error>>>;
|
||||
async fn delete_paths(&self, volume: &str, paths: &[&str]) -> Result<()>;
|
||||
async fn write_metadata(&self, org_volume: &str, volume: &str, path: &str, fi: FileInfo) -> Result<()>;
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: UpdateMetadataOpts) -> Result<()>;
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: &UpdateMetadataOpts) -> Result<()>;
|
||||
async fn read_version(
|
||||
&self,
|
||||
org_volume: &str,
|
||||
@@ -143,7 +143,7 @@ pub struct CheckPartsResp {
|
||||
pub results: Vec<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[derive(Debug, Serialize, Deserialize, Default)]
|
||||
pub struct UpdateMetadataOpts {
|
||||
pub no_persistence: bool,
|
||||
}
|
||||
@@ -597,7 +597,7 @@ pub struct VolumeInfo {
|
||||
pub created: Option<OffsetDateTime>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct ReadOptions {
|
||||
pub read_data: bool,
|
||||
pub healing: bool,
|
||||
@@ -644,6 +644,7 @@ pub struct ReadOptions {
|
||||
pub enum FileWriter {
|
||||
Local(LocalFileWriter),
|
||||
Remote(RemoteFileWriter),
|
||||
Buffer(Vec<u8>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -656,6 +657,10 @@ impl Write for FileWriter {
|
||||
match self {
|
||||
Self::Local(local_file_writer) => local_file_writer.write(buf).await,
|
||||
Self::Remote(remote_file_writer) => remote_file_writer.write(buf).await,
|
||||
Self::Buffer(buffer) => {
|
||||
buffer.extend_from_slice(buf);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -773,6 +778,7 @@ impl Write for RemoteFileWriter {
|
||||
pub enum FileReader {
|
||||
Local(LocalFileReader),
|
||||
Remote(RemoteFileReader),
|
||||
Buffer(Vec<u8>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
@@ -781,6 +787,10 @@ impl ReadAt for FileReader {
|
||||
match self {
|
||||
Self::Local(local_file_writer) => local_file_writer.read_at(offset, length).await,
|
||||
Self::Remote(remote_file_writer) => remote_file_writer.read_at(offset, length).await,
|
||||
Self::Buffer(buffer) => {
|
||||
let s = &buffer[offset..offset + length];
|
||||
Ok((s.to_vec(), s.len()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+21
-18
@@ -56,7 +56,7 @@ pub fn is_root_disk(disk_path: &str, root_disk: &str) -> Result<bool> {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
same_disk(disk_path, root_disk)
|
||||
Ok(same_disk(disk_path, root_disk)?)
|
||||
}
|
||||
|
||||
pub async fn make_dir_all(path: impl AsRef<Path>, base_dir: impl AsRef<Path>) -> Result<()> {
|
||||
@@ -90,13 +90,14 @@ pub async fn read_dir(path: impl AsRef<Path>, count: i32) -> Result<Vec<String>>
|
||||
|
||||
let file_type = entry.file_type().await?;
|
||||
|
||||
if file_type.is_dir() {
|
||||
count -= 1;
|
||||
if file_type.is_file() {
|
||||
volumes.push(name);
|
||||
} else if file_type.is_dir() {
|
||||
volumes.push(format!("{}{}", name, utils::path::SLASH_SEPARATOR));
|
||||
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count -= 1;
|
||||
if count == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,17 +109,19 @@ pub async fn rename_all(
|
||||
dst_file_path: impl AsRef<Path>,
|
||||
base_dir: impl AsRef<Path>,
|
||||
) -> Result<()> {
|
||||
reliable_rename(src_file_path, dst_file_path, base_dir).await.map_err(|e| {
|
||||
if is_sys_err_not_dir(&e) || !os_is_not_exist(&e) || is_sys_err_path_not_found(&e) {
|
||||
Error::new(DiskError::FileAccessDenied)
|
||||
} else if os_is_not_exist(&e) {
|
||||
Error::new(DiskError::FileNotFound)
|
||||
} else if os_is_exist(&e) {
|
||||
Error::new(DiskError::IsNotRegular)
|
||||
} else {
|
||||
Error::new(e)
|
||||
}
|
||||
})?;
|
||||
reliable_rename(src_file_path, dst_file_path.as_ref(), base_dir)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
if is_sys_err_not_dir(&e) || !os_is_not_exist(&e) || is_sys_err_path_not_found(&e) {
|
||||
Error::new(DiskError::FileAccessDenied)
|
||||
} else if os_is_not_exist(&e) {
|
||||
Error::new(DiskError::FileNotFound)
|
||||
} else if os_is_exist(&e) {
|
||||
Error::new(DiskError::IsNotRegular)
|
||||
} else {
|
||||
Error::new(e)
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ use futures::lock::Mutex;
|
||||
use protos::{
|
||||
node_service_time_out_client,
|
||||
proto_gen::node_service::{
|
||||
CheckPartsRequest, DeletePathsRequest, DeleteRequest, DeleteVersionRequest, DeleteVersionsRequest, DeleteVolumeRequest, DiskInfoRequest, ListDirRequest, ListVolumesRequest, MakeVolumeRequest, MakeVolumesRequest, ReadAllRequest, ReadMultipleRequest, ReadVersionRequest, ReadXlRequest, RenameDataRequest, RenameFileRequst, StatVolumeRequest, UpdateMetadataRequest, VerifyFileRequest, WalkDirRequest, WriteAllRequest, WriteMetadataRequest
|
||||
CheckPartsRequest, DeletePathsRequest, DeleteRequest, DeleteVersionRequest, DeleteVersionsRequest, DeleteVolumeRequest,
|
||||
DiskInfoRequest, ListDirRequest, ListVolumesRequest, MakeVolumeRequest, MakeVolumesRequest, ReadAllRequest,
|
||||
ReadMultipleRequest, ReadVersionRequest, ReadXlRequest, RenameDataRequest, RenameFileRequst, StatVolumeRequest,
|
||||
UpdateMetadataRequest, VerifyFileRequest, WalkDirRequest, WriteAllRequest, WriteMetadataRequest,
|
||||
},
|
||||
};
|
||||
use tonic::Request;
|
||||
@@ -12,7 +15,9 @@ use tracing::info;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{
|
||||
endpoint::Endpoint, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskOption, FileInfoVersions, FileReader, FileWriter, MetaCacheEntry, ReadMultipleReq, ReadMultipleResp, ReadOptions, RemoteFileReader, RemoteFileWriter, RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions
|
||||
endpoint::Endpoint, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskOption,
|
||||
FileInfoVersions, FileReader, FileWriter, MetaCacheEntry, ReadMultipleReq, ReadMultipleResp, ReadOptions, RemoteFileReader,
|
||||
RemoteFileWriter, RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions,
|
||||
};
|
||||
use crate::{
|
||||
disk::error::DiskError,
|
||||
@@ -110,7 +115,7 @@ impl DiskAPI for RemoteDisk {
|
||||
info!("read_all success");
|
||||
|
||||
if !response.success {
|
||||
return Err(DiskError::FileNotFound.into());
|
||||
return Err(Error::new(DiskError::FileNotFound));
|
||||
}
|
||||
|
||||
Ok(response.data)
|
||||
@@ -479,7 +484,7 @@ impl DiskAPI for RemoteDisk {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: UpdateMetadataOpts) -> Result<()> {
|
||||
async fn update_metadata(&self, volume: &str, path: &str, fi: FileInfo, opts: &UpdateMetadataOpts) -> Result<()> {
|
||||
info!("update_metadata");
|
||||
let file_info = serde_json::to_string(&fi)?;
|
||||
let opts = serde_json::to_string(&opts)?;
|
||||
|
||||
Reference in New Issue
Block a user