mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-07 05:43:14 +00:00
init bucketmetadata_sys
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum BucketMetadataError {
|
||||
#[error("tagging not found")]
|
||||
TaggingNotFound,
|
||||
}
|
||||
@@ -13,18 +13,30 @@ use time::OffsetDateTime;
|
||||
use tracing::error;
|
||||
|
||||
use crate::bucket::tags;
|
||||
use crate::config;
|
||||
use crate::config::common::{read_config, save_config};
|
||||
use crate::config::error::ConfigError;
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
use crate::disk::BUCKET_META_PREFIX;
|
||||
use crate::store::ECStore;
|
||||
use crate::store_api::StorageAPI;
|
||||
|
||||
type TypeConfigFile = &'static str;
|
||||
|
||||
pub const BUCKET_METADATA_FILE: &str = ".metadata.bin";
|
||||
pub const BUCKET_METADATA_FORMAT: u16 = 1;
|
||||
pub const BUCKET_METADATA_VERSION: u16 = 1;
|
||||
|
||||
pub const BUCKET_POLICY_CONFIG: &str = "policy.json";
|
||||
pub const BUCKET_NOTIFICATION_CONFIG: &str = "notification.xml";
|
||||
pub const BUCKET_LIFECYCLE_CONFIG: &str = "lifecycle.xml";
|
||||
pub const BUCKET_SSECONFIG: &str = "bucket-encryption.xml";
|
||||
pub const BUCKET_TAGGING_CONFIG: &str = "tagging.xml";
|
||||
pub const BUCKET_QUOTA_CONFIG_FILE: &str = "quota.json";
|
||||
pub const OBJECT_LOCK_CONFIG: &str = "object-lock.xml";
|
||||
pub const BUCKET_VERSIONING_CONFIG: &str = "versioning.xml";
|
||||
pub const BUCKET_REPLICATION_CONFIG: &str = "replication.xml";
|
||||
pub const BUCKET_TARGETS_FILE: &str = "bucket-targets.json";
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(rename_all = "PascalCase", default)]
|
||||
pub struct BucketMetadata {
|
||||
@@ -170,7 +182,57 @@ impl BucketMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
async fn save(&mut self, api: &ECStore) -> Result<()> {
|
||||
pub fn update_config(&mut self, config_file: &str, data: Vec<u8>) -> Result<OffsetDateTime> {
|
||||
let updated = OffsetDateTime::now_utc();
|
||||
|
||||
match config_file {
|
||||
BUCKET_POLICY_CONFIG => {
|
||||
self.policy_config_json = data;
|
||||
self.policy_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_NOTIFICATION_CONFIG => {
|
||||
self.notification_config_xml = data;
|
||||
self.notification_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_LIFECYCLE_CONFIG => {
|
||||
self.lifecycle_config_xml = data;
|
||||
self.lifecycle_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_SSECONFIG => {
|
||||
self.encryption_config_xml = data;
|
||||
self.encryption_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_TAGGING_CONFIG => {
|
||||
self.tagging_config_xml = data;
|
||||
self.tagging_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_QUOTA_CONFIG_FILE => {
|
||||
self.quota_config_json = data;
|
||||
self.quota_config_updated_at = updated;
|
||||
}
|
||||
OBJECT_LOCK_CONFIG => {
|
||||
self.object_lock_config_xml = data;
|
||||
self.object_lock_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_VERSIONING_CONFIG => {
|
||||
self.versioning_config_xml = data;
|
||||
self.versioning_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_REPLICATION_CONFIG => {
|
||||
self.replication_config_xml = data;
|
||||
self.replication_config_updated_at = updated;
|
||||
}
|
||||
BUCKET_TARGETS_FILE => {
|
||||
self.tagging_config_xml = data;
|
||||
self.tagging_config_updated_at = updated;
|
||||
}
|
||||
_ => return Err(Error::msg(format!("config file not found : {}", config_file))),
|
||||
}
|
||||
|
||||
Ok(updated)
|
||||
}
|
||||
|
||||
pub async fn save(&mut self, api: &ECStore) -> Result<()> {
|
||||
self.parse_all_configs(api)?;
|
||||
|
||||
let mut buf: Vec<u8> = vec![0; 4];
|
||||
@@ -201,14 +263,12 @@ pub async fn load_bucket_metadata(api: &ECStore, bucket: &str) -> Result<BucketM
|
||||
load_bucket_metadata_parse(api, bucket, true).await
|
||||
}
|
||||
|
||||
async fn load_bucket_metadata_parse(api: &ECStore, bucket: &str, parse: bool) -> Result<BucketMetadata> {
|
||||
pub async fn load_bucket_metadata_parse(api: &ECStore, bucket: &str, parse: bool) -> Result<BucketMetadata> {
|
||||
let mut bm = match read_bucket_metadata(api, bucket).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
if let Some(e) = err.downcast_ref::<ConfigError>() {
|
||||
if !ConfigError::is_not_found(&e) {
|
||||
return Err(err);
|
||||
}
|
||||
if !config::error::is_not_found(&err) {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
BucketMetadata::new(bucket)
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use crate::bucket::error::BucketMetadataError;
|
||||
use crate::bucket::metadata::load_bucket_metadata_parse;
|
||||
use crate::bucket::utils::is_meta_bucketname;
|
||||
use crate::config;
|
||||
use crate::config::error::ConfigError;
|
||||
use crate::disk::error::DiskError;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::global::{is_dist_erasure, is_erasure, new_object_layer_fn};
|
||||
use crate::store::ECStore;
|
||||
use futures::future::join_all;
|
||||
use lazy_static::lazy_static;
|
||||
use time::OffsetDateTime;
|
||||
use tokio::sync::RwLock;
|
||||
@@ -10,41 +18,132 @@ use super::metadata::{load_bucket_metadata, BucketMetadata};
|
||||
use super::tags;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref GLOBAL_BucketMetadataSys: Arc<Option<BucketMetadataSys>> = Arc::new(Some(BucketMetadataSys::new()));
|
||||
static ref GLOBAL_BucketMetadataSys: Arc<BucketMetadataSys> = Arc::new(BucketMetadataSys::new());
|
||||
}
|
||||
|
||||
pub fn get_bucket_metadata_sys() -> Arc<Option<BucketMetadataSys>> {
|
||||
pub fn get_bucket_metadata_sys() -> Arc<BucketMetadataSys> {
|
||||
GLOBAL_BucketMetadataSys.clone()
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct BucketMetadataSys {
|
||||
metadata_map: RwLock<HashMap<String, BucketMetadata>>,
|
||||
api: Option<Arc<ECStore>>,
|
||||
api: Option<ECStore>,
|
||||
initialized: RwLock<bool>,
|
||||
}
|
||||
|
||||
impl BucketMetadataSys {
|
||||
fn new() -> Self {
|
||||
Self { ..Default::default() }
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn init(&mut self, api: Arc<ECStore>, buckets: Vec<String>) {
|
||||
self.api = Some(api);
|
||||
pub async fn init(&mut self, api: Option<ECStore>, buckets: Vec<&str>) -> Result<()> {
|
||||
if api.is_none() {
|
||||
return Err(Error::msg("errServerNotInitialized"));
|
||||
}
|
||||
self.api = api;
|
||||
|
||||
let _ = self.init_internal(buckets).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
async fn init_internal(&self, buckets: Vec<&str>) -> Result<()> {
|
||||
if self.api.is_none() {
|
||||
return Err(Error::msg("errServerNotInitialized"));
|
||||
}
|
||||
let mut futures = Vec::new();
|
||||
let mut errs = Vec::new();
|
||||
let mut ress = Vec::new();
|
||||
|
||||
for &bucket in buckets.iter() {
|
||||
futures.push(load_bucket_metadata(self.api.as_ref().unwrap(), bucket));
|
||||
}
|
||||
|
||||
let results = join_all(futures).await;
|
||||
|
||||
for res in results {
|
||||
match res {
|
||||
Ok(entrys) => {
|
||||
ress.push(Some(entrys));
|
||||
errs.push(None);
|
||||
}
|
||||
Err(e) => {
|
||||
ress.push(None);
|
||||
errs.push(Some(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
async fn concurrent_load(&self, buckets: Vec<&str>) -> Result<Vec<&str>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub async fn get(&self, bucket: &str) -> Result<BucketMetadata> {
|
||||
if is_meta_bucketname(bucket) {
|
||||
return Err(Error::new(ConfigError::NotFound));
|
||||
}
|
||||
|
||||
let map = self.metadata_map.read().await;
|
||||
if let Some(bm) = map.get(bucket) {
|
||||
Ok(bm.clone())
|
||||
} else {
|
||||
Err(Error::new(ConfigError::NotFound))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set(&self, bucket: &str, bm: BucketMetadata) {
|
||||
if !is_meta_bucketname(bucket) {
|
||||
let mut map = self.metadata_map.write().await;
|
||||
map.insert(bucket.to_string(), bm);
|
||||
}
|
||||
}
|
||||
|
||||
async fn reset(&mut self) {
|
||||
let mut map = self.metadata_map.write().await;
|
||||
map.clear();
|
||||
}
|
||||
|
||||
pub async fn get_config(&self, bucket: String) -> Result<(BucketMetadata, bool)> {
|
||||
pub async fn update(&mut self, bucket: &str, config_file: &str, data: Vec<u8>) -> Result<(OffsetDateTime)> {
|
||||
self.update_and_parse(bucket, config_file, data, true).await
|
||||
}
|
||||
|
||||
async fn update_and_parse(&mut self, bucket: &str, config_file: &str, data: Vec<u8>, parse: bool) -> Result<OffsetDateTime> {
|
||||
let layer = new_object_layer_fn();
|
||||
let lock = layer.read().await;
|
||||
let store = match lock.as_ref() {
|
||||
Some(s) => s,
|
||||
None => return Err(Error::msg("errServerNotInitialized")),
|
||||
};
|
||||
|
||||
if is_meta_bucketname(&bucket) {
|
||||
return Err(Error::msg("errInvalidArgument"));
|
||||
}
|
||||
|
||||
let mut bm = match load_bucket_metadata_parse(store, &bucket, parse).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
if !is_erasure().await && !is_dist_erasure().await && DiskError::VolumeNotFound.is(&err) {
|
||||
BucketMetadata::new(&bucket)
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let updated = bm.update_config(config_file, data)?;
|
||||
|
||||
bm.save(store).await?;
|
||||
|
||||
Ok(updated)
|
||||
}
|
||||
|
||||
pub async fn get_config(&self, bucket: &str) -> Result<(BucketMetadata, bool)> {
|
||||
if let Some(api) = self.api.as_ref() {
|
||||
let has_bm = {
|
||||
let map = self.metadata_map.read().await;
|
||||
if let Some(bm) = map.get(&bucket) {
|
||||
if let Some(bm) = map.get(&bucket.to_string()) {
|
||||
Some(bm.clone())
|
||||
} else {
|
||||
None
|
||||
@@ -54,7 +153,7 @@ impl BucketMetadataSys {
|
||||
if let Some(bm) = has_bm {
|
||||
return Ok((bm, false));
|
||||
} else {
|
||||
let bm = match load_bucket_metadata(&api, bucket.as_str()).await {
|
||||
let bm = match load_bucket_metadata(&api, bucket).await {
|
||||
Ok(res) => res,
|
||||
Err(err) => {
|
||||
if *self.initialized.read().await {
|
||||
@@ -67,7 +166,7 @@ impl BucketMetadataSys {
|
||||
|
||||
let mut map = self.metadata_map.write().await;
|
||||
|
||||
map.insert(bucket, bm.clone());
|
||||
map.insert(bucket.to_string(), bm.clone());
|
||||
|
||||
Ok((bm, true))
|
||||
}
|
||||
@@ -76,7 +175,22 @@ impl BucketMetadataSys {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_tagging_config(&self, bucket: String) -> Result<(tags::Tags, Option<OffsetDateTime>)> {
|
||||
unimplemented!()
|
||||
pub async fn get_tagging_config(&self, bucket: &str) -> Result<(tags::Tags, OffsetDateTime)> {
|
||||
let bm = match self.get_config(bucket).await {
|
||||
Ok((res, _)) => res,
|
||||
Err(err) => {
|
||||
if config::error::is_not_found(&err) {
|
||||
return Err(Error::new(BucketMetadataError::TaggingNotFound));
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(config) = bm.tagging_config {
|
||||
Ok((config, bm.tagging_config_updated_at))
|
||||
} else {
|
||||
Err(Error::new(BucketMetadataError::TaggingNotFound))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod encryption;
|
||||
mod error;
|
||||
mod event;
|
||||
mod lifecycle;
|
||||
pub mod metadata;
|
||||
@@ -10,5 +11,6 @@ mod replication;
|
||||
mod tags;
|
||||
mod target;
|
||||
mod versioning;
|
||||
pub mod utils;
|
||||
|
||||
pub use metadata_sys::get_bucket_metadata_sys;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
use crate::disk::RUSTFS_META_BUCKET;
|
||||
|
||||
pub fn is_meta_bucketname(name: &str) -> bool {
|
||||
name.starts_with(RUSTFS_META_BUCKET)
|
||||
}
|
||||
Reference in New Issue
Block a user