mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 15:37:02 +00:00
add disk.delete_version
This commit is contained in:
+82
-10
@@ -1,12 +1,12 @@
|
|||||||
use super::error::{
|
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,
|
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::os::{is_root_disk, rename_all};
|
||||||
use super::{endpoint::Endpoint, error::DiskError, format::FormatV3};
|
use super::{endpoint::Endpoint, error::DiskError, format::FormatV3};
|
||||||
use super::{
|
use super::{
|
||||||
os, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskMetrics, FileInfoVersions,
|
os, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskMetrics, FileInfoVersions,
|
||||||
FileReader, FileWriter, Info, MetaCacheEntry, ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp,
|
FileReader, FileWriter, Info, MetaCacheEntry, ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp,
|
||||||
UpdateMetadataOpts, VolumeInfo, WalkDirOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET,
|
UpdateMetadataOpts, VolumeInfo, WalkDirOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET, STORAGE_FORMAT_FILE_BACKUP,
|
||||||
};
|
};
|
||||||
use crate::bitrot::bitrot_verify;
|
use crate::bitrot::bitrot_verify;
|
||||||
use crate::bucket::metadata_sys::GLOBAL_BucketMetadataSys;
|
use crate::bucket::metadata_sys::GLOBAL_BucketMetadataSys;
|
||||||
@@ -1760,16 +1760,88 @@ impl DiskAPI for LocalDisk {
|
|||||||
async fn delete_version(
|
async fn delete_version(
|
||||||
&self,
|
&self,
|
||||||
volume: &str,
|
volume: &str,
|
||||||
_path: &str,
|
path: &str,
|
||||||
_fi: FileInfo,
|
fi: FileInfo,
|
||||||
_force_del_marker: bool,
|
force_del_marker: bool,
|
||||||
_opts: DeleteOptions,
|
opts: DeleteOptions,
|
||||||
) -> Result<RawFileInfo> {
|
) -> Result<()> {
|
||||||
let _volume_dir = self.get_bucket_path(volume)?;
|
if path.starts_with(SLASH_SEPARATOR) {
|
||||||
|
return self
|
||||||
|
.delete(
|
||||||
|
volume,
|
||||||
|
path,
|
||||||
|
DeleteOptions {
|
||||||
|
recursive: false,
|
||||||
|
immediate: false,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
// self.read_all_data(bucket, volume_dir, path);
|
let volume_dir = self.get_bucket_path(volume)?;
|
||||||
|
|
||||||
unimplemented!()
|
let file_path = volume_dir.join(Path::new(&path));
|
||||||
|
|
||||||
|
check_path_length(file_path.to_string_lossy().as_ref())?;
|
||||||
|
|
||||||
|
let xl_path = file_path.join(Path::new(STORAGE_FORMAT_FILE));
|
||||||
|
let buf = match self.read_all_data(volume, &volume_dir, &xl_path).await {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(err) => {
|
||||||
|
//
|
||||||
|
if !is_err_file_not_found(&err) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.deleted && force_del_marker {
|
||||||
|
return self.write_metadata("", volume, path, fi).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if fi.version_id.is_some() {
|
||||||
|
return Err(Error::new(DiskError::FileVersionNotFound));
|
||||||
|
} else {
|
||||||
|
return Err(Error::new(DiskError::FileNotFound));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut meta = FileMeta::load(&buf)?;
|
||||||
|
let old_dir = meta.delete_version(&fi)?;
|
||||||
|
|
||||||
|
if let Some(uuid) = old_dir {
|
||||||
|
let vid = fi.version_id.unwrap_or(Uuid::nil());
|
||||||
|
let _ = meta.data.remove(vec![vid, uuid])?;
|
||||||
|
|
||||||
|
let old_path = file_path.join(Path::new(uuid.to_string().as_str()));
|
||||||
|
check_path_length(old_path.to_string_lossy().as_ref())?;
|
||||||
|
|
||||||
|
if let Err(err) = self.move_to_trash(&old_path, true, false).await {
|
||||||
|
if !is_err_file_not_found(&err) {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !meta.versions.is_empty() {
|
||||||
|
let buf = meta.marshal_msg()?;
|
||||||
|
return self
|
||||||
|
.write_all_meta(volume, format!("{}{}{}", path, SLASH_SEPARATOR, STORAGE_FORMAT_FILE).as_str(), &buf, true)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
// opts.undo_write && opts.old_data_dir.is_some_and(f)
|
||||||
|
if let Some(old_data_dir) = opts.old_data_dir {
|
||||||
|
if opts.undo_write {
|
||||||
|
let src_path = file_path.join(Path::new(
|
||||||
|
format!("{}{}{}", old_data_dir.to_string(), SLASH_SEPARATOR, STORAGE_FORMAT_FILE_BACKUP).as_str(),
|
||||||
|
));
|
||||||
|
let dst_path = file_path.join(Path::new(format!("{}{}{}", path, SLASH_SEPARATOR, STORAGE_FORMAT_FILE).as_str()));
|
||||||
|
return rename_all(src_path, dst_path, file_path).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.delete_file(&volume_dir, &xl_path, true, false).await
|
||||||
}
|
}
|
||||||
async fn delete_versions(
|
async fn delete_versions(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ pub const RUSTFS_META_TMP_BUCKET: &str = ".rustfs.sys/tmp";
|
|||||||
pub const RUSTFS_META_TMP_DELETED_BUCKET: &str = ".rustfs.sys/tmp/.trash";
|
pub const RUSTFS_META_TMP_DELETED_BUCKET: &str = ".rustfs.sys/tmp/.trash";
|
||||||
pub const BUCKET_META_PREFIX: &str = "buckets";
|
pub const BUCKET_META_PREFIX: &str = "buckets";
|
||||||
pub const FORMAT_CONFIG_FILE: &str = "format.json";
|
pub const FORMAT_CONFIG_FILE: &str = "format.json";
|
||||||
const STORAGE_FORMAT_FILE: &str = "xl.meta";
|
pub const STORAGE_FORMAT_FILE: &str = "xl.meta";
|
||||||
|
pub const STORAGE_FORMAT_FILE_BACKUP: &str = "xl.meta.bkp";
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
erasure::Writer,
|
erasure::Writer,
|
||||||
@@ -303,7 +304,7 @@ impl DiskAPI for Disk {
|
|||||||
fi: FileInfo,
|
fi: FileInfo,
|
||||||
force_del_marker: bool,
|
force_del_marker: bool,
|
||||||
opts: DeleteOptions,
|
opts: DeleteOptions,
|
||||||
) -> Result<RawFileInfo> {
|
) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Disk::Local(local_disk) => local_disk.delete_version(volume, path, fi, force_del_marker, opts).await,
|
Disk::Local(local_disk) => local_disk.delete_version(volume, path, fi, force_del_marker, opts).await,
|
||||||
Disk::Remote(remote_disk) => remote_disk.delete_version(volume, path, fi, force_del_marker, opts).await,
|
Disk::Remote(remote_disk) => remote_disk.delete_version(volume, path, fi, force_del_marker, opts).await,
|
||||||
@@ -409,7 +410,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static {
|
|||||||
fi: FileInfo,
|
fi: FileInfo,
|
||||||
force_del_marker: bool,
|
force_del_marker: bool,
|
||||||
opts: DeleteOptions,
|
opts: DeleteOptions,
|
||||||
) -> Result<RawFileInfo>;
|
) -> Result<()>;
|
||||||
async fn delete_versions(
|
async fn delete_versions(
|
||||||
&self,
|
&self,
|
||||||
volume: &str,
|
volume: &str,
|
||||||
|
|||||||
@@ -616,7 +616,7 @@ impl DiskAPI for RemoteDisk {
|
|||||||
fi: FileInfo,
|
fi: FileInfo,
|
||||||
force_del_marker: bool,
|
force_del_marker: bool,
|
||||||
opts: DeleteOptions,
|
opts: DeleteOptions,
|
||||||
) -> Result<RawFileInfo> {
|
) -> Result<()> {
|
||||||
info!("delete_version");
|
info!("delete_version");
|
||||||
let file_info = serde_json::to_string(&fi)?;
|
let file_info = serde_json::to_string(&fi)?;
|
||||||
let opts = serde_json::to_string(&opts)?;
|
let opts = serde_json::to_string(&opts)?;
|
||||||
@@ -639,9 +639,9 @@ impl DiskAPI for RemoteDisk {
|
|||||||
return Err(Error::from_string(response.error_info.unwrap_or("".to_string())));
|
return Err(Error::from_string(response.error_info.unwrap_or("".to_string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw_file_info = serde_json::from_str::<RawFileInfo>(&response.raw_file_info)?;
|
// let raw_file_info = serde_json::from_str::<RawFileInfo>(&response.raw_file_info)?;
|
||||||
|
|
||||||
Ok(raw_file_info)
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn delete_versions(
|
async fn delete_versions(
|
||||||
&self,
|
&self,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use std::io::{Cursor, Read};
|
use std::io::{Cursor, Read};
|
||||||
@@ -157,7 +158,63 @@ impl InlineData {
|
|||||||
|
|
||||||
self.serialize(keys, values)
|
self.serialize(keys, values)
|
||||||
}
|
}
|
||||||
|
pub fn remove(&mut self, remove_keys: Vec<Uuid>) -> Result<bool> {
|
||||||
|
let buf = self.after_version();
|
||||||
|
let mut cur = Cursor::new(buf);
|
||||||
|
|
||||||
|
let mut fields_len = rmp::decode::read_map_len(&mut cur)? as usize;
|
||||||
|
let mut keys = Vec::with_capacity(fields_len + 1);
|
||||||
|
let mut values = Vec::with_capacity(fields_len + 1);
|
||||||
|
|
||||||
|
let remove_key = |found_key: &str| {
|
||||||
|
for key in remove_keys.iter() {
|
||||||
|
if key.to_string().as_str() == found_key {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut found = false;
|
||||||
|
|
||||||
|
while fields_len > 0 {
|
||||||
|
fields_len -= 1;
|
||||||
|
|
||||||
|
let str_len = rmp::decode::read_str_len(&mut cur)?;
|
||||||
|
|
||||||
|
let mut field_buff = vec![0u8; str_len as usize];
|
||||||
|
|
||||||
|
cur.read_exact(&mut field_buff)?;
|
||||||
|
|
||||||
|
let find_key = String::from_utf8(field_buff)?;
|
||||||
|
|
||||||
|
let bin_len = rmp::decode::read_bin_len(&mut cur)? as usize;
|
||||||
|
let start = cur.position() as usize;
|
||||||
|
let end = start + bin_len;
|
||||||
|
cur.set_position(end as u64);
|
||||||
|
|
||||||
|
let find_value = &buf[start..end];
|
||||||
|
|
||||||
|
if !remove_key(&find_key) {
|
||||||
|
values.push(find_value.to_vec());
|
||||||
|
keys.push(find_key);
|
||||||
|
} else {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if keys.is_empty() {
|
||||||
|
self.0 = Vec::new();
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.serialize(keys, values)?;
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
fn serialize(&mut self, keys: Vec<String>, values: Vec<Vec<u8>>) -> Result<()> {
|
fn serialize(&mut self, keys: Vec<String>, values: Vec<Vec<u8>>) -> Result<()> {
|
||||||
assert_eq!(keys.len(), values.len(), "InlineData serialize: keys/values not match");
|
assert_eq!(keys.len(), values.len(), "InlineData serialize: keys/values not match");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user