mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 09:18:28 +00:00
merge global_disks
This commit is contained in:
+247
-9
@@ -1,24 +1,45 @@
|
||||
use crate::{
|
||||
bucket_meta::BucketMetadata,
|
||||
disk::{error::DiskError, DeleteOptions, DiskOption, DiskStore, WalkDirOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET},
|
||||
disks_layout::DisksLayout,
|
||||
endpoints::EndpointServerPools,
|
||||
error::{Error, Result},
|
||||
peer::S3PeerSys,
|
||||
sets::Sets,
|
||||
store_api::{
|
||||
BucketInfo, BucketOptions, CompletePart, GetObjectReader, HTTPRangeSpec, ListObjectsInfo, ListObjectsV2Info,
|
||||
MakeBucketOptions, MultipartUploadResult, ObjectInfo, ObjectOptions, PartInfo, PutObjReader, StorageAPI,
|
||||
BucketInfo, BucketOptions, CompletePart, DeletedObject, GetObjectReader, HTTPRangeSpec, ListObjectsInfo,
|
||||
ListObjectsV2Info, MakeBucketOptions, MultipartUploadResult, ObjectInfo, ObjectOptions, ObjectToDelete, PartInfo,
|
||||
PutObjReader, StorageAPI,
|
||||
},
|
||||
store_init, utils,
|
||||
};
|
||||
use futures::future::join_all;
|
||||
use http::HeaderMap;
|
||||
use s3s::{dto::StreamingBlob, Body};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::{debug, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref GLOBAL_OBJECT_API: Arc<Mutex<Option<ECStore>>> = Arc::new(Mutex::new(None));
|
||||
}
|
||||
|
||||
pub fn new_object_layer_fn() -> Arc<Mutex<Option<ECStore>>> {
|
||||
// 这里不需要显式地锁定和解锁,因为 Arc 提供了必要的线程安全性
|
||||
GLOBAL_OBJECT_API.clone()
|
||||
}
|
||||
|
||||
async fn set_object_layer(o: ECStore) {
|
||||
let mut global_object_api = GLOBAL_OBJECT_API.lock().await;
|
||||
*global_object_api = Some(o);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ECStore {
|
||||
pub id: uuid::Uuid,
|
||||
@@ -30,12 +51,12 @@ pub struct ECStore {
|
||||
}
|
||||
|
||||
impl ECStore {
|
||||
pub async fn new(address: String, endpoints: Vec<String>) -> Result<Self> {
|
||||
let layouts = DisksLayout::try_from(endpoints.as_slice())?;
|
||||
pub async fn new(_address: String, endpoint_pools: EndpointServerPools) -> Result<()> {
|
||||
// let layouts = DisksLayout::try_from(endpoints.as_slice())?;
|
||||
|
||||
let mut deployment_id = None;
|
||||
|
||||
let (endpoint_pools, _) = EndpointServerPools::create_server_endpoints(address.as_str(), &layouts)?;
|
||||
// let (endpoint_pools, _) = EndpointServerPools::create_server_endpoints(address.as_str(), &layouts)?;
|
||||
|
||||
let mut pools = Vec::with_capacity(endpoint_pools.as_ref().len());
|
||||
let mut disk_map = HashMap::with_capacity(endpoint_pools.as_ref().len());
|
||||
@@ -95,13 +116,17 @@ impl ECStore {
|
||||
|
||||
let peer_sys = S3PeerSys::new(&endpoint_pools, local_disks.clone());
|
||||
|
||||
Ok(ECStore {
|
||||
let ec = ECStore {
|
||||
id: deployment_id.unwrap(),
|
||||
disk_map,
|
||||
pools,
|
||||
local_disks,
|
||||
peer_sys,
|
||||
})
|
||||
};
|
||||
|
||||
set_object_layer(ec).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn local_disks(&self) -> Vec<DiskStore> {
|
||||
@@ -231,6 +256,77 @@ impl ECStore {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn delete_prefix(&self, _bucket: &str, _object: &str) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn get_pool_info_existing_with_opts(
|
||||
&self,
|
||||
bucket: &str,
|
||||
object: &str,
|
||||
opts: &ObjectOptions,
|
||||
) -> Result<(PoolObjInfo, Vec<Error>)> {
|
||||
let mut futures = Vec::new();
|
||||
|
||||
for pool in self.pools.iter() {
|
||||
futures.push(pool.get_object_info(bucket, object, opts));
|
||||
}
|
||||
|
||||
let results = join_all(futures).await;
|
||||
|
||||
let mut ress = Vec::new();
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
// join_all结果跟输入顺序一致
|
||||
for res in results {
|
||||
let index = i;
|
||||
|
||||
match res {
|
||||
Ok(r) => {
|
||||
ress.push(PoolObjInfo {
|
||||
index,
|
||||
object_info: r,
|
||||
err: None,
|
||||
});
|
||||
}
|
||||
Err(e) => {
|
||||
ress.push(PoolObjInfo {
|
||||
index,
|
||||
err: Some(e),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ress.sort_by(|a, b| {
|
||||
let at = a.object_info.mod_time.unwrap_or(OffsetDateTime::UNIX_EPOCH);
|
||||
let bt = b.object_info.mod_time.unwrap_or(OffsetDateTime::UNIX_EPOCH);
|
||||
|
||||
at.cmp(&bt)
|
||||
});
|
||||
|
||||
for res in ress {
|
||||
// check
|
||||
if res.err.is_none() {
|
||||
// TODO: let errs = self.poolsWithObject()
|
||||
return Ok((res, Vec::new()));
|
||||
}
|
||||
}
|
||||
|
||||
let ret = PoolObjInfo::default();
|
||||
|
||||
Ok((ret, Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct PoolObjInfo {
|
||||
pub index: usize,
|
||||
pub object_info: ObjectInfo,
|
||||
pub err: Option<Error>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@@ -305,7 +401,149 @@ impl StorageAPI for ECStore {
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
async fn delete_objects(
|
||||
&self,
|
||||
bucket: &str,
|
||||
objects: Vec<ObjectToDelete>,
|
||||
opts: ObjectOptions,
|
||||
) -> Result<(Vec<DeletedObject>, Vec<Option<Error>>)> {
|
||||
// encode object name
|
||||
let objects: Vec<ObjectToDelete> = objects
|
||||
.iter()
|
||||
.map(|v| {
|
||||
let mut v = v.clone();
|
||||
v.object_name = utils::path::encode_dir_object(v.object_name.as_str());
|
||||
v
|
||||
})
|
||||
.collect();
|
||||
|
||||
// 默认返回值
|
||||
let mut del_objects = vec![DeletedObject::default(); objects.len()];
|
||||
|
||||
let mut del_errs = Vec::with_capacity(objects.len());
|
||||
for _ in 0..objects.len() {
|
||||
del_errs.push(None)
|
||||
}
|
||||
|
||||
// TODO: limte 限制并发数量
|
||||
let opt = ObjectOptions::default();
|
||||
// 取所有poolObjInfo
|
||||
let mut futures = Vec::new();
|
||||
for obj in objects.iter() {
|
||||
futures.push(self.get_pool_info_existing_with_opts(bucket, &obj.object_name, &opt));
|
||||
}
|
||||
|
||||
let results = join_all(futures).await;
|
||||
|
||||
// 记录pool Index 对应的objects pool_idx -> objects idx
|
||||
let mut pool_index_objects = HashMap::new();
|
||||
|
||||
let mut i = 0;
|
||||
for res in results {
|
||||
match res {
|
||||
Ok((pinfo, _)) => {
|
||||
if pinfo.object_info.delete_marker && opts.version_id.is_empty() {
|
||||
del_objects[i] = DeletedObject {
|
||||
delete_marker: pinfo.object_info.delete_marker,
|
||||
delete_marker_version_id: pinfo.object_info.version_id.map(|v| v.to_string()),
|
||||
object_name: utils::path::decode_dir_object(&pinfo.object_info.name),
|
||||
delete_marker_mtime: pinfo.object_info.mod_time,
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
|
||||
if !pool_index_objects.contains_key(&pinfo.index) {
|
||||
pool_index_objects.insert(pinfo.index, vec![i]);
|
||||
} else {
|
||||
// let mut vals = pool_index_objects.
|
||||
if let Some(val) = pool_index_objects.get_mut(&pinfo.index) {
|
||||
val.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
//TODO: check not found
|
||||
|
||||
del_errs[i] = Some(e)
|
||||
}
|
||||
}
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if !pool_index_objects.is_empty() {
|
||||
for sets in self.pools.iter() {
|
||||
// 取pool idx 对应的 objects index
|
||||
let vals = pool_index_objects.get(&sets.pool_idx);
|
||||
if vals.is_none() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let obj_idxs = vals.unwrap();
|
||||
// 取对应obj,理论上不会none
|
||||
let objs: Vec<ObjectToDelete> = obj_idxs
|
||||
.iter()
|
||||
.filter_map(|&idx| {
|
||||
if let Some(obj) = objects.get(idx) {
|
||||
Some(obj.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if objs.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let (pdel_objs, perrs) = sets.delete_objects(bucket, objs, opts.clone()).await?;
|
||||
|
||||
// perrs的顺序理论上跟obj_idxs顺序一致
|
||||
let mut i = 0;
|
||||
for err in perrs {
|
||||
let obj_idx = obj_idxs[i];
|
||||
|
||||
if err.is_some() {
|
||||
del_errs[obj_idx] = err;
|
||||
}
|
||||
|
||||
let mut dobj = pdel_objs.get(i).unwrap().clone();
|
||||
dobj.object_name = utils::path::decode_dir_object(&dobj.object_name);
|
||||
|
||||
del_objects[obj_idx] = dobj;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok((del_objects, del_errs))
|
||||
}
|
||||
async fn delete_object(&self, bucket: &str, object: &str, opts: ObjectOptions) -> Result<ObjectInfo> {
|
||||
if opts.delete_prefix {
|
||||
self.delete_prefix(bucket, &object).await?;
|
||||
return Ok(ObjectInfo::default());
|
||||
}
|
||||
|
||||
let object = utils::path::encode_dir_object(object);
|
||||
let object = object.as_str();
|
||||
|
||||
// 查询在哪个pool
|
||||
let (mut pinfo, errs) = self.get_pool_info_existing_with_opts(bucket, object, &opts).await?;
|
||||
if pinfo.object_info.delete_marker && opts.version_id.is_empty() {
|
||||
pinfo.object_info.name = utils::path::decode_dir_object(object);
|
||||
return Ok(pinfo.object_info);
|
||||
}
|
||||
|
||||
if !errs.is_empty() {
|
||||
// TODO: deleteObjectFromAllPools
|
||||
}
|
||||
|
||||
let mut obj = self.pools[pinfo.index].delete_object(bucket, object, opts.clone()).await?;
|
||||
obj.name = utils::path::decode_dir_object(object);
|
||||
|
||||
Ok(obj)
|
||||
}
|
||||
async fn list_objects_v2(
|
||||
&self,
|
||||
bucket: &str,
|
||||
|
||||
Reference in New Issue
Block a user