From fe50ccd39f53b697908cc4e5ddac2fdfdad49f3d Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Mon, 11 Nov 2024 17:33:25 +0800 Subject: [PATCH 01/11] tmp --- ecstore/Cargo.toml | 1 + ecstore/src/config/heal.rs | 65 ++++++ ecstore/src/config/mod.rs | 1 + ecstore/src/disk/error.rs | 4 + ecstore/src/disk/format.rs | 12 +- ecstore/src/disk/mod.rs | 6 +- ecstore/src/endpoints.rs | 10 + ecstore/src/erasure.rs | 45 ++++ ecstore/src/global.rs | 6 +- ecstore/src/heal/background_heal_ops.rs | 101 ++++++-- ecstore/src/heal/data_scanner.rs | 293 ++++++++++++++++++++++++ ecstore/src/heal/data_scanner_metric.rs | 74 ++++++ ecstore/src/heal/data_usage.rs | 158 +++++++++++++ ecstore/src/heal/data_usage_cache.rs | 234 +++++++++++++++++++ ecstore/src/heal/heal_commands.rs | 15 +- ecstore/src/heal/heal_ops.rs | 63 ++--- ecstore/src/heal/mod.rs | 4 + ecstore/src/lib.rs | 2 +- ecstore/src/sets.rs | 222 +++++++++++++++++- ecstore/src/store.rs | 134 +++++++++-- ecstore/src/store_api.rs | 22 +- ecstore/src/store_init.rs | 32 ++- ecstore/src/utils/bool_flag.rs | 15 ++ ecstore/src/utils/mod.rs | 1 + rustfs/src/main.rs | 5 + 25 files changed, 1413 insertions(+), 112 deletions(-) create mode 100644 ecstore/src/config/heal.rs create mode 100644 ecstore/src/heal/data_scanner.rs create mode 100644 ecstore/src/heal/data_scanner_metric.rs create mode 100644 ecstore/src/heal/data_usage.rs create mode 100644 ecstore/src/heal/data_usage_cache.rs create mode 100644 ecstore/src/utils/bool_flag.rs diff --git a/ecstore/Cargo.toml b/ecstore/Cargo.toml index 79370b32f..1208304da 100644 --- a/ecstore/Cargo.toml +++ b/ecstore/Cargo.toml @@ -41,6 +41,7 @@ protos.workspace = true rmp-serde = "1.3.0" tokio-util = { version = "0.7.12", features = ["io", "compat"] } crc32fast = "1.4.2" +rand = "0.8.5" siphasher = "1.0.1" base64-simd = "0.8.0" sha2 = { version = "0.11.0-pre.4" } diff --git a/ecstore/src/config/heal.rs b/ecstore/src/config/heal.rs new file mode 100644 index 000000000..20e910a6f --- /dev/null +++ b/ecstore/src/config/heal.rs @@ -0,0 +1,65 @@ +use std::time::Duration; + +use crate::{ + error::{Error, Result}, + utils::bool_flag::parse_bool, +}; + +#[derive(Debug, Default)] +pub struct Config { + pub bitrot: String, + pub sleep: Duration, + pub io_count: usize, + pub drive_workers: usize, + pub cache: Duration, +} + +impl Config { + pub fn bitrot_scan_cycle(&self) -> Duration { + self.cache + } + + pub fn get_workers(&self) -> usize { + self.drive_workers + } + + pub fn update(&mut self, nopts: &Config) { + self.bitrot = nopts.bitrot.clone(); + self.io_count = nopts.io_count; + self.sleep = nopts.sleep; + self.drive_workers = nopts.drive_workers; + } +} + +const RUSTFS_BITROT_CYCLE_IN_MONTHS: u64 = 1; + +fn parse_bitrot_config(s: &str) -> Result { + match parse_bool(s) { + Ok(enabled) => { + if enabled { + return Ok(Duration::from_secs_f64(0.0)); + } else { + return Ok(Duration::from_secs_f64(-1.0)); + } + } + Err(_) => { + if !s.ends_with("m") { + return Err(Error::from_string("unknown format")); + } + + match s.trim_end_matches('m').parse::() { + Ok(months) => { + if months < RUSTFS_BITROT_CYCLE_IN_MONTHS { + return Err(Error::from_string(format!( + "minimum bitrot cycle is {} month(s)", + RUSTFS_BITROT_CYCLE_IN_MONTHS + ))); + } + + Ok(Duration::from_secs(months * 30 * 24 * 60)) + } + Err(err) => Err(err.into()), + } + } + } +} diff --git a/ecstore/src/config/mod.rs b/ecstore/src/config/mod.rs index 7da3f8469..030d15a10 100644 --- a/ecstore/src/config/mod.rs +++ b/ecstore/src/config/mod.rs @@ -1,5 +1,6 @@ pub mod common; pub mod error; +pub mod heal; pub mod storageclass; use crate::error::Result; diff --git a/ecstore/src/disk/error.rs b/ecstore/src/disk/error.rs index fd20a91dc..f114210cc 100644 --- a/ecstore/src/disk/error.rs +++ b/ecstore/src/disk/error.rs @@ -106,6 +106,9 @@ pub enum DiskError { #[error("part missing or corrupt")] PartMissingOrCorrupt, + + #[error("No healing is required")] + NoHealRequired, } impl DiskError { @@ -210,6 +213,7 @@ pub fn clone_disk_err(e: &DiskError) -> Error { DiskError::MoreData => Error::new(DiskError::MoreData), DiskError::OutdatedXLMeta => Error::new(DiskError::OutdatedXLMeta), DiskError::PartMissingOrCorrupt => Error::new(DiskError::PartMissingOrCorrupt), + DiskError::NoHealRequired => Error::new(DiskError::NoHealRequired), } } diff --git a/ecstore/src/disk/format.rs b/ecstore/src/disk/format.rs index f2a9775cc..602ea629c 100644 --- a/ecstore/src/disk/format.rs +++ b/ecstore/src/disk/format.rs @@ -1,4 +1,4 @@ -use super::error::DiskError; +use super::{error::DiskError, DiskInfo}; use crate::error::{Error, Result}; use serde::{Deserialize, Serialize}; use serde_json::Error as JsonError; @@ -31,7 +31,7 @@ pub enum FormatBackend { /// /// The V3 format to support "large bucket" support where a bucket /// can span multiple erasure sets. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct FormatErasureV3 { /// Version of 'xl' format. pub version: FormatErasureVersion, @@ -88,7 +88,7 @@ pub enum DistributionAlgoVersion { /// /// Ideally we will never have a situation where we will have to change the /// fields of this struct and deal with related migration. -#[derive(Debug, Serialize, Deserialize, Clone)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct FormatV3 { /// Version of the format config. pub version: FormatMetaVersion, @@ -103,8 +103,8 @@ pub struct FormatV3 { pub erasure: FormatErasureV3, // /// DiskInfo is an extended type which returns current // /// disk usage per path. - // #[serde(skip)] - // pub disk_info: Option, + #[serde(skip)] + pub disk_info: Option, } impl TryFrom<&[u8]> for FormatV3 { @@ -146,7 +146,7 @@ impl FormatV3 { format, id: Uuid::new_v4(), erasure, - // disk_info: None, + disk_info: None, } } diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index e57543058..3a59fa250 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -467,7 +467,7 @@ pub struct DiskInfoOptions { pub noop: bool, } -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] pub struct DiskInfo { pub total: u64, pub free: u64, @@ -489,7 +489,7 @@ pub struct DiskInfo { pub error: String, } -#[derive(Clone, Debug, Default, Serialize, Deserialize)] +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] pub struct DiskMetrics { api_calls: HashMap, total_waiting: u32, @@ -835,7 +835,7 @@ impl MetaCacheEntries { } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct DiskOption { pub cleanup: bool, pub health_check: bool, diff --git a/ecstore/src/endpoints.rs b/ecstore/src/endpoints.rs index c5ff9cbf0..0329f88f5 100644 --- a/ecstore/src/endpoints.rs +++ b/ecstore/src/endpoints.rs @@ -109,6 +109,16 @@ impl Endpoints { pub fn into_inner(self) -> Vec { self.0 } + + // GetString - returns endpoint string of i-th endpoint (0-based), + // and empty string for invalid indexes. + pub fn get_string(&self, i: usize) -> String { + if i < 0 || i >= self.0.len() { + return "".to_string(); + } + + self.0[i].to_string() + } } #[derive(Debug)] diff --git a/ecstore/src/erasure.rs b/ecstore/src/erasure.rs index f0983aac6..769995d60 100644 --- a/ecstore/src/erasure.rs +++ b/ecstore/src/erasure.rs @@ -19,6 +19,7 @@ use uuid::Uuid; // use crate::chunk_stream::ChunkedStream; use crate::disk::error::DiskError; +#[derive(Default)] pub struct Erasure { data_shards: usize, parity_shards: usize, @@ -417,6 +418,50 @@ impl Erasure { till_offset } + + pub async fn heal(&self, writers: &mut [Option], readers: Vec>, total_length: usize, prefer: &[bool]) -> Result<()> { + if writers.len() != self.parity_shards + self.data_shards { + return Err(Error::from_string("invalid argument")); + } + let mut reader = ShardReader::new(readers, self, 0, total_length); + + let start_block = 0; + let mut end_block = total_length / self.block_size; + if total_length % self.block_size != 0 { + end_block += 1; + } + + let mut bytes_writed = 0; + + let mut errs = Vec::new(); + for _ in start_block..=end_block { + let mut bufs = reader.read().await?; + + if self.parity_shards > 0 { + self.encoder.as_ref().unwrap().reconstruct(&mut bufs)?; + } + + let shards = bufs.into_iter().filter_map(|x| x).collect::>(); + if shards.len() != self.parity_shards + self.data_shards { + return Err(Error::from_string("can not reconstruct data")); + } + + for (i, w) in writers.iter_mut().enumerate() { + if w.is_none() { + continue; + } + match w.as_mut().unwrap().write(shards[i].as_ref()).await { + Ok(_) => {}, + Err(e) => errs.push(e), + } + } + } + if !errs.is_empty() { + return Err(errs[0].clone()); + } + + Ok(()) + } } #[async_trait::async_trait] diff --git a/ecstore/src/global.rs b/ecstore/src/global.rs index 16ac35be9..a602fc728 100644 --- a/ecstore/src/global.rs +++ b/ecstore/src/global.rs @@ -4,9 +4,7 @@ use tokio::sync::RwLock; use uuid::Uuid; use crate::{ - disk::DiskStore, - endpoints::{EndpointServerPools, PoolEndpoints, SetupType}, - store::ECStore, + disk::DiskStore, endpoints::{EndpointServerPools, PoolEndpoints, SetupType}, heal::{background_heal_ops::HealRoutine, heal_ops::AllHealState}, store::ECStore }; pub const DISK_ASSUME_UNKNOWN_SIZE: u64 = 1 << 30; @@ -24,6 +22,8 @@ lazy_static! { pub static ref GLOBAL_LOCAL_DISK_SET_DRIVES: Arc> = Arc::new(RwLock::new(Vec::new())); pub static ref GLOBAL_Endpoints: RwLock = RwLock::new(EndpointServerPools(Vec::new())); pub static ref GLOBAL_RootDiskThreshold: RwLock = RwLock::new(0); + pub static ref GLOBAL_BackgroundHealRoutine: Arc> = HealRoutine::new(); + pub static ref GLOBAL_BackgroundHealState: Arc> = AllHealState::new(false); static ref globalDeploymentIDPtr: RwLock = RwLock::new(Uuid::nil()); } diff --git a/ecstore/src/heal/background_heal_ops.rs b/ecstore/src/heal/background_heal_ops.rs index 30f9e0563..f0de47329 100644 --- a/ecstore/src/heal/background_heal_ops.rs +++ b/ecstore/src/heal/background_heal_ops.rs @@ -1,14 +1,16 @@ -use std::sync::Arc; +use std::{env, sync::Arc}; use tokio::{ select, sync::{ broadcast::Receiver as B_Receiver, - mpsc::{self, Receiver, Sender}, + mpsc::{self, Receiver, Sender}, RwLock, }, }; -use crate::{error::Error, heal::heal_ops::NOP_HEAL, utils::path::SLASH_SEPARATOR}; +use crate::{ + disk::error::DiskError, error::{Error, Result}, heal::heal_ops::NOP_HEAL, new_object_layer_fn, store_api::StorageAPI, utils::path::SLASH_SEPARATOR +}; use super::{ heal_commands::{HealOpts, HealResultItem}, @@ -21,8 +23,8 @@ pub struct HealTask { pub object: String, pub version_id: String, pub opts: HealOpts, - pub resp_tx: Arc>, - pub resp_rx: Arc>, + pub resp_tx: Option>>, + pub resp_rx: Option>>, } impl HealTask { @@ -33,15 +35,15 @@ impl HealTask { object: object.to_string(), version_id: version_id.to_string(), opts: opts.clone(), - resp_tx: tx.into(), - resp_rx: rx.into(), + resp_tx: Some(tx.into()), + resp_rx: Some(rx.into()), } } } pub struct HealResult { pub result: HealResultItem, - err: Error, + err: Option, } pub struct HealRoutine { @@ -51,18 +53,78 @@ pub struct HealRoutine { } impl HealRoutine { - pub async fn add_worker(&mut self, mut ctx: B_Receiver, bgseq: &HealSequence) { + pub fn new() -> Arc> { + let mut workers = num_cpus::get() / 2; + if let Ok(env_heal_workers) = env::var("_RUSTFS_HEAL_WORKERS") { + if let Ok(num_healers) = env_heal_workers.parse::() { + workers = num_healers; + } + } + + if workers == 0 { + workers = 4; + } + + let (tx, rx) = mpsc::channel(100); + Arc::new(RwLock::new(Self { + tasks_tx: tx, + tasks_rx: rx, + workers, + })) + } + + pub async fn add_worker(&mut self, mut ctx: B_Receiver, bgseq: &mut HealSequence) { loop { select! { task = self.tasks_rx.recv() => { - let mut res = HealResultItem::default(); - let mut err: Error; + let mut d_res = HealResultItem::default(); + let d_err: Option; match task { Some(task) => { if task.bucket == NOP_HEAL { - err = Error::from_string("skip file"); + d_err = Some(Error::from_string("skip file")); } else if task.bucket == SLASH_SEPARATOR { - (res, err) = heal_disk_format(task.opts).await; + match heal_disk_format(task.opts).await { + Ok((res, err)) => { + d_res = res; + d_err = err; + }, + Err(err) => {d_err = Some(err)}, + } + } else { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = lock + .as_ref() + .expect("Not init"); + if task.object.is_empty() { + match store.heal_object(&task.bucket, &task.object, &task.version_id, &task.opts).await { + Ok((res, err)) => { + d_res = res; + d_err = err; + }, + Err(err) => {d_err = Some(err)}, + } + } else { + match store.heal_object(&task.bucket, &task.object, &task.version_id, &task.opts).await { + Ok((res, err)) => { + d_res = res; + d_err = err; + }, + Err(err) => {d_err = Some(err)}, + } + } + } + if let Some(resp_tx) = task.resp_tx { + let _ = resp_tx.send(HealResult{result: d_res, err: d_err}).await; + } else { + // when respCh is not set caller is not waiting but we + // update the relevant metrics for them + if d_err.is_none() { + bgseq.count_healed(d_res.heal_item_type); + } else { + bgseq.count_failed(d_res.heal_item_type); + } } }, None => return, @@ -80,6 +142,15 @@ impl HealRoutine { // } -async fn heal_disk_format(opts: HealOpts) -> (HealResultItem, Error) { - todo!() +async fn heal_disk_format(opts: HealOpts) -> Result<(HealResultItem, Option)> { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = lock.as_ref().expect("Not init"); + let (res, err) = store.heal_format(opts.dry_run).await?; + // return any error, ignore error returned when disks have + // already healed. + if err.is_some() { + return Ok((HealResultItem::default(), err)); + } + return Ok((res, err)); } diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs new file mode 100644 index 000000000..ed290818e --- /dev/null +++ b/ecstore/src/heal/data_scanner.rs @@ -0,0 +1,293 @@ +use std::{ + io::{Cursor, Read}, + sync::{atomic::{AtomicU32, AtomicU64}, Arc}, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use byteorder::{LittleEndian, ReadBytesExt}; +use lazy_static::lazy_static; +use rand::Rng; +use rmp_serde::{Deserializer, Serializer}; +use serde::{Deserialize, Serialize}; +use tokio::{sync::{mpsc, RwLock}, time::sleep}; +use tracing::{error, info}; + +use crate::{ + config::{common::{read_config, save_config}, heal::Config}, + error::{Error, Result}, + global::GLOBAL_IsErasureSD, + heal::data_usage::BACKGROUND_HEAL_INFO_PATH, + new_object_layer_fn, + store::ECStore, +}; + +use super::{data_scanner_metric::globalScannerMetrics, data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}}; + +const DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. +const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16; // Visit all folders every n cycles. +const DATA_SCANNER_COMPACT_LEAST_OBJECT: u64 = 500; // Compact when there are less than this many objects in a branch. +const DATA_SCANNER_COMPACT_AT_CHILDREN: u64 = 10000; // Compact when there are this many children in a branch. +const DATA_SCANNER_COMPACT_AT_FOLDERS: u64 = DATA_SCANNER_COMPACT_AT_CHILDREN / 4; // Compact when this many subfolders in a single folder. +const DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS: u64 = 250_000; // Compact when this many subfolders in a single folder (even top level). +const DATA_SCANNER_START_DELAY: Duration = Duration::from_secs(60); // Time to wait on startup and between cycles. + +const HEAL_DELETE_DANGLING: bool = true; +const HEAL_OBJECT_SELECT_PROB: u64 = 1024; // Overall probability of a file being scanned; one in n. + +// static SCANNER_SLEEPER: () = new_dynamic_sleeper(2, Duration::from_secs(1), true); // Keep defaults same as config defaults +static SCANNER_CYCLE: AtomicU64 = AtomicU64::new(DATA_SCANNER_START_DELAY.as_secs()); +static SCANNER_IDLE_MODE: AtomicU32 = AtomicU32::new(0); // default is throttled when idle +static SCANNER_EXCESS_OBJECT_VERSIONS: AtomicU64 = AtomicU64::new(100); +static SCANNER_EXCESS_OBJECT_VERSIONS_TOTAL_SIZE: AtomicU64 = AtomicU64::new(1024 * 1024 * 1024 * 1024); // 1 TB +static SCANNER_EXCESS_FOLDERS: AtomicU64 = AtomicU64::new(50_000); + +lazy_static! { + pub static ref globalHealConfig: Arc> = Arc::new(RwLock::new(Config::default())); +} + +pub async fn init_data_scanner() { + let mut r = rand::thread_rng(); + let random = r.gen_range(0.0..1.0); + tokio::spawn(async move { + loop { + run_data_scanner().await; + let duration = Duration::from_secs_f64(random * (SCANNER_CYCLE.load(std::sync::atomic::Ordering::SeqCst) as f64)); + let sleep_duration = if duration < Duration::new(1, 0) { + Duration::new(1, 0) + } else { + duration + }; + sleep(sleep_duration).await; + } + }); +} + +async fn run_data_scanner() { + let mut cycle_info = CurrentScannerCycle::default(); + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => { + info!("errServerNotInitialized"); + return; + } + }; + let mut buf = read_config(store, &DATA_USAGE_BLOOM_NAME_PATH) + .await + .map_or(Vec::new(), |buf| buf); + if buf.len() == 8 { + cycle_info.next = match Cursor::new(buf).read_u64::() { + Ok(buf) => buf, + Err(_) => { + error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); + return; + } + }; + } else if buf.len() > 8 { + cycle_info.next = match Cursor::new(buf[..8].to_vec()).read_u64::() { + Ok(buf) => buf, + Err(_) => { + error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); + return; + } + }; + let _ = cycle_info.unmarshal_msg(&buf.split_off(8)); + } + + loop { + cycle_info.current = cycle_info.next; + cycle_info.started = SystemTime::now(); + { + globalScannerMetrics.write().await.set_cycle(Some(cycle_info.clone())).await; + } + + let bg_heal_info = read_background_heal_info(store).await; + let scan_mode = get_cycle_scan_mode(cycle_info.current, bg_heal_info.bitrot_start_cycle, bg_heal_info.bitrot_start_time).await; + if bg_heal_info.current_scan_mode != scan_mode { + let mut new_heal_info = bg_heal_info; + new_heal_info.current_scan_mode = scan_mode; + if scan_mode == HEAL_DEEP_SCAN { + new_heal_info.bitrot_start_time = SystemTime::now(); + new_heal_info.bitrot_start_cycle = cycle_info.current; + } + save_background_heal_info(store, &new_heal_info).await; + } + // Wait before starting next cycle and wait on startup. + let (tx, rx) = mpsc::channel(100); + tokio::spawn(async { + store_data_usage_in_backend(rx).await; + }); + sleep(Duration::from_secs(SCANNER_CYCLE.load(std::sync::atomic::Ordering::SeqCst))).await; + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct BackgroundHealInfo { + bitrot_start_time: SystemTime, + bitrot_start_cycle: u64, + current_scan_mode: HealScanMode, +} + +impl Default for BackgroundHealInfo { + fn default() -> Self { + Self { + bitrot_start_time: SystemTime::now(), + bitrot_start_cycle: Default::default(), + current_scan_mode: Default::default(), + } + } +} + +async fn read_background_heal_info(store: &ECStore) -> BackgroundHealInfo { + if *GLOBAL_IsErasureSD.read().await { + return BackgroundHealInfo::default(); + } + + let buf = read_config(store, &BACKGROUND_HEAL_INFO_PATH) + .await + .map_or(Vec::new(), |buf| buf); + if buf.is_empty() { + return BackgroundHealInfo::default(); + } + serde_json::from_slice::(&buf).map_or(BackgroundHealInfo::default(), |b| b) +} + +async fn save_background_heal_info(store: &ECStore, info: &BackgroundHealInfo) { + if *GLOBAL_IsErasureSD.read().await { + return; + } + let b = match serde_json::to_vec(info) { + Ok(info) => info, + Err(_) => return, + }; + let _ = save_config(store, &BACKGROUND_HEAL_INFO_PATH, &b).await; +} + +async fn get_cycle_scan_mode(current_cycle: u64, bitrot_start_cycle: u64, bitrot_start_time: SystemTime) -> HealScanMode { + let bitrot_cycle = globalHealConfig.read().await.bitrot_scan_cycle(); + let v = bitrot_cycle.as_secs_f64() ; + if v == -1.0 { + return HEAL_NORMAL_SCAN; + } else if v == 0.0 { + return HEAL_DEEP_SCAN; + } + + if current_cycle - bitrot_start_cycle < HEAL_OBJECT_SELECT_PROB { + return HEAL_DEEP_SCAN; + } + + if bitrot_start_time.duration_since(SystemTime::now()).unwrap() > bitrot_cycle { + return HEAL_DEEP_SCAN; + } + + HEAL_NORMAL_SCAN +} + +#[derive(Clone, Debug)] +pub struct CurrentScannerCycle { + pub current: u64, + pub next: u64, + pub started: SystemTime, + pub cycle_completed: Vec, +} + +impl Default for CurrentScannerCycle { + fn default() -> Self { + Self { + current: Default::default(), + next: Default::default(), + started: SystemTime::now(), + cycle_completed: Default::default(), + } + } +} + +impl CurrentScannerCycle { + pub fn marshal_msg(&self) -> Result> { + let len: u32 = 4; + let mut wr = Vec::new(); + + // 字段数量 + rmp::encode::write_map_len(&mut wr, len)?; + + // write "current" + rmp::encode::write_str(&mut wr, "current")?; + rmp::encode::write_uint(&mut wr, self.current)?; + + // write "next" + rmp::encode::write_str(&mut wr, "next")?; + rmp::encode::write_uint(&mut wr, self.next)?; + + // write "started" + rmp::encode::write_str(&mut wr, "started")?; + rmp::encode::write_uint(&mut wr, system_time_to_timestamp(&self.started))?; + + // write "cycle_completed" + rmp::encode::write_str(&mut wr, "cycle_completed")?; + let mut buf = Vec::new(); + self.cycle_completed + .serialize(&mut Serializer::new(&mut buf)) + .expect("Serialization failed"); + rmp::encode::write_bin(&mut wr, &buf)?; + + Ok(wr) + } + + #[tracing::instrument] + pub fn unmarshal_msg(&mut self, buf: &[u8]) -> Result { + let mut cur = Cursor::new(buf); + + let mut fields_len = rmp::decode::read_map_len(&mut cur)?; + + while fields_len > 0 { + fields_len -= 1; + + let str_len = rmp::decode::read_str_len(&mut cur)?; + + // !!! Vec::with_capacity(str_len) 失败,vec!正常 + let mut field_buff = vec![0u8; str_len as usize]; + + cur.read_exact(&mut field_buff)?; + + let field = String::from_utf8(field_buff)?; + + match field.as_str() { + "current" => { + let u: u64 = rmp::decode::read_int(&mut cur)?; + self.current = u; + } + + "next" => { + let u: u64 = rmp::decode::read_int(&mut cur)?; + self.next = u; + } + "started" => { + let u: u64 = rmp::decode::read_int(&mut cur)?; + let started = timestamp_to_system_time(u); + self.started = started; + } + "cycleCompleted" => { + let mut buf = Vec::new(); + let _ = cur.read_to_end(&mut buf)?; + let u: Vec = + Deserialize::deserialize(&mut Deserializer::new(&buf[..])).expect("Deserialization failed"); + self.cycle_completed = u; + } + name => return Err(Error::msg(format!("not suport field name {}", name))), + } + } + + Ok(cur.position()) + } +} + +// 将 SystemTime 转换为时间戳 +fn system_time_to_timestamp(time: &SystemTime) -> u64 { + time.duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs() +} + +// 将时间戳转换为 SystemTime +fn timestamp_to_system_time(timestamp: u64) -> SystemTime { + UNIX_EPOCH + std::time::Duration::new(timestamp, 0) +} diff --git a/ecstore/src/heal/data_scanner_metric.rs b/ecstore/src/heal/data_scanner_metric.rs new file mode 100644 index 000000000..93af83106 --- /dev/null +++ b/ecstore/src/heal/data_scanner_metric.rs @@ -0,0 +1,74 @@ +use std::{ + collections::HashMap, + sync::{atomic::{AtomicU32, Ordering}, Arc}, + time::SystemTime, +}; + +use lazy_static::lazy_static; +use tokio::sync::RwLock; + +use super::data_scanner::CurrentScannerCycle; + +lazy_static! { + pub static ref globalScannerMetrics: Arc> = Arc::new(RwLock::new(ScannerMetrics::new())); +} + +#[derive(Clone, Debug, PartialEq, PartialOrd)] +pub enum ScannerMetric { + // START Realtime metrics, that only to records + // last minute latencies and total operation count. + ReadMetadata = 0, + CheckMissing, + SaveUsage, + ApplyAll, + ApplyVersion, + TierObjSweep, + HealCheck, + Ilm, + CheckReplication, + Yield, + CleanAbandoned, + ApplyNonCurrent, + HealAbandonedVersion, + + // START Trace metrics: + StartTrace, + ScanObject, // Scan object. All operations included. + HealAbandonedObject, + + // END realtime metrics: + LastRealtime, + + // Trace only metrics: + ScanFolder, // Scan a folder on disk, recursively. + ScanCycle, // Full cycle, cluster global. + ScanBucketDrive, // Single bucket on one drive. + CompactFolder, // Folder compacted. + + // Must be last: + Last, +} + +pub struct ScannerMetrics { + operations: Vec, + cycle_info: RwLock>, +} + +impl ScannerMetrics { + pub fn new() -> Self { + Self { + operations: (0..ScannerMetric::Last as usize).map(|_| AtomicU32::new(0)).collect(), + cycle_info: RwLock::new(None), + } + } + + pub fn log(&mut self, s: ScannerMetric, _paths: &[String], _custom: &HashMap, _start_time: SystemTime) { + // let duration = start_time.duration_since(start_time); + self.operations[s.clone() as usize].fetch_add(1, Ordering::SeqCst); + // Dodo + } + + pub async fn set_cycle(&mut self, c: Option) { + *self.cycle_info.write().await = c; + } +} diff --git a/ecstore/src/heal/data_usage.rs b/ecstore/src/heal/data_usage.rs new file mode 100644 index 000000000..3ffa3453d --- /dev/null +++ b/ecstore/src/heal/data_usage.rs @@ -0,0 +1,158 @@ +use std::{collections::HashMap, time::SystemTime}; + +use lazy_static::lazy_static; +use serde::{Deserialize, Serialize}; +use tokio::sync::mpsc::Receiver; +use tracing::info; + +use crate::{ + config::common::save_config, + disk::{BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, + new_object_layer_fn, + utils::path::SLASH_SEPARATOR, +}; + +pub const DATA_USAGE_ROOT: &str = SLASH_SEPARATOR; +const DATA_USAGE_OBJ_NAME: &str = ".usage.json"; +const DATA_USAGE_BLOOM_NAME: &str = ".bloomcycle.bin"; +pub const DATA_USAGE_CACHE_NAME: &str = ".usage-cache.bin"; +lazy_static! { + pub static ref DATA_USAGE_BUCKET: String = format!("{}{}{}", RUSTFS_META_BUCKET, SLASH_SEPARATOR, BUCKET_META_PREFIX); + pub static ref DATA_USAGE_OBJ_NAME_PATH: String = format!("{}{}{}", BUCKET_META_PREFIX, SLASH_SEPARATOR, DATA_USAGE_OBJ_NAME); + pub static ref DATA_USAGE_BLOOM_NAME_PATH: String = + format!("{}{}{}", BUCKET_META_PREFIX, SLASH_SEPARATOR, DATA_USAGE_BLOOM_NAME); + pub static ref BACKGROUND_HEAL_INFO_PATH: String = + format!("{}{}{}", BUCKET_META_PREFIX, SLASH_SEPARATOR, ".background-heal.json"); +} + +// BucketTargetUsageInfo - bucket target usage info provides +// - replicated size for all objects sent to this target +// - replica size for all objects received from this target +// - replication pending size for all objects pending replication to this target +// - replication failed size for all objects failed replication to this target +// - replica pending count +// - replica failed count +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct BucketTargetUsageInfo { + replication_pending_size: u64, + replication_failed_size: u64, + replicated_size: u64, + replica_size: u64, + replication_pending_count: u64, + replication_failed_count: u64, + replicated_count: u64, +} + +// BucketUsageInfo - bucket usage info provides +// - total size of the bucket +// - total objects in a bucket +// - object size histogram per bucket +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct BucketUsageInfo { + size: u64, + // Following five fields suffixed with V1 are here for backward compatibility + // Total Size for objects that have not yet been replicated + replication_pending_size_v1: u64, + // Total size for objects that have witness one or more failures and will be retried + replication_failed_size_v1: u64, + // Total size for objects that have been replicated to destination + replicated_size_v1: u64, + // Total number of objects pending replication + replication_pending_count_v1: u64, + // Total number of objects that failed replication + replication_failed_count_v1: u64, + + objects_count: u64, + object_size_histogram: HashMap, + object_versions_histogram: HashMap, + versions_count: u64, + delete_markers_count: u64, + replica_size: u64, + replica_count: u64, + replication_info: HashMap, +} + +// DataUsageInfo represents data usage stats of the underlying Object API +#[derive(Debug, Serialize, Deserialize)] +pub struct DataUsageInfo { + total_capacity: u64, + total_used_capacity: u64, + total_free_capacity: u64, + + // LastUpdate is the timestamp of when the data usage info was last updated. + // This does not indicate a full scan. + last_update: SystemTime, + + // Objects total count across all buckets + objects_total_count: u64, + // Versions total count across all buckets + versions_total_count: u64, + // Delete markers total count across all buckets + delete_markers_total_count: u64, + // Objects total size across all buckets + objects_total_size: u64, + replication_info: HashMap, + + // Total number of buckets in this cluster + buckets_count: u64, + // Buckets usage info provides following information across all buckets + // - total size of the bucket + // - total objects in a bucket + // - object size histogram per bucket + buckets_usage: HashMap, + // Deprecated kept here for backward compatibility reasons. + bucket_sizes: HashMap, + // Todo: TierStats + // TierStats contains per-tier stats of all configured remote tiers +} + +impl Default for DataUsageInfo { + fn default() -> Self { + Self { + total_capacity: Default::default(), + total_used_capacity: Default::default(), + total_free_capacity: Default::default(), + last_update: SystemTime::now(), + objects_total_count: Default::default(), + versions_total_count: Default::default(), + delete_markers_total_count: Default::default(), + objects_total_size: Default::default(), + replication_info: Default::default(), + buckets_count: Default::default(), + buckets_usage: Default::default(), + bucket_sizes: Default::default(), + } + } +} + +pub async fn store_data_usage_in_backend(mut rx: Receiver) { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => { + info!("errServerNotInitialized"); + return; + } + }; + let mut attempts = 1; + loop { + match rx.recv().await { + Some(data_usage_info) => { + if let Ok(data) = serde_json::to_vec(&data_usage_info) { + if attempts > 10 { + let _ = save_config(store, &format!("{}{}", DATA_USAGE_OBJ_NAME_PATH.to_string(), ".bkp"), &data).await; + attempts += 1; + } + let _ = save_config(store, &DATA_USAGE_OBJ_NAME_PATH, &data).await; + attempts += 1; + } else { + continue; + } + } + None => { + return; + } + } + } +} diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs new file mode 100644 index 000000000..3bbf1f504 --- /dev/null +++ b/ecstore/src/heal/data_usage_cache.rs @@ -0,0 +1,234 @@ +use http::HeaderMap; +use rand::Rng; +use rmp_serde::Serializer; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; +use std::path::Path; +use std::time::{Duration, SystemTime}; +use s3s::{S3Error, S3ErrorCode}; +use tokio::sync::mpsc::Sender; +use tokio::time::sleep; +use crate::config::common::save_config; +use crate::disk::error::DiskError; +use crate::disk::{BUCKET_META_PREFIX, RUSTFS_META_BUCKET}; +use crate::error::{Error, Result}; +use crate::new_object_layer_fn; +use crate::set_disk::SetDisks; +use crate::store_api::{HTTPRangeSpec, ObjectIO, ObjectOptions, StorageAPI}; + +use super::data_usage::DATA_USAGE_ROOT; + +// DATA_USAGE_BUCKET_LEN must be length of ObjectsHistogramIntervals +pub const DATA_USAGE_BUCKET_LEN: usize = 11; +pub const DATA_USAGE_VERSION_LEN: usize = 7; + +type DataUsageHashMap = HashSet; +// sizeHistogram is a size histogram. +type SizeHistogram = Vec; +// versionsHistogram is a histogram of number of versions in an object. +type VersionsHistogram = Vec; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ReplicationStats { + pub pending_size: u64, + pub replicated_size: u64, + pub failed_size: u64, + pub failed_count: u64, + pub pending_count: u64, + pub missed_threshold_size: u64, + pub after_threshold_size: u64, + pub missed_threshold_count: u64, + pub after_threshold_count: u64, + pub replicated_count: u64, +} + +impl ReplicationStats { + pub fn empty(&self) -> bool { + self.replicated_size == 0 && self.failed_size == 0 && self.failed_count == 0 + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ReplicationAllStats { + pub targets: HashMap, + pub replica_size: u64, + pub replica_count: u64, +} + +impl ReplicationAllStats { + pub fn empty(&self) -> bool { + if self.replica_size != 0 && self.replica_count != 0 { + return false; + } + for (_, v) in self.targets.iter() { + if !v.empty() { + return false; + } + } + + true + } +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct DataUsageEntry { + pub children: DataUsageHashMap, + // These fields do no include any children. + pub size: i64, + pub objects: u64, + pub versions: u64, + pub delete_markers: u64, + pub obj_sizes: SizeHistogram, + pub obj_versions: VersionsHistogram, + pub replication_stats: ReplicationAllStats, + // Todo: tier + // pub all_tier_stats: , + pub compacted: bool, +} + +#[derive(Clone, Serialize, Deserialize)] +pub struct DataUsageCacheInfo { + pub name: String, + pub next_cycle: usize, + pub last_update: SystemTime, + pub skip_healing: bool, + // todo: life_cycle + // pub life_cycle: + #[serde(skip)] + pub updates: Option>, + // Todo: replication + // #[serde(skip_serializing)] + // replication: +} + +impl Default for DataUsageCacheInfo { + fn default() -> Self { + Self { + name: Default::default(), + next_cycle: Default::default(), + last_update: SystemTime::now(), + skip_healing: Default::default(), + updates: Default::default(), + } + } +} + +#[derive(Clone, Default, Serialize, Deserialize)] +pub struct DataUsageCache { + pub info: DataUsageCacheInfo, + pub cache: HashMap, +} + +impl DataUsageCache { + pub async fn load(store: &SetDisks, name: &str) -> Result { + let mut d = DataUsageCache::default(); + let mut retries = 0; + while retries < 5 { + let path = Path::new(BUCKET_META_PREFIX).join(name); + match store + .get_object_reader( + RUSTFS_META_BUCKET, + path.to_str().unwrap(), + HTTPRangeSpec::nil(), + HeaderMap::new(), + &ObjectOptions { + no_lock: true, + ..Default::default() + }, + ) + .await + { + Ok(mut reader) => { + if let Ok(info) = Self::unmarshal(&reader.read_all().await?) { + d = info + } + break; + } + Err(err) => match err.downcast_ref::() { + Some(DiskError::FileNotFound) | Some(DiskError::VolumeNotFound) => { + match store + .get_object_reader( + RUSTFS_META_BUCKET, + name, + HTTPRangeSpec::nil(), + HeaderMap::new(), + &ObjectOptions { + no_lock: true, + ..Default::default() + }, + ) + .await + { + Ok(mut reader) => { + if let Ok(info) = Self::unmarshal(&reader.read_all().await?) { + d = info + } + break; + } + Err(_) => match err.downcast_ref::() { + Some(DiskError::FileNotFound) | Some(DiskError::VolumeNotFound) => { + break; + } + _ => {} + }, + } + } + _ => {} + }, + } + retries += 1; + let mut rng = rand::thread_rng(); + sleep(Duration::from_millis(rng.gen_range(0..1_000))).await; + } + Ok(d) + } + + pub async fn save(&self, name: &str) -> Result<()> { + let buf = self.marshal_msg()?; + let buf_clone = buf.clone(); + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => return Err(Error::from(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()))), + }; + let store_clone = store.clone(); + let name_clone = name.to_string(); + tokio::spawn(async move { + let _ = save_config(&store_clone, &format!("{}{}", &name_clone, ".bkp"), &buf_clone).await; + }); + save_config(&store, name, &buf).await + } + + pub fn replace(&mut self, path: &str, parent: &str, e: DataUsageEntry) { + let hash = hash_path(path); + } + + pub fn marshal_msg(&self) -> Result> { + let mut buf = Vec::new(); + + self.serialize(&mut Serializer::new(&mut buf))?; + + Ok(buf) + } + + pub fn unmarshal(buf: &[u8]) -> Result { + let t: Self = rmp_serde::from_slice(buf)?; + Ok(t) + } +} + +struct DataUsageHash(String); + +impl DataUsageHash { + +} + +pub fn hash_path(data: &str) -> DataUsageHash { + let mut data = data; + if data != DATA_USAGE_ROOT { + data = data.trim_matches('/'); + } + Path::new(&data); + todo!() +} diff --git a/ecstore/src/heal/heal_commands.rs b/ecstore/src/heal/heal_commands.rs index 39da448e2..5c208d309 100644 --- a/ecstore/src/heal/heal_commands.rs +++ b/ecstore/src/heal/heal_commands.rs @@ -7,12 +7,7 @@ use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use crate::{ - disk::{DeleteOptions, DiskAPI, DiskStore, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, - error::{Error, Result}, - heal::heal_ops::HEALING_TRACKER_FILENAME, - new_object_layer_fn, - store_api::{BucketInfo, StorageAPI}, - utils::fs::read_file, + disk::{DeleteOptions, DiskAPI, DiskStore, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, error::{Error, Result}, global::GLOBAL_BackgroundHealState, heal::heal_ops::HEALING_TRACKER_FILENAME, new_object_layer_fn, store_api::{BucketInfo, StorageAPI}, utils::fs::read_file }; pub type HealScanMode = usize; @@ -50,7 +45,7 @@ pub struct HealOpts { pub set: Option, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct HealDriveInfo { pub uuid: String, pub endpoint: String, @@ -259,7 +254,7 @@ impl HealingTracker { let htracker_bytes = self.marshal_msg()?; - // TODO: globalBackgroundHealState + GLOBAL_BackgroundHealState.write().await.update_heal_status(&self).await; if let Some(disk) = &self.disk { let file_path = Path::new(BUCKET_META_PREFIX).join(HEALING_TRACKER_FILENAME); @@ -430,10 +425,10 @@ async fn load_healing_tracker(disk: &Option) -> Result Result { +pub async fn init_healing_tracker(disk: DiskStore, heal_id: &str) -> Result { let mut healing_tracker = HealingTracker::default(); healing_tracker.id = disk.get_disk_id().await?.map_or("".to_string(), |id| id.to_string()); - healing_tracker.heal_id = heal_id; + healing_tracker.heal_id = heal_id.to_string(); healing_tracker.path = disk.to_string(); healing_tracker.endpoint = disk.endpoint().to_string(); healing_tracker.started = SystemTime::now() diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 9ef9ee37a..0c9415d24 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -141,6 +141,7 @@ impl HealSequence { ..Default::default() } } + } impl HealSequence { @@ -160,7 +161,7 @@ impl HealSequence { self.heal_failed_items_map.clone() } - fn count_failed(&mut self, heal_type: HealItemType) { + pub fn count_failed(&mut self, heal_type: HealItemType) { *self.heal_failed_items_map.entry(heal_type).or_insert(0) += 1; self.last_heal_activity = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -168,7 +169,7 @@ impl HealSequence { .as_secs(); } - fn count_scanned(&mut self, heal_type: HealItemType) { + pub fn count_scanned(&mut self, heal_type: HealItemType) { *self.scanned_items_map.entry(heal_type).or_insert(0) += 1; self.last_heal_activity = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -176,7 +177,7 @@ impl HealSequence { .as_secs(); } - fn count_healed(&mut self, heal_type: HealItemType) { + pub fn count_healed(&mut self, heal_type: HealItemType) { *self.healed_items_map.entry(heal_type).or_insert(0) += 1; self.last_heal_activity = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -353,10 +354,25 @@ pub struct AllHealState { } impl AllHealState { - pub fn new(cleanup: bool) -> Self { - let hstate = AllHealState::default(); + pub fn new(cleanup: bool) -> Arc> { + let hstate = Arc::new(RwLock::new(AllHealState::default())); + let (_, mut rx) = broadcast::channel(1); if cleanup { - // spawn(f); + let hstate_clone = hstate.clone(); + tokio::spawn(async move { + loop { + select! { + result = rx.recv() =>{ + if let Ok(true) = result { + return; + } + } + _ = sleep(Duration::from_secs(5 * 60)) => { + hstate_clone.write().await.periodic_heal_seqs_clean().await; + } + } + } + }); } hstate @@ -382,7 +398,7 @@ impl AllHealState { }); } - async fn update_heal_status(&mut self, tracker: &HealingTracker) { + pub async fn update_heal_status(&mut self, tracker: &HealingTracker) { let _ = self.mu.write().await; let _ = tracker.mu.read().await; @@ -427,30 +443,19 @@ impl AllHealState { }); } - async fn periodic_heal_seqs_clean(&mut self, mut rx: Receiver) { - loop { - select! { - result = rx.recv() =>{ - if let Ok(true) = result { - return; - } - } - _ = sleep(Duration::from_secs(5 * 60)) => { - let _ = self.mu.write().await; - let now = SystemTime::now(); - - let mut keys_to_reomve = Vec::new(); - for (k, v) in self.heal_seq_map.iter() { - if v.has_ended().await && (UNIX_EPOCH + Duration::from_secs(*(v.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now { - keys_to_reomve.push(k.clone()) - } - } - for key in keys_to_reomve.iter() { - self.heal_seq_map.remove(key); - } - } + async fn periodic_heal_seqs_clean(&mut self) { + let _ = self.mu.write().await; + let now = SystemTime::now(); + + let mut keys_to_reomve = Vec::new(); + for (k, v) in self.heal_seq_map.iter() { + if v.has_ended().await && (UNIX_EPOCH + Duration::from_secs(*(v.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now { + keys_to_reomve.push(k.clone()) } } + for key in keys_to_reomve.iter() { + self.heal_seq_map.remove(key); + } } async fn get_heal_sequence_by_token(&self, token: &str) -> (Option, bool) { diff --git a/ecstore/src/heal/mod.rs b/ecstore/src/heal/mod.rs index 38db00f2c..f477be10e 100644 --- a/ecstore/src/heal/mod.rs +++ b/ecstore/src/heal/mod.rs @@ -1,3 +1,7 @@ pub mod background_heal_ops; +pub mod data_scanner; +pub mod data_scanner_metric; +pub mod data_usage; pub mod heal_commands; pub mod heal_ops; +pub mod data_usage_cache; diff --git a/ecstore/src/lib.rs b/ecstore/src/lib.rs index 07551a343..7f0a32d94 100644 --- a/ecstore/src/lib.rs +++ b/ecstore/src/lib.rs @@ -9,7 +9,7 @@ pub mod erasure; pub mod error; mod file_meta; mod global; -mod heal; +pub mod heal; pub mod peer; mod quorum; pub mod set_disk; diff --git a/ecstore/src/sets.rs b/ecstore/src/sets.rs index c5dc2c07c..30d8c5a04 100644 --- a/ecstore/src/sets.rs +++ b/ecstore/src/sets.rs @@ -10,14 +10,18 @@ use uuid::Uuid; use crate::{ disk::{ + error::DiskError, format::{DistributionAlgoVersion, FormatV3}, - DiskAPI, DiskStore, + new_disk, DiskInfo, DiskOption, DiskStore, }, - endpoints::PoolEndpoints, + endpoints::{Endpoints, PoolEndpoints}, error::{Error, Result}, global::{is_dist_erasure, GLOBAL_LOCAL_DISK_SET_DRIVES}, heal::{ - heal_commands::{HealOpts, HealResultItem}, + heal_commands::{ + HealDriveInfo, HealOpts, HealResultItem, DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE, + DRIVE_STATE_OK, HEAL_ITEM_METADATA, + }, heal_ops::HealObjectFn, }, set_disk::SetDisks, @@ -26,7 +30,9 @@ use crate::{ ListMultipartsInfo, ListObjectsV2Info, MakeBucketOptions, MultipartUploadResult, ObjectIO, ObjectInfo, ObjectOptions, ObjectToDelete, PartInfo, PutObjReader, StorageAPI, }, - utils::hash, + store_init::{check_format_erasure_values, get_format_erasure_in_quorum, load_format_erasure_all, save_format_file}, + + utils::hash,, }; use tokio::time::Duration; @@ -489,13 +495,99 @@ impl StorageAPI for Sets { async fn delete_bucket(&self, _bucket: &str, _opts: &DeleteBucketOptions) -> Result<()> { unimplemented!() } - async fn heal_format(&self, dry_run: bool) -> Result { - unimplemented!() + async fn heal_format(&self, dry_run: bool) -> Result<(HealResultItem, Option)> { + let (disks, _) = init_storage_disks_with_errors( + &self.endpoints.endpoints, + &DiskOption { + cleanup: false, + health_check: false, + }, + ) + .await; + let (formats, errs) = load_format_erasure_all(&disks, true).await; + if let Err(err) = check_format_erasure_values(&formats, self.set_drive_count) { + return Ok((HealResultItem::default(), Some(err))); + } + let ref_format = match get_format_erasure_in_quorum(&formats) { + Ok(format) => format, + Err(err) => return Ok((HealResultItem::default(), Some(err))), + }; + let mut res = HealResultItem { + heal_item_type: HEAL_ITEM_METADATA.to_string(), + detail: "disk-format".to_string(), + disk_count: self.set_count * self.set_drive_count, + set_count: self.set_count, + ..Default::default() + }; + let before_derives = formats_to_drives_info(&self.endpoints.endpoints, &formats, &errs); + res.before = vec![HealDriveInfo::default(); before_derives.len()]; + res.after = vec![HealDriveInfo::default(); before_derives.len()]; + + for v in before_derives.iter() { + res.before.push(v.clone()); + res.after.push(v.clone()); + } + if DiskError::UnformattedDisk.count_errs(&errs) == 0 { + return Ok((res, Some(Error::new(DiskError::NoHealRequired)))); + } + + if !self.format.eq(&ref_format) { + return Ok((res, Some(Error::new(DiskError::CorruptedFormat)))); + } + + let format_op_id = Uuid::new_v4().to_string(); + let (new_format_sets, current_disks_info) = new_heal_format_sets(&ref_format, self.set_count, self.set_drive_count, &formats, &errs); + if !dry_run { + let mut tmp_new_formats = vec![None; self.set_count*self.set_drive_count]; + for (i, set) in new_format_sets.iter().enumerate() { + for (j, fm) in set.iter().enumerate() { + if let Some(fm) = fm { + res.after[i*self.set_drive_count+j].uuid = fm.erasure.this.to_string(); + res.after[i*self.set_drive_count+j].state = DRIVE_STATE_OK.to_string(); + tmp_new_formats[i*self.set_drive_count+j] = Some(fm.clone()); + } + } + } + // Save new formats `format.json` on unformatted disks. + for (fm, disk) in tmp_new_formats.iter_mut().zip(disks.iter()) { + if fm.is_some() && disk.is_some() { + if save_format_file(disk, fm, &format_op_id).await.is_err() { + let _ = disk.as_ref().unwrap().close().await; + *fm = None; + } + } + } + + for (index, fm) in tmp_new_formats.iter().enumerate() { + if let Some(fm) = fm { + let (m, n) = match ref_format.find_disk_index_by_disk_id(fm.erasure.this) { + Ok((m, n)) => (m, n), + Err(_) => continue, + }; + if let Some(set) = self.disk_set.get(m) { + if let Some(Some(disk)) = set.disks.read().await.get(n) { + let _ = disk.close().await; + } + } + + if let Some(Some(disk)) = disks.get(index) { + self.disk_set[m].renew_disk(&disk.endpoint()).await; + } + } + } + } + Ok((res, None)) } async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { unimplemented!() } - async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result { + async fn heal_object( + &self, + bucket: &str, + object: &str, + version_id: &str, + opts: &HealOpts, + ) -> Result<(HealResultItem, Option)> { self.get_disks_by_key(object) .heal_object(bucket, object, version_id, opts) .await @@ -510,3 +602,119 @@ impl StorageAPI for Sets { unimplemented!() } } + +async fn close_storage_disks(disks: &[Option]) { + let mut futures = Vec::with_capacity(disks.len()); + for disk in disks.iter() { + if let Some(disk) = disk { + let disk = disk.clone(); + futures.push(tokio::spawn(async move { + let _ = disk.close().await; + })); + } + } + let _ = join_all(futures).await; +} + +async fn init_storage_disks_with_errors( + endpoints: &Endpoints, + opts: &DiskOption, +) -> (Vec>, Vec>) { + // Bootstrap disks. + let disks = Arc::new(RwLock::new(vec![None; endpoints.as_ref().len()])); + let errs = Arc::new(RwLock::new(vec![None; endpoints.as_ref().len()])); + let mut futures = Vec::with_capacity(endpoints.as_ref().len()); + for (index, endpoint) in endpoints.as_ref().iter().enumerate() { + let ep = endpoint.clone(); + let opt = opts.clone(); + let disks_clone = disks.clone(); + let errs_clone = errs.clone(); + futures.push(tokio::spawn(async move { + match new_disk(&ep, &opt).await { + Ok(disk) => { + disks_clone.write().await[index] = Some(disk); + errs_clone.write().await[index] = None; + } + Err(err) => { + disks_clone.write().await[index] = None; + errs_clone.write().await[index] = Some(err); + } + } + })); + } + let _ = join_all(futures).await; + let disks = disks.read().await.clone(); + let errs = errs.read().await.clone(); + (disks, errs) +} + +fn formats_to_drives_info(endpoints: &Endpoints, formats: &[Option], errs: &[Option]) -> Vec { + let mut before_drives = Vec::with_capacity(endpoints.as_ref().len()); + for (index, format) in formats.iter().enumerate() { + let drive = endpoints.get_string(index); + let mut state = if format.is_some() { + DRIVE_STATE_OK + } else { + if let Some(Some(err)) = errs.get(index) { + match err.downcast_ref::() { + Some(DiskError::UnformattedDisk) => DRIVE_STATE_MISSING, + Some(DiskError::DiskNotFound) => DRIVE_STATE_OFFLINE, + _ => DRIVE_STATE_CORRUPT, + }; + } + DRIVE_STATE_CORRUPT + }; + + let uuid = if let Some(format) = format { + format.erasure.this.to_string() + } else { + "".to_string() + }; + before_drives.push(HealDriveInfo { + uuid, + endpoint: drive, + state: state.to_string(), + }); + } + before_drives +} + +fn new_heal_format_sets( + ref_format: &FormatV3, + set_count: usize, + set_drive_count: usize, + formats: &[Option], + errs: &[Option], +) -> (Vec>>, Vec>) { + let mut new_formats = vec![vec![None; set_drive_count]; set_count]; + let mut current_disks_info = vec![vec![DiskInfo::default(); set_drive_count]; set_count]; + for (i, set) in ref_format.erasure.sets.iter().enumerate() { + for (j, value) in set.iter().enumerate() { + if let Some(Some(err)) = errs.get(i*set_drive_count+j) { + match err.downcast_ref::() { + Some(DiskError::UnformattedDisk) => { + let mut fm = FormatV3::new(set_count, set_drive_count); + fm.id = ref_format.id; + fm.format = ref_format.format.clone(); + fm.version = ref_format.version.clone(); + fm.erasure.this = ref_format.erasure.sets[i][j]; + fm.erasure.sets = ref_format.erasure.sets.clone(); + fm.erasure.version = ref_format.erasure.version.clone(); + fm.erasure.distribution_algo = ref_format.erasure.distribution_algo.clone(); + new_formats[i][j] = Some(fm); + }, + _ => {}, + } + } + if let (Some(format), None) = (&formats[i*set_drive_count+j], &errs[i*set_drive_count+j]) { + if let Some(info) = &format.disk_info { + if !info.endpoint.is_empty() { + current_disks_info[i][j] = info.clone(); + } + } + } + } + } + + (new_formats, current_disks_info) +} diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index 9f361d482..b9d1c492e 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -10,7 +10,8 @@ use crate::global::{ is_dist_erasure, is_erasure_sd, set_global_deployment_id, set_object_layer, DISK_ASSUME_UNKNOWN_SIZE, DISK_FILL_FRACTION, DISK_MIN_INODES, DISK_RESERVE_FRACTION, GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, }; -use crate::heal::heal_commands::{HealOpts, HealResultItem, HealScanMode}; +use crate::heal::data_usage::DataUsageInfo; +use crate::heal::heal_commands::{HealOpts, HealResultItem, HealScanMode, HEAL_ITEM_METADATA}; use crate::heal::heal_ops::HealObjectFn; use crate::new_object_layer_fn; use crate::store_api::{ListMultipartsInfo, ObjectIO}; @@ -43,6 +44,7 @@ use http::HeaderMap; use lazy_static::lazy_static; use rand::Rng; use s3s::dto::{BucketVersioningStatus, ObjectLockConfiguration, ObjectLockEnabled, VersioningConfiguration}; +use tokio::sync::mpsc::Sender; use std::cmp::Ordering; use std::slice::Iter; use std::{ @@ -52,10 +54,11 @@ use std::{ }; use time::OffsetDateTime; use tokio::fs; -use tokio::sync::Semaphore; +use tokio::sync::{mpsc, RwLock, Semaphore}; use tracing::{debug, info, warn}; use uuid::Uuid; +use crate::heal::data_usage_cache::DataUsageCache; const MAX_UPLOADS_LIST: usize = 10000; @@ -488,6 +491,47 @@ impl ECStore { internal_get_pool_info_existing_with_opts(&self.pools, bucket, object, opts).await } + pub async fn ns_scanner(&self, updates: Sender, want_cycle: usize, heal_scan_mode: HealScanMode) -> Result<()> { + let all_buckets = self.list_bucket(&BucketOptions::default()).await?; + if all_buckets.is_empty() { + let _ = updates.send(DataUsageInfo::default()).await; + return Ok(()); + } + + let mut total_results = 0; + let mut result_index = 0; + self.pools.iter().for_each(|pool| { + total_results += pool.disk_set.len(); + }); + let mut results = Arc::new(RwLock::new(vec![DataUsageCache::default(); total_results])); + let mut futures = Vec::new(); + for pool in self.pools.iter() { + for set in pool.disk_set.iter() { + let index = result_index; + let results_clone = results.clone(); + futures.push(async move { + let (tx, mut rx) = mpsc::channel(100); + let task = tokio::spawn(async move { + loop { + match rx.recv().await { + Some(info) => { + results_clone.write().await[index] = info; + }, + None => { + return ; + } + } + } + }); + + let _ = task.await; + }); + result_index += 1; + } + } + Ok(()) + } + async fn get_latest_object_info_with_idx( &self, bucket: &str, @@ -1369,51 +1413,93 @@ impl StorageAPI for ECStore { } counts } - async fn heal_format(&self, dry_run: bool) -> Result { - unimplemented!() + async fn heal_format(&self, dry_run: bool) -> Result<(HealResultItem, Option)> { + let mut r = HealResultItem { + heal_item_type: HEAL_ITEM_METADATA.to_string(), + detail: "disk-format".to_string(), + ..Default::default() + }; + + let mut count_no_heal = 0; + for pool in self.pools.iter() { + let (mut result, err) = pool.heal_format(dry_run).await?; + if let Some(err) = err { + match err.downcast_ref::() { + Some(DiskError::NoHealRequired) => { + count_no_heal += 1; + }, + _ => { + + continue; + } + } + } + r.disk_count += result.disk_count; + r.set_count += result.set_count; + r.before.append(&mut result.before); + r.after.append(&mut result.after); + + } + if count_no_heal == self.pools.len() { + return Ok((r, Some(Error::new(DiskError::NoHealRequired)))); + } + Ok((r, None)) } async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { unimplemented!() } - async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result { + async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result<(HealResultItem, Option)> { let object = utils::path::encode_dir_object(object); - let mut errs = HashMap::new(); - let mut results = HashMap::new(); + let errs = Arc::new(RwLock::new(vec![None; self.pools.len()])); + let results = Arc::new(RwLock::new(vec![HealResultItem::default(); self.pools.len()])); + let mut futures = Vec::with_capacity(self.pools.len()); for (idx, pool) in self.pools.iter().enumerate() { //TODO: IsSuspended - match pool.heal_object(bucket, &object, version_id, opts).await { - Ok(mut result) => { - result.object = utils::path::decode_dir_object(&result.object); - results.insert(idx, result); + let object = object.clone(); + let results = results.clone(); + let errs = errs.clone(); + futures.push(async move { + match pool.heal_object(bucket, &object, version_id, opts).await { + Ok((mut result, err)) => { + result.object = utils::path::decode_dir_object(&result.object); + results.write().await.insert(idx, result); + errs.write().await.insert(idx, err); + } + Err(err) => { + errs.write().await.insert(idx, Some(err)); + } } - Err(err) => { - errs.insert(idx, err); - } - } + }); } + let _ = join_all(futures).await; // Return the first nil error - for i in 0..self.pools.len() { - if !errs.contains_key(&i) { - return Ok(results.remove(&i).unwrap()); + for (index, err) in errs.read().await.iter().enumerate() { + if err.is_none() { + return Ok((results.write().await.remove(index), None)); } } // No pool returned a nil error, return the first non 'not found' error - for (k, err) in errs.iter() { - match err.downcast_ref::() { - Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} - _ => return Ok(results.remove(k).unwrap()), + for (index, err) in errs.read().await.iter().enumerate() { + match err { + Some(err) => match err.downcast_ref::() { + Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} + _ => return Ok((results.write().await.remove(index), Some(err.clone()))), + }, + None => { + return Ok((results.write().await.remove(index), None)); + } } } // At this stage, all errors are 'not found' if !version_id.is_empty() { - return Err(Error::new(DiskError::FileVersionNotFound)); + return Ok((HealResultItem::default(), Some(Error::new(DiskError::FileVersionNotFound)))); } - Err(Error::new(DiskError::FileNotFound)) + Ok((HealResultItem::default(), Some(Error::new(DiskError::FileNotFound)))) } async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()> { let mut first_err = None; diff --git a/ecstore/src/store_api.rs b/ecstore/src/store_api.rs index 8cc0342f6..c64180d2b 100644 --- a/ecstore/src/store_api.rs +++ b/ecstore/src/store_api.rs @@ -22,6 +22,8 @@ pub const ERASURE_ALGORITHM: &str = "rs-vandermonde"; pub const BLOCK_SIZE_V2: usize = 1048576; // 1M pub const RESERVED_METADATA_PREFIX: &str = "X-Rustfs-Internal-"; pub const RESERVED_METADATA_PREFIX_LOWER: &str = "X-Rustfs-Internal-"; +pub const RUSTFS_HEALING: &str = "X-Rustfs-Internal-healing"; +pub const RUSTFS_DATA_MOVE: &str = "X-Rustfs-Internal-data-mov"; // #[derive(Debug, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] @@ -100,6 +102,12 @@ impl FileInfo { false } + pub fn inline_data(&self) -> bool { + self.metadata.as_ref().map_or(false, |metadata| { + metadata.contains_key(&format!("{}inline-data", RESERVED_METADATA_PREFIX_LOWER)) && !self.is_remote() + }) + } + pub fn get_etag(&self) -> Option { if let Some(meta) = &self.metadata { meta.get("etag").cloned() @@ -237,6 +245,16 @@ impl FileInfo { Err(Error::msg("part not found")) } + pub fn set_healing(&mut self) { + if self.metadata.is_none() { + self.metadata = Some(HashMap::new()); + } + + if let Some(metadata) = self.metadata.as_mut() { + metadata.insert(RUSTFS_HEALING.to_string(), "true".to_string()); + } + } + pub fn set_inline_data(&mut self) { if let Some(meta) = self.metadata.as_mut() { meta.insert("x-rustfs-inline-data".to_owned(), "true".to_owned()); @@ -899,9 +917,9 @@ pub trait StorageAPI: ObjectIO { async fn put_object_tags(&self, bucket: &str, object: &str, tags: &str, opts: &ObjectOptions) -> Result; async fn delete_object_tags(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result; - async fn heal_format(&self, dry_run: bool) -> Result; + async fn heal_format(&self, dry_run: bool) ->Result<(HealResultItem, Option)>; async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result; - async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result; + async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result<(HealResultItem, Option)>; async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()>; async fn get_pool_and_set(&self, id: &str) -> Result<(Option, Option, Option)>; async fn check_abandoned_parts(&self, bucket: &str, object: &str, opts: &HealOpts) -> Result<()>; diff --git a/ecstore/src/store_init.rs b/ecstore/src/store_init.rs index 6d8f7dd53..e531d6470 100644 --- a/ecstore/src/store_init.rs +++ b/ecstore/src/store_init.rs @@ -2,12 +2,10 @@ use crate::config::{storageclass, KVS}; use crate::disk::DiskAPI; use crate::{ disk::{ - error::DiskError, - format::{FormatErasureVersion, FormatMetaVersion, FormatV3}, - new_disk, DiskOption, DiskStore, FORMAT_CONFIG_FILE, RUSTFS_META_BUCKET, + error::DiskError, format::{FormatErasureVersion, FormatMetaVersion, FormatV3}, new_disk, DiskInfoOptions, DiskOption, DiskStore, FORMAT_CONFIG_FILE, RUSTFS_META_BUCKET }, endpoints::Endpoints, - error::{Error, Result}, + error::{Error, Result}, heal::heal_commands::init_healing_tracker, }; use futures::future::join_all; use std::{ @@ -114,7 +112,7 @@ fn init_format_erasure( fms } -fn get_format_erasure_in_quorum(formats: &[Option]) -> Result { +pub fn get_format_erasure_in_quorum(formats: &[Option]) -> Result { let mut countmap = HashMap::new(); for f in formats.iter() { @@ -148,7 +146,7 @@ fn get_format_erasure_in_quorum(formats: &[Option]) -> Result], // disks: &Vec>, set_drive_count: usize, @@ -184,7 +182,7 @@ fn check_format_erasure_value(format: &FormatV3) -> Result<()> { } // load_format_erasure_all 读取所有foramt.json -async fn load_format_erasure_all(disks: &[Option], heal: bool) -> (Vec>, Vec>) { +pub async fn load_format_erasure_all(disks: &[Option], heal: bool) -> (Vec>, Vec>) { let mut futures = Vec::with_capacity(disks.len()); let mut datas = Vec::with_capacity(disks.len()); let mut errors = Vec::with_capacity(disks.len()); @@ -220,7 +218,7 @@ async fn load_format_erasure_all(disks: &[Option], heal: bool) -> (Ve (datas, errors) } -pub async fn load_format_erasure(disk: &DiskStore, _heal: bool) -> Result { +pub async fn load_format_erasure(disk: &DiskStore, heal: bool) -> Result { let data = disk .read_all(RUSTFS_META_BUCKET, FORMAT_CONFIG_FILE) .await @@ -231,9 +229,15 @@ pub async fn load_format_erasure(disk: &DiskStore, _heal: bool) -> Result e, })?; - let fm = FormatV3::try_from(data.as_slice())?; + let mut fm = FormatV3::try_from(data.as_slice())?; - // TODO: heal + if heal { + let info = disk.disk_info(&DiskInfoOptions { + noop: heal, + ..Default::default() + }).await?; + fm.disk_info = Some(info); + } Ok(fm) } @@ -242,7 +246,7 @@ async fn save_format_file_all(disks: &[Option], formats: &[Option], formats: &[Option, format: &Option) -> Result<()> { +pub async fn save_format_file(disk: &Option, format: &Option, heal_id: &str) -> Result<()> { if disk.is_none() { return Err(Error::new(DiskError::DiskNotFound)); } @@ -281,6 +285,10 @@ async fn save_format_file(disk: &Option, format: &Option) - .await?; disk.set_disk_id(Some(format.erasure.this)).await?; + if !heal_id.is_empty() { + let mut ht = init_healing_tracker(disk.clone(), heal_id).await?; + return ht.save().await; + } Ok(()) } diff --git a/ecstore/src/utils/bool_flag.rs b/ecstore/src/utils/bool_flag.rs new file mode 100644 index 000000000..895fd9763 --- /dev/null +++ b/ecstore/src/utils/bool_flag.rs @@ -0,0 +1,15 @@ +use crate::error::{Error, Result}; + +pub fn parse_bool(str: &str) -> Result { + match str { + "1"| "t"| "T"| "true"| "TRUE"| "True"| "on"| "ON"| "On"| "enabled" => { + return Ok(true); + }, + "0"| "f"| "F"| "false"| "FALSE"| "False"| "off"| "OFF"| "Off"| "disabled" => { + return Ok(false); + } + _ => { + return Err(Error::from_string(format!("ParseBool: parsing {}", str))); + } + } +} \ No newline at end of file diff --git a/ecstore/src/utils/mod.rs b/ecstore/src/utils/mod.rs index daff92a6c..c1f6ce7d8 100644 --- a/ecstore/src/utils/mod.rs +++ b/ecstore/src/utils/mod.rs @@ -1,5 +1,6 @@ pub mod crypto; pub mod ellipses; +pub mod bool_flag; pub mod fs; pub mod hash; pub mod net; diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index 46daded39..975d4c9b4 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -6,9 +6,12 @@ mod storage; use clap::Parser; use common::error::{Error, Result}; use ecstore::{ + bucket::metadata_sys::init_bucket_metadata_sys, endpoints::EndpointServerPools, + heal::data_scanner::init_data_scanner, set_global_endpoints, store::{init_local_disks, ECStore}, + store_api::{BucketOptions, StorageAPI}, update_erasure_type, }; use grpc::make_server; @@ -184,6 +187,8 @@ async fn run(opt: config::Opt) -> Result<()> { .map_err(|err| Error::from_string(err.to_string()))?; store.init().await.map_err(|err| Error::from_string(err.to_string()))?; + // init scanner + init_data_scanner().await; tokio::select! { _ = tokio::signal::ctrl_c() => { From be7d1ab0cce40622b6544affd244bca778b154cb Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Wed, 13 Nov 2024 13:10:51 +0000 Subject: [PATCH 02/11] tmp(2) Signed-off-by: junxiang Mu <1948535941@qq.com> --- Cargo.lock | 6 + common/common/src/lib.rs | 19 + ecstore/Cargo.toml | 1 + ecstore/src/bucket/metadata_sys.rs | 2 +- ecstore/src/cache_value/metacache_set.rs | 25 +- ecstore/src/disk/local.rs | 38 ++ ecstore/src/disk/mod.rs | 10 + ecstore/src/disk/remote.rs | 14 +- ecstore/src/heal/data_scanner.rs | 656 ++++++++++++++++++++++- ecstore/src/heal/data_usage_cache.rs | 515 +++++++++++++++++- ecstore/src/heal/error.rs | 1 + ecstore/src/heal/heal_ops.rs | 24 +- ecstore/src/heal/mod.rs | 1 + ecstore/src/peer.rs | 2 +- ecstore/src/utils/path.rs | 13 + 15 files changed, 1272 insertions(+), 55 deletions(-) create mode 100644 ecstore/src/heal/error.rs diff --git a/Cargo.lock b/Cargo.lock index 5a24b8a1d..880e5d497 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,6 +336,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + [[package]] name = "bytestring" version = "1.3.1" diff --git a/common/common/src/lib.rs b/common/common/src/lib.rs index b7a0605d3..f3b5db329 100644 --- a/common/common/src/lib.rs +++ b/common/common/src/lib.rs @@ -1,2 +1,21 @@ pub mod error; pub mod globals; + +/// Defers evaluation of a block of code until the end of the scope. +#[macro_export] macro_rules! defer { + ($($body:tt)*) => { + let _guard = { + pub struct Guard(Option); + + impl Drop for Guard { + fn drop(&mut self) { + (self.0).take().map(|f| f()); + } + } + + Guard(Some(|| { + let _ = { $($body)* }; + })) + }; + }; +} diff --git a/ecstore/Cargo.toml b/ecstore/Cargo.toml index 1208304da..8b8028904 100644 --- a/ecstore/Cargo.toml +++ b/ecstore/Cargo.toml @@ -13,6 +13,7 @@ async-trait.workspace = true backon.workspace = true blake2 = "0.10.6" bytes.workspace = true +bytesize = "1.3.0" common.workspace = true reader.workspace = true glob = "0.3.1" diff --git a/ecstore/src/bucket/metadata_sys.rs b/ecstore/src/bucket/metadata_sys.rs index 764a57b50..03ece0d3d 100644 --- a/ecstore/src/bucket/metadata_sys.rs +++ b/ecstore/src/bucket/metadata_sys.rs @@ -28,7 +28,7 @@ use super::target::BucketTargets; use lazy_static::lazy_static; lazy_static! { - static ref GLOBAL_BucketMetadataSys: Arc> = Arc::new(RwLock::new(BucketMetadataSys::new())); + pub static ref GLOBAL_BucketMetadataSys: Arc> = Arc::new(RwLock::new(BucketMetadataSys::new())); } pub async fn init_bucket_metadata_sys(api: ECStore, buckets: Vec) { diff --git a/ecstore/src/cache_value/metacache_set.rs b/ecstore/src/cache_value/metacache_set.rs index 42b81a20f..18b698a9e 100644 --- a/ecstore/src/cache_value/metacache_set.rs +++ b/ecstore/src/cache_value/metacache_set.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{future::Future, pin::Pin, sync::Arc}; use tokio::{ spawn, @@ -14,6 +14,10 @@ use crate::{ error::{Error, Result}, }; +type AgreedFn = Box Pin>> + Send + 'static>; +type PartialFn = Box]) -> Pin>> + Send + 'static>; +type FinishedFn = Box]) -> Pin + Send>> + Send + 'static>; + #[derive(Default)] pub struct ListPathRawOptions { pub disks: Vec>, @@ -26,9 +30,12 @@ pub struct ListPathRawOptions { pub min_disks: usize, pub report_not_found: bool, pub per_disk_limit: i32, - pub agreed: Option>, - pub partial: Option]) + Send + Sync>>, - pub finished: Option]) + Send + Sync>>, + pub agreed: Option, + pub partial: Option, + pub finished: Option, + // pub agreed: Option>, + // pub partial: Option]) + Send + Sync>>, + // pub finished: Option]) + Send + Sync>>, } impl Clone for ListPathRawOptions { @@ -185,8 +192,8 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - } if has_err > 0 && has_err > opts.disks.len() - opts.min_disks { - if let Some(finished_fn) = opts.finished.clone() { - finished_fn(&errs); + if let Some(finished_fn) = opts.finished.as_ref() { + finished_fn(&errs).await; } let mut combined_err = Vec::new(); errs.iter().zip(opts.disks.iter()).for_each(|(err, disk)| match (err, disk) { @@ -205,7 +212,7 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - // Break if all at EOF or error. if at_eof + has_err == readers.len() { if has_err > 0 { - if let Some(finished_fn) = opts.finished.clone() { + if let Some(finished_fn) = opts.finished.as_ref() { finished_fn(&errs); } break; @@ -213,13 +220,13 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - } if agree == readers.len() { - if let Some(agreed_fn) = opts.agreed.clone() { + if let Some(agreed_fn) = opts.agreed.as_ref() { agreed_fn(current); } continue; } - if let Some(partial_fn) = opts.partial.clone() { + if let Some(partial_fn) = opts.partial.as_ref() { partial_fn(MetaCacheEntries(top_entries), &errs); } } diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index d34687c01..75ebc2642 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -9,6 +9,7 @@ use super::{ UpdateMetadataOpts, VolumeInfo, WalkDirOptions, }; use crate::bitrot::bitrot_verify; +use crate::bucket::metadata_sys::GLOBAL_BucketMetadataSys; use crate::cache_value::cache::{Cache, Opts}; use crate::disk::error::{ convert_access_error, is_sys_err_handle_invalid, is_sys_err_invalid_arg, is_sys_err_is_dir, is_sys_err_not_dir, @@ -18,6 +19,10 @@ use crate::disk::os::{check_path_length, is_empty_dir}; use crate::disk::{LocalFileReader, LocalFileWriter, STORAGE_FORMAT_FILE}; use crate::error::{Error, Result}; use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold}; +use crate::heal::data_scanner::has_active_rules; +use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry}; +use crate::heal::heal_commands::HealScanMode; +use crate::new_object_layer_fn; 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, @@ -31,7 +36,9 @@ use crate::{ store_api::{FileInfo, RawFileInfo}, utils, }; +use common::defer; use path_absolutize::Absolutize; +use s3s::dto::{ReplicationConfiguration, ReplicationRuleStatus}; use std::collections::HashSet; use std::fmt::Debug; use std::io::Cursor; @@ -47,6 +54,7 @@ use time::OffsetDateTime; use tokio::fs::{self, File}; use tokio::io::{AsyncReadExt, AsyncWriteExt, ErrorKind}; use tokio::runtime::Runtime; +use tokio::sync::mpsc::Sender; use tokio::sync::RwLock; use tracing::{error, info, warn}; use uuid::Uuid; @@ -1868,6 +1876,36 @@ impl DiskAPI for LocalDisk { Ok(info) } + + async fn ns_scanner( + &self, + cache: &DataUsageCache, + updates: Sender, + scan_mode: HealScanMode, + ) -> Result { + self.scanning.fetch_add(1, Ordering::SeqCst); + defer!(|| { self.scanning.fetch_sub(1, Ordering::SeqCst) }); + + // Check if the current bucket has replication configuration + if let Ok((rcfg, _)) = GLOBAL_BucketMetadataSys + .read() + .await + .get_replication_config(&cache.info.name) + .await + { + if has_active_rules(&rcfg, "", true) { + // TODO: globalBucketTargetSys + } + } + + 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")), + }; + todo!() + } } async fn get_disk_info(drive_path: PathBuf) -> Result<(Info, bool)> { diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index 3a59fa250..920ca072d 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -17,6 +17,10 @@ use crate::{ erasure::{ReadAt, Writer}, error::{Error, Result}, file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion}, + heal::{ + data_usage_cache::{DataUsageCache, DataUsageEntry}, + heal_commands::HealScanMode, + }, store_api::{FileInfo, RawFileInfo}, }; use endpoint::Endpoint; @@ -436,6 +440,12 @@ pub trait DiskAPI: Debug + Send + Sync + 'static { async fn write_all(&self, volume: &str, path: &str, data: Vec) -> Result<()>; async fn read_all(&self, volume: &str, path: &str) -> Result>; async fn disk_info(&self, opts: &DiskInfoOptions) -> Result; + async fn ns_scanner( + &self, + cache: &DataUsageCache, + updates: Sender, + scan_mode: HealScanMode, + ) -> Result; } #[derive(Debug, Default, Serialize, Deserialize)] diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index 0eefe1c58..aff542350 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -10,6 +10,7 @@ use protos::{ UpdateMetadataRequest, VerifyFileRequest, WalkDirRequest, WriteAllRequest, WriteMetadataRequest, }, }; +use tokio::sync::mpsc::Sender; use tonic::Request; use tracing::info; use uuid::Uuid; @@ -20,9 +21,7 @@ use super::{ RemoteFileWriter, RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions, }; use crate::{ - disk::error::DiskError, - error::{Error, Result}, - store_api::{FileInfo, RawFileInfo}, + disk::error::DiskError, error::{Error, Result}, heal::{data_usage_cache::{DataUsageCache, DataUsageEntry}, heal_commands::HealScanMode}, store_api::{FileInfo, RawFileInfo} }; use protos::proto_gen::node_service::RenamePartRequst; @@ -729,4 +728,13 @@ impl DiskAPI for RemoteDisk { Ok(disk_info) } + + async fn ns_scanner( + &self, + cache: &DataUsageCache, + updates: Sender, + scan_mode: HealScanMode, + ) -> Result { + todo!() + } } diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs index ed290818e..06dc702eb 100644 --- a/ecstore/src/heal/data_scanner.rs +++ b/ecstore/src/heal/data_scanner.rs @@ -1,6 +1,14 @@ use std::{ + collections::{HashMap, HashSet}, + fs, + future::Future, io::{Cursor, Read}, - sync::{atomic::{AtomicU32, AtomicU64}, Arc}, + path::{Path, PathBuf}, + pin::Pin, + sync::{ + atomic::{AtomicU32, AtomicU64}, + Arc, + }, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -8,20 +16,46 @@ use byteorder::{LittleEndian, ReadBytesExt}; use lazy_static::lazy_static; use rand::Rng; use rmp_serde::{Deserializer, Serializer}; +use s3s::dto::{ReplicationConfiguration, ReplicationRuleStatus}; use serde::{Deserialize, Serialize}; -use tokio::{sync::{mpsc, RwLock}, time::sleep}; +use tokio::{ + sync::{ + broadcast, + mpsc::{self, Sender}, + RwLock, + }, + time::sleep, +}; use tracing::{error, info}; use crate::{ - config::{common::{read_config, save_config}, heal::Config}, + cache_value::metacache_set::{list_path_raw, ListPathRawOptions}, + config::{ + common::{read_config, save_config}, + heal::Config, + }, + disk::{error::DiskError, DiskStore, MetaCacheEntries, MetaCacheEntry, MetadataResolutionParams}, error::{Error, Result}, - global::GLOBAL_IsErasureSD, - heal::data_usage::BACKGROUND_HEAL_INFO_PATH, + global::{GLOBAL_BackgroundHealState, GLOBAL_IsErasure, GLOBAL_IsErasureSD}, + heal::{ + data_usage::BACKGROUND_HEAL_INFO_PATH, + data_usage_cache::{hash_path, DataUsageHashMap}, + error::ERR_IGNORE_FILE_CONTRIB, + heal_commands::{HEAL_ITEM_BUCKET, HEAL_ITEM_OBJECT}, + heal_ops::{HealSource, BG_HEALING_UUID}, + }, new_object_layer_fn, - store::ECStore, + peer::is_reserved_or_invalid_bucket, + store::{ECStore, ListPathOptions}, + utils::path::{path_join, path_to_bucket_object, path_to_bucket_object_with_base_path, SLASH_SEPARATOR}, }; -use super::{data_scanner_metric::globalScannerMetrics, data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}}; +use super::{ + data_scanner_metric::globalScannerMetrics, + data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, + data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash}, + heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}, +}; const DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16; // Visit all folders every n cycles. @@ -103,7 +137,8 @@ async fn run_data_scanner() { } let bg_heal_info = read_background_heal_info(store).await; - let scan_mode = get_cycle_scan_mode(cycle_info.current, bg_heal_info.bitrot_start_cycle, bg_heal_info.bitrot_start_time).await; + let scan_mode = + get_cycle_scan_mode(cycle_info.current, bg_heal_info.bitrot_start_cycle, bg_heal_info.bitrot_start_time).await; if bg_heal_info.current_scan_mode != scan_mode { let mut new_heal_info = bg_heal_info; new_heal_info.current_scan_mode = scan_mode; @@ -166,7 +201,7 @@ async fn save_background_heal_info(store: &ECStore, info: &BackgroundHealInfo) { async fn get_cycle_scan_mode(current_cycle: u64, bitrot_start_cycle: u64, bitrot_start_time: SystemTime) -> HealScanMode { let bitrot_cycle = globalHealConfig.read().await.bitrot_scan_cycle(); - let v = bitrot_cycle.as_secs_f64() ; + let v = bitrot_cycle.as_secs_f64(); if v == -1.0 { return HEAL_NORMAL_SCAN; } else if v == 0.0 { @@ -291,3 +326,606 @@ fn system_time_to_timestamp(time: &SystemTime) -> u64 { fn timestamp_to_system_time(timestamp: u64) -> SystemTime { UNIX_EPOCH + std::time::Duration::new(timestamp, 0) } + +#[derive(Debug, Default)] +struct Heal { + enabled: bool, + bitrot: bool, +} + +struct ScannerItem { + path: String, + bucket: String, + prefix: String, + object_name: String, + replication: Option, + // todo: lifecycle + // typ: fs::Permissions, + heal: Heal, + debug: bool, +} + +impl ScannerItem { + pub fn transform_meda_dir(&mut self) { + let split = self + .prefix + .split(SLASH_SEPARATOR) + .map(|s| PathBuf::from(s)) + .collect::>(); + if split.len() > 1 { + self.prefix = path_join(&split[0..split.len() - 1]).to_string_lossy().to_string(); + } else { + self.prefix = "".to_string(); + } + self.object_name = split.last().map_or("".to_string(), |v| v.to_string_lossy().to_string()); + } + + pub fn object_path(&self) -> PathBuf { + path_join(&[PathBuf::from(self.prefix.clone()), PathBuf::from(self.object_name.clone())]) + } +} + +#[derive(Debug, Default)] +pub struct SizeSummary { + pub total_size: usize, + pub versions: usize, + pub delete_markers: usize, + pub replicated_size: usize, + pub replicated_count: usize, + pub pending_size: usize, + pub failed_size: usize, + pub replica_size: usize, + pub replica_count: usize, + pub pending_count: usize, + pub failed_count: usize, + pub repl_target_stats: HashMap, + // Todo: tires +} + +#[derive(Debug, Default)] +pub struct ReplTargetSizeSummary { + pub replicated_size: usize, + pub replicated_count: usize, + pub pending_size: usize, + pub failed_size: usize, + pub pending_count: usize, + pub failed_count: usize, +} + +#[derive(Debug, Clone)] +struct CachedFolder { + name: String, + parent: DataUsageHash, + object_heal_prob_div: u32, +} + +type GetSizeFn = Box Pin>>> + Send + 'static>; + +struct FolderScanner { + root: String, + get_size: GetSizeFn, + old_cache: DataUsageCache, + new_cache: DataUsageCache, + update_cache: DataUsageCache, + data_usage_scanner_debug: bool, + heal_object_select: u32, + scan_mode: HealScanMode, + should_heal: Arc bool + Send + Sync>, + disks: Vec>, + disks_quorum: usize, + updates: Sender, + last_update: SystemTime, + update_current_path: Arc, +} + +impl FolderScanner { + async fn scan_folder(&mut self, folder: &CachedFolder, into: &mut DataUsageEntry) -> Result<()> { + let this_hash = hash_path(&folder.name); + let was_compacted = into.compacted; + + loop { + let mut abandoned_children: DataUsageHashMap = if !into.compacted { + self.old_cache.find_children_copy(this_hash.clone()) + } else { + HashSet::new() + }; + + let (_, prefix) = path_to_bucket_object_with_base_path(&self.root, &folder.name); + // Todo: lifeCycle + let replication_cfg = if self.old_cache.info.replication.is_some() + && has_active_rules(self.old_cache.info.replication.as_ref().unwrap(), &prefix, true) + { + self.old_cache.info.replication.clone() + } else { + None + }; + + let mut existing_folders = Vec::new(); + let mut new_folders = Vec::new(); + let mut found_objects: bool = false; + + let path = Path::new(&self.root).join(&folder.name); + if path.is_dir() { + for entry in fs::read_dir(path)? { + let entry = entry?; + let sub_path = entry.path(); + let ent_name = Path::new(&folder.name).join(&sub_path); + let (bucket, prefix) = path_to_bucket_object_with_base_path(&self.root, ent_name.to_str().unwrap()); + if bucket.is_empty() { + continue; + } + if is_reserved_or_invalid_bucket(&bucket, false) { + continue; + } + + if !sub_path.is_dir() { + let h = hash_path(ent_name.to_str().unwrap()); + if h == this_hash { + continue; + } + let this = CachedFolder { + name: ent_name.to_string_lossy().to_string(), + parent: this_hash.clone(), + object_heal_prob_div: folder.object_heal_prob_div, + }; + abandoned_children.remove(&h.key()); + if self.old_cache.cache.contains_key(&h.key()) { + existing_folders.push(this); + self.update_cache + .copy_with_children(&self.old_cache, &h, &Some(this_hash.clone())); + } else { + new_folders.push(this); + } + continue; + } + + let mut item = ScannerItem { + path: Path::new(&self.root).join(&ent_name).to_string_lossy().to_string(), + bucket, + prefix: Path::new(&prefix) + .parent() + .unwrap_or(Path::new("")) + .to_string_lossy() + .to_string(), + object_name: ent_name + .file_name() + .map(|name| name.to_string_lossy().into_owned()) + .unwrap_or_default(), + debug: self.data_usage_scanner_debug, + replication: replication_cfg.clone(), + heal: Heal::default(), + }; + + item.heal.enabled = this_hash.mod_alt( + self.old_cache.info.next_cycle / folder.object_heal_prob_div, + self.heal_object_select / folder.object_heal_prob_div, + ) && (self.should_heal)(); + item.heal.bitrot = self.scan_mode == HEAL_DEEP_SCAN; + + let (sz, err) = match (self.get_size)(&item).await { + Ok(sz) => (sz, None), + Err(err) => { + if err.to_string() != ERR_IGNORE_FILE_CONTRIB { + continue; + } + (SizeSummary::default(), Some(err)) + } + }; + // successfully read means we have a valid object. + found_objects = true; + // Remove filename i.e is the meta file to construct object name + item.transform_meda_dir(); + // Object already accounted for, remove from heal map, + // simply because getSize() function already heals the + // object. + abandoned_children.remove( + &path_join(&[PathBuf::from(item.bucket.clone()), item.object_path()]) + .to_string_lossy() + .to_string(), + ); + + if err.is_none() || err.unwrap().to_string() != ERR_IGNORE_FILE_CONTRIB { + into.add_sizes(&sz); + into.objects += 1; + } + } + } + if found_objects && *GLOBAL_IsErasure.read().await { + // If we found an object in erasure mode, we skip subdirs (only datadirs)... + break; + } + + let should_compact = self.new_cache.info.name != folder.name + && existing_folders.len() + new_folders.len() >= DATA_SCANNER_COMPACT_AT_FOLDERS.try_into().unwrap() + || existing_folders.len() + new_folders.len() >= DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS.try_into().unwrap(); + + let total_folders = existing_folders.len() + new_folders.len(); + if total_folders + > SCANNER_EXCESS_FOLDERS + .load(std::sync::atomic::Ordering::SeqCst) + .try_into() + .unwrap() + { + let _prefix_name = format!("{}/", folder.name.trim_end_matches('/')); + // todo: notification + } + + if !into.compacted && should_compact { + into.compacted = true; + new_folders.extend(existing_folders.clone()); + existing_folders.clear(); + } + + // Transfer existing + if !into.compacted { + for folder in existing_folders.iter() { + let h = hash_path(&folder.name); + self.update_cache + .copy_with_children(&self.old_cache, &h, &Some(folder.parent.clone())); + } + } + + // Scan new... + for folder in new_folders.iter() { + let h = hash_path(&folder.name); + if !into.compacted { + let mut found_any = false; + let mut parent = this_hash.clone(); + while parent != hash_path(&self.update_cache.info.name) { + let e = self.update_cache.find(&parent.key()); + if e.is_none() || e.as_ref().unwrap().compacted { + found_any = true; + break; + } + match self.update_cache.search_parent(&parent) { + Some(next) => { + parent = next; + } + None => { + found_any = true; + break; + } + } + } + if !found_any { + self.update_cache + .replace_hashed(&h, &Some(this_hash.clone()), &DataUsageEntry::default()); + } + } + (self.update_current_path)(&folder.name); + scan(folder, into, self).await; + // Add new folders if this is new and we don't have existing. + if !into.compacted { + if let Some(parent) = self.update_cache.find(&this_hash.key()) { + if !parent.compacted { + self.update_cache.delete_recursive(&h); + self.update_cache + .copy_with_children(&self.new_cache, &h, &Some(this_hash.clone())); + } + } + } + } + + // Scan existing... + for folder in existing_folders.iter() { + let h = hash_path(&folder.name); + if !into.compacted && self.old_cache.is_compacted(&h) { + if !h.mod_(self.old_cache.info.next_cycle, DATA_USAGE_UPDATE_DIR_CYCLES) { + self.new_cache + .copy_with_children(&self.old_cache, &h, &Some(folder.parent.clone())); + into.add_child(&h); + continue; + } + } + (self.update_current_path)(&folder.name); + scan(folder, into, self).await; + } + + // Scan for healing + if abandoned_children.is_empty() || !(self.should_heal)() { + break; + } + + if self.disks.is_empty() || self.disks_quorum == 0 { + break; + } + + let (bg_seq, found) = GLOBAL_BackgroundHealState + .read() + .await + .get_heal_sequence_by_token(BG_HEALING_UUID) + .await; + if !found { + break; + } + let bg_seq = bg_seq.unwrap(); + + let mut resolver = MetadataResolutionParams { + dir_quorum: self.disks_quorum, + obj_quorum: self.disks_quorum, + bucket: "".to_string(), + strict: false, + ..Default::default() + }; + + for k in abandoned_children.iter() { + if !(self.should_heal)() { + break; + } + + let (bucket, prefix) = path_to_bucket_object(k); + (self.update_current_path)(k); + + if bucket != resolver.bucket { + let _ = bg_seq + .clone() + .write() + .await + .queue_heal_task( + HealSource { + bucket: bucket.clone(), + ..Default::default() + }, + HEAL_ITEM_BUCKET.to_owned(), + ) + .await?; + } + + resolver.bucket = bucket.clone(); + let found_objs = Arc::new(RwLock::new(false)); + let found_objs_clone = found_objs.clone(); + let (tx, rx) = broadcast::channel(1); + let tx_partial = tx.clone(); + let tx_finished = tx.clone(); + let update_current_path_agreed = self.update_current_path.clone(); + let update_current_path_partial = self.update_current_path.clone(); + let should_heal_clone = self.should_heal.clone(); + let resolver_clone = resolver.clone(); + let bg_seq_clone = bg_seq.clone(); + let lopts = ListPathRawOptions { + disks: self.disks.clone(), + bucket: bucket.clone(), + path: prefix.clone(), + recursice: true, + report_not_found: true, + min_disks: self.disks_quorum, + agreed: Some(Box::new(move |entry: MetaCacheEntry| { + Box::pin({ + let update_current_path_agreed = update_current_path_agreed.clone(); + async move { + update_current_path_agreed(&entry.name); + } + }) + })), + partial: Some(Box::new(move |entries: MetaCacheEntries, _: &[Option]| { + Box::pin({ + let update_current_path_partial = update_current_path_partial.clone(); + let should_heal_partial = should_heal_clone.clone(); + let tx_partial = tx_partial.clone(); + let resolver_partial = resolver_clone.clone(); + let bucket_partial = bucket.clone(); + let found_objs_clone = found_objs_clone.clone(); + let bg_seq_partial = bg_seq_clone.clone(); + async move { + if !should_heal_partial() { + let _ = tx_partial.send(true); + return; + } + let entry = match entries.resolve(resolver_partial) { + Ok(Some(entry)) => entry, + _ => match entries.first_found() { + (Some(entry), _) => entry, + _ => return, + }, + }; + + update_current_path_partial(&entry.name); + let mut custom = HashMap::new(); + if entry.is_dir() { + return; + } + + // We got an entry which we should be able to heal. + let fiv = match entry.file_info_versions(&bucket_partial) { + Ok(fiv) => fiv, + Err(_) => { + if let Err(err) = bg_seq_partial + .write() + .await + .queue_heal_task( + HealSource { + bucket: bucket_partial.clone(), + object: entry.name.clone(), + version_id: "".to_string(), + ..Default::default() + }, + HEAL_ITEM_OBJECT.to_string(), + ) + .await + { + match err.downcast_ref() { + Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} + _ => { + info!("{}", err.to_string()); + } + } + } else { + let mut w = found_objs_clone.write().await; + *w = *w || true; + } + return; + } + }; + + custom.insert("versions", fiv.versions.len().to_string()); + let (mut success_versions, mut fail_versions) = (0, 0); + for ver in fiv.versions.iter() { + match bg_seq_partial + .write() + .await + .queue_heal_task( + HealSource { + bucket: bucket_partial.clone(), + object: entry.name.clone(), + version_id: "".to_string(), + ..Default::default() + }, + HEAL_ITEM_OBJECT.to_string(), + ) + .await + { + Ok(_) => { + success_versions += 1; + let mut w = found_objs_clone.write().await; + *w = *w || true; + } + Err(_) => fail_versions += 1, + } + } + custom.insert("success_versions", success_versions.to_string()); + custom.insert("failed_versions", fail_versions.to_string()); + } + }) + })), + finished: Some(Box::new(move |err: &[Option]| { + Box::pin({ + let tx_finished = tx_finished.clone(); + async move { + let _ = tx_finished.send(true); + } + }) + })), + ..Default::default() + }; + let _ = list_path_raw(rx, lopts).await; + + if *found_objs.read().await { + let this = CachedFolder { + name: k.clone(), + parent: this_hash.clone(), + object_heal_prob_div: 1, + }; + scan(&this, into, self).await; + } + } + break; + } + if !was_compacted { + self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), &into); + } + + if !into.compacted && self.new_cache.info.name != folder.name { + let mut flat = self + .new_cache + .size_recursive(&this_hash.key()) + .unwrap_or(DataUsageEntry::default()); + flat.compacted = true; + let mut compact = false; + if flat.objects < DATA_SCANNER_COMPACT_LEAST_OBJECT.try_into().unwrap() { + compact = true; + } else { + // Compact if we only have objects as children... + compact = true; + for k in into.children.iter() { + if let Some(v) = self.new_cache.cache.get(k) { + if !v.children.is_empty() || v.objects > 1 { + compact = false; + break; + } + } + } + } + if compact { + self.new_cache.delete_recursive(&this_hash); + self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), &flat); + let mut total: HashMap = HashMap::new(); + total.insert("objects".to_string(), flat.objects.to_string()); + total.insert("size".to_string(), flat.size.to_string()); + if flat.versions > 0 { + total.insert("versions".to_string(), flat.versions.to_string()); + } + } + } + // Compact if too many children... + if !into.compacted { + self.new_cache.reduce_children_of( + &this_hash, + DATA_SCANNER_COMPACT_AT_CHILDREN.try_into().unwrap(), + self.new_cache.info.name != folder.name, + ); + } + if self.update_cache.cache.contains_key(&this_hash.key()) && !was_compacted { + // Replace if existed before. + if let Some(flat) = self.new_cache.size_recursive(&this_hash.key()) { + self.update_cache.delete_recursive(&this_hash); + self.update_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), &flat); + } + } + Ok(()) + } + + async fn send_update(&mut self) { + if SystemTime::now().duration_since(self.last_update).unwrap() < Duration::from_secs(60) { + return; + } + if let Some(flat) = self.update_cache.size_recursive(&self.new_cache.info.name) { + let _ = self.updates.send(flat).await; + self.last_update = SystemTime::now(); + } + } +} + +async fn scan(folder: &CachedFolder, into: &mut DataUsageEntry, folder_scanner: &mut FolderScanner) { + let mut dst = if !into.compacted { + DataUsageEntry::default() + } else { + into.clone() + }; + + if Box::pin(folder_scanner.scan_folder(folder, &mut dst)).await.is_err() { + return; + } + if !into.compacted { + let h = DataUsageHash(folder.name.clone()); + into.add_child(&h); + folder_scanner.update_cache.delete_recursive(&h); + folder_scanner + .update_cache + .copy_with_children(&folder_scanner.new_cache, &h, &Some(folder.parent.clone())); + folder_scanner.send_update().await; + } +} + +pub fn has_active_rules(config: &ReplicationConfiguration, prefix: &str, recursive: bool) -> bool { + if config.rules.is_empty() { + return false; + } + + for rule in config.rules.iter() { + if rule + .status + .eq(&ReplicationRuleStatus::from_static(ReplicationRuleStatus::DISABLED)) + { + continue; + } + if !prefix.is_empty() { + if let Some(filter) = &rule.filter { + if let Some(r_prefix) = &filter.prefix { + if !r_prefix.is_empty() { + // incoming prefix must be in rule prefix + if !recursive && !prefix.starts_with(r_prefix) { + continue; + } + // If recursive, we can skip this rule if it doesn't match the tested prefix or level below prefix + // does not match + if recursive && !r_prefix.starts_with(prefix) && !prefix.starts_with(r_prefix) { + continue; + } + } + } + } + } + return true; + } + false +} diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs index 3bbf1f504..037f503b8 100644 --- a/ecstore/src/heal/data_usage_cache.rs +++ b/ecstore/src/heal/data_usage_cache.rs @@ -1,10 +1,16 @@ +use bytesize::ByteSize; use http::HeaderMap; +use path_clean::PathClean; use rand::Rng; use rmp_serde::Serializer; +use s3s::dto::ReplicationConfiguration; use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; +use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::Path; +use std::sync::Arc; use std::time::{Duration, SystemTime}; +use std::u64; use s3s::{S3Error, S3ErrorCode}; use tokio::sync::mpsc::Sender; use tokio::time::sleep; @@ -14,21 +20,162 @@ use crate::disk::{BUCKET_META_PREFIX, RUSTFS_META_BUCKET}; use crate::error::{Error, Result}; use crate::new_object_layer_fn; use crate::set_disk::SetDisks; -use crate::store_api::{HTTPRangeSpec, ObjectIO, ObjectOptions, StorageAPI}; +use crate::store_api::{HTTPRangeSpec, ObjectIO, ObjectOptions}; +use super::data_scanner::SizeSummary; use super::data_usage::DATA_USAGE_ROOT; // DATA_USAGE_BUCKET_LEN must be length of ObjectsHistogramIntervals pub const DATA_USAGE_BUCKET_LEN: usize = 11; pub const DATA_USAGE_VERSION_LEN: usize = 7; -type DataUsageHashMap = HashSet; -// sizeHistogram is a size histogram. -type SizeHistogram = Vec; -// versionsHistogram is a histogram of number of versions in an object. -type VersionsHistogram = Vec; +pub type DataUsageHashMap = HashSet; -#[derive(Debug, Clone, Serialize, Deserialize)] +struct ObjectHistogramInterval { + name: &'static str, + start: u64, + end: u64, +} + +const OBJECTS_HISTOGRAM_INTERVALS: [ObjectHistogramInterval; DATA_USAGE_BUCKET_LEN] = [ + ObjectHistogramInterval { + name: "LESS_THAN_1024_B", + start: 0, + end: ByteSize::kib(1).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_1024_B_AND_64_KB", + start: ByteSize::kib(1).as_u64(), + end: ByteSize::kib(64).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_64_KB_AND_256_KB", + start: ByteSize::kib(64).as_u64(), + end: ByteSize::kib(256).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_256_KB_AND_512_KB", + start: ByteSize::kib(256).as_u64(), + end: ByteSize::kib(512).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_512_KB_AND_1_MB", + start: ByteSize::kib(512).as_u64(), + end: ByteSize::mib(1).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_1024B_AND_1_MB", + start: ByteSize::kib(1).as_u64(), + end: ByteSize::mib(1).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_1_MB_AND_10_MB", + start: ByteSize::mib(1).as_u64(), + end: ByteSize::mib(10).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_10_MB_AND_64_MB", + start: ByteSize::mib(10).as_u64(), + end: ByteSize::mib(64).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_64_MB_AND_128_MB", + start: ByteSize::mib(64).as_u64(), + end: ByteSize::mib(128).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_128_MB_AND_512_MB", + start: ByteSize::mib(128).as_u64(), + end: ByteSize::mib(512).as_u64() - 1, + }, + ObjectHistogramInterval { + name: "GREATER_THAN_512_MB", + start: ByteSize::mib(512).as_u64(), + end: u64::MAX, + }, +]; + +const OBJECTS_VERSION_COUNT_INTERVALS: [ObjectHistogramInterval; DATA_USAGE_VERSION_LEN] = [ + ObjectHistogramInterval { + name: "UNVERSIONED", + start: 0, + end: 0, + }, + ObjectHistogramInterval { + name: "SINGLE_VERSION", + start: 1, + end: 1, + }, + ObjectHistogramInterval { + name: "BETWEEN_2_AND_10", + start: 2, + end: 9, + }, + ObjectHistogramInterval { + name: "BETWEEN_10_AND_100", + start: 10, + end: 99, + }, + ObjectHistogramInterval { + name: "BETWEEN_100_AND_1000", + start: 100, + end: 999, + }, + ObjectHistogramInterval { + name: "BETWEEN_1000_AND_10000", + start: 1000, + end: 9999, + }, + ObjectHistogramInterval { + name: "GREATER_THAN_10000", + start: 10000, + end: u64::MAX, + }, +]; + +// sizeHistogram is a size histogram. +#[derive(Clone, Serialize, Deserialize)] +pub struct SizeHistogram(Vec); + +impl Default for SizeHistogram { + fn default() -> Self { + Self(vec![0; DATA_USAGE_BUCKET_LEN]) + } +} + +impl SizeHistogram { + fn add(&mut self, size: u64) { + for (idx, interval) in OBJECTS_HISTOGRAM_INTERVALS.iter().enumerate() { + if size >= interval.start && size <= interval.end { + self.0[idx] += 1; + break; + } + } + } +} + +// versionsHistogram is a histogram of number of versions in an object. +#[derive(Clone, Serialize, Deserialize)] +pub struct VersionsHistogram(Vec); + +impl Default for VersionsHistogram { + fn default() -> Self { + Self(vec![0; DATA_USAGE_VERSION_LEN]) + } +} + +impl VersionsHistogram { + fn add(&mut self, size: u64) { + for (idx, interval) in OBJECTS_VERSION_COUNT_INTERVALS.iter().enumerate() { + if size >= interval.start && size <= interval.end { + self.0[idx] += 1; + break; + } + } + } +} + +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct ReplicationStats { pub pending_size: u64, pub replicated_size: u64, @@ -48,7 +195,7 @@ impl ReplicationStats { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct ReplicationAllStats { pub targets: HashMap, pub replica_size: u64, @@ -70,35 +217,117 @@ impl ReplicationAllStats { } } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Default, Serialize, Deserialize)] pub struct DataUsageEntry { pub children: DataUsageHashMap, // These fields do no include any children. - pub size: i64, - pub objects: u64, - pub versions: u64, - pub delete_markers: u64, + pub size: usize, + pub objects: usize, + pub versions: usize, + pub delete_markers: usize, pub obj_sizes: SizeHistogram, pub obj_versions: VersionsHistogram, - pub replication_stats: ReplicationAllStats, + pub replication_stats: Option, // Todo: tier // pub all_tier_stats: , pub compacted: bool, } +impl DataUsageEntry { + pub fn add_child(&mut self, hash: &DataUsageHash) { + if self.children.contains(&hash.key()) { + return; + } + + self.children.insert(hash.key()); + } + + pub fn add_sizes(&mut self, summary: &SizeSummary) { + self.size += summary.total_size; + self.versions += summary.versions; + self.delete_markers += summary.delete_markers; + self.obj_sizes.add(summary.total_size as u64); + self.obj_versions.add(summary.versions as u64); + + let replication_stats = if self.replication_stats.is_none() { + self.replication_stats = Some(ReplicationAllStats::default()); + self.replication_stats.as_mut().unwrap() + } else { + self.replication_stats.as_mut().unwrap() + }; + replication_stats.replica_size += summary.replica_size as u64; + replication_stats.replica_count += summary.replica_count as u64; + + for (arn, st) in &summary.repl_target_stats { + let tgt_stat = replication_stats.targets.entry(arn.to_string()).or_insert(ReplicationStats::default()); + tgt_stat.pending_size += st.pending_size as u64; + tgt_stat.failed_size += st.failed_size as u64; + tgt_stat.replicated_size += st.replicated_size as u64; + tgt_stat.replicated_count += st.replicated_count as u64; + tgt_stat.failed_count += st.failed_count as u64; + tgt_stat.pending_count += st.pending_count as u64; + } + // Todo:: tiers + } + + pub fn merge(&mut self, other: &DataUsageEntry) { + self.objects += other.objects; + self.versions += other.versions; + self.delete_markers += other.delete_markers; + self.size += other.size; + if let Some(o_rep) = &other.replication_stats { + if self.replication_stats.is_none() { + self.replication_stats = Some(ReplicationAllStats::default()); + } + let s_rep = self.replication_stats.as_mut().unwrap(); + s_rep.targets.clear(); + s_rep.replica_size += o_rep.replica_size; + s_rep.replica_count += o_rep.replica_count; + for (arn, stat) in o_rep.targets.iter() { + let st = s_rep.targets.entry(arn.clone()).or_insert(ReplicationStats::default()); + *st = ReplicationStats { + pending_size: stat.pending_size + st.pending_size, + failed_size: stat.failed_size + st.failed_size, + replicated_size: stat.replicated_size + st.replicated_size, + pending_count: stat.pending_count + st.pending_count, + failed_count: stat.failed_count + st.failed_count, + replicated_count: stat.replicated_count + st.replicated_count, + ..Default::default() + }; + } + } + + for (i, v) in other.obj_sizes.0.iter().enumerate() { + self.obj_sizes.0[i] += v; + } + + for (i, v) in other.obj_versions.0.iter().enumerate() { + self.obj_versions.0[i] += v; + } + + // todo: tiers + } +} + +#[derive(Clone)] +pub struct DataUsageEntryInfo { + pub name: String, + pub parent: String, + pub entry: DataUsageEntry, +} + #[derive(Clone, Serialize, Deserialize)] pub struct DataUsageCacheInfo { pub name: String, - pub next_cycle: usize, + pub next_cycle: u32, pub last_update: SystemTime, pub skip_healing: bool, // todo: life_cycle // pub life_cycle: #[serde(skip)] pub updates: Option>, - // Todo: replication - // #[serde(skip_serializing)] - // replication: + #[serde(skip)] + pub replication: Option, } impl Default for DataUsageCacheInfo { @@ -109,6 +338,7 @@ impl Default for DataUsageCacheInfo { last_update: SystemTime::now(), skip_healing: Default::default(), updates: Default::default(), + replication: Default::default(), } } } @@ -202,6 +432,195 @@ impl DataUsageCache { pub fn replace(&mut self, path: &str, parent: &str, e: DataUsageEntry) { let hash = hash_path(path); + self.cache.insert(hash.key(), e); + if !parent.is_empty() { + let phash = hash_path(parent); + let p = { + let p = self.cache.entry(phash.key()).or_insert(DataUsageEntry::default()); + p.add_child(&hash); + p.clone() + }; + self.cache.insert(phash.key(), p); + } + } + + pub fn replace_hashed(&mut self, hash: &DataUsageHash, parent: &Option, e: &DataUsageEntry) { + self.cache.insert(hash.key(), e.clone()); + if let Some(parent) = parent { + self.cache.entry(parent.key()).or_insert(DataUsageEntry::default()).add_child(hash); + } + } + + pub fn find(&self, path: &str) -> Option { + self.cache.get(&hash_path(path).key()).cloned() + } + + pub fn find_children_copy(&mut self, h: DataUsageHash) -> DataUsageHashMap { + self.cache.entry(h.string()).or_insert(DataUsageEntry::default()).children.clone() + } + + pub fn flatten(&self, root: &DataUsageEntry) -> DataUsageEntry { + let mut root = root.clone(); + for id in root.children.clone().iter() { + if let Some(e) = self.cache.get(id) { + let mut e = e.clone(); + if !e.children.is_empty() { + e = self.flatten(&e); + } + root.merge(&e); + } + } + root.children.clear(); + root + } + + pub fn copy_with_children(&mut self, src: &DataUsageCache, hash: &DataUsageHash, parent: &Option) { + match src.cache.get(&hash.string()) { + Some(e) => { + self.cache.insert(hash.key(), e.clone()); + for ch in e.children.iter() { + if *ch == hash.key() { + return; + } + self.copy_with_children(src, &DataUsageHash(ch.to_string()), &Some(hash.clone())); + } + if let Some(parent) = parent { + let p = self.cache.entry(parent.key()).or_insert(DataUsageEntry::default()); + p.add_child(hash); + } + }, + None => return, + } + } + + pub fn delete_recursive(&mut self, hash: &DataUsageHash) { + let mut need_remove = Vec::new(); + if let Some(v) = self.cache.get(&hash.string()) { + for child in v.children.iter() { + need_remove.push(child.clone()); + } + } + self.cache.remove(&hash.string()); + need_remove.iter().for_each(|child| { + self.delete_recursive(&DataUsageHash(child.to_string())); + }); + } + + pub fn size_recursive(&self, path: &str) -> Option { + match self.find(path) { + Some(root) => { + if root.children.is_empty() { + return None; + } + let mut flat = self.flatten(&root); + if flat.replication_stats.is_some() && flat.replication_stats.as_ref().unwrap().empty() { + flat.replication_stats = None; + } + return Some(flat); + }, + None => None + } + } + + pub fn search_parent(&self, hash: &DataUsageHash) -> Option { + let want = hash.key(); + if let Some(last_index) = want.rfind('/') { + if let Some(v) = self.find(&want[0..last_index]) { + if v.children.contains(&want) { + let found = hash_path(&want[0..last_index]); + return Some(found); + } + } + } + + for (k, v) in self.cache.iter() { + if v.children.contains(&want) { + let found = DataUsageHash(k.clone()); + return Some(found); + } + } + None + } + + pub fn is_compacted(&self, hash: &DataUsageHash) -> bool { + match self.cache.get(&hash.key()) { + Some(due) => { + due.compacted + }, + None => false + } + } + + pub fn reduce_children_of(&mut self, path: &DataUsageHash, limit: usize, compact_self: bool) { + let e = match self.cache.get(&path.key()) { + Some(e) => e, + None => return, + }; + + if e.compacted { + return; + } + + if e.children.len() > limit && compact_self { + let mut flat = self.size_recursive(&path.key()).unwrap_or(DataUsageEntry::default()); + flat.compacted = true; + self.delete_recursive(path); + self.replace_hashed(path, &None, &flat); + return; + } + let total = self.total_children_rec(&path.key()); + if total < limit { + return; + } + + let mut leaves = Vec::new(); + let mut remove = total - limit; + add(self, path, &mut leaves); + leaves.sort_by(|a, b| { + a.objects.cmp(&b.objects) + }); + + while remove > 0 && leaves.len() > 0 { + let e = leaves.first().unwrap(); + let candidate = e.path.clone(); + if candidate == *path && !compact_self { + break; + } + let removing = self.total_children_rec(&candidate.key()); + let mut flat = match self.size_recursive(&candidate.key()) { + Some(flat) => flat, + None => { + leaves.remove(0); + continue; + } + }; + + flat.compacted = true; + self.delete_recursive(&candidate); + self.replace_hashed(&candidate, &None, &flat); + + remove -= removing; + leaves.remove(0); + } + + } + + pub fn total_children_rec(&self, path: &str) -> usize { + let root = self.find(path); + + if root.is_none() { + return 0; + } + let root = root.unwrap(); + if root.children.is_empty() { + return 0; + } + + let mut n = root.children.len(); + for ch in root.children.iter() { + n += self.total_children_rec(&ch); + } + n } pub fn marshal_msg(&self) -> Result> { @@ -218,10 +637,63 @@ impl DataUsageCache { } } -struct DataUsageHash(String); +#[derive(Default, Clone)] +struct Inner { + objects: usize, + path: DataUsageHash, +} + +fn add(data_usage_cache: &DataUsageCache, path: &DataUsageHash, leaves: &mut Vec) { + let e = match data_usage_cache.cache.get(&path.key()) { + Some(e) => e, + None => return, + }; + if !e.children.is_empty() { + return; + } + + let sz = data_usage_cache.size_recursive(&path.key()).unwrap_or(DataUsageEntry::default()); + leaves.push(Inner{objects: sz.objects, path: path.clone()}); + for ch in e.children.iter() { + add(data_usage_cache, &DataUsageHash(ch.clone()), leaves); + } +} + +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct DataUsageHash(pub String); impl DataUsageHash { - + pub fn string(&self) -> String { + self.0.clone() + } + + pub fn key(&self) -> String { + self.0.clone() + } + + pub fn mod_(&self, cycle: u32, cycles: u32) -> bool { + if cycles <= 1 { + return cycles == 1; + } + + let hash = self.calculate_hash(); + hash as u32 % cycles == cycle % cycles + } + + pub fn mod_alt(&self, cycle: u32, cycles: u32) -> bool { + if cycles <= 1 { + return cycles == 1; + } + + let hash = self.calculate_hash(); + (hash >> 32) as u32 % cycles == cycle % cycles + } + + fn calculate_hash(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.0.hash(&mut hasher); + hasher.finish() + } } pub fn hash_path(data: &str) -> DataUsageHash { @@ -229,6 +701,5 @@ pub fn hash_path(data: &str) -> DataUsageHash { if data != DATA_USAGE_ROOT { data = data.trim_matches('/'); } - Path::new(&data); - todo!() + DataUsageHash(Path::new(&data).clean().to_string_lossy().to_string()) } diff --git a/ecstore/src/heal/error.rs b/ecstore/src/heal/error.rs new file mode 100644 index 000000000..9b5e9d0cd --- /dev/null +++ b/ecstore/src/heal/error.rs @@ -0,0 +1 @@ +pub const ERR_IGNORE_FILE_CONTRIB: &str = "ignore this file's contribution toward data-usage"; \ No newline at end of file diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 0c9415d24..de79a66f2 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -60,12 +60,13 @@ pub struct HealSequenceStatus { pub items: Vec, } +#[derive(Debug, Default)] pub struct HealSource { pub bucket: String, pub object: String, pub version_id: String, pub no_wait: bool, - opts: Option, + pub opts: Option, } #[derive(Clone, Debug)] @@ -245,7 +246,7 @@ impl HealSequence { Ok(()) } - async fn queue_heal_task(&mut self, source: HealSource, heal_type: HealItemType) -> Result<()> { + pub async fn queue_heal_task(&mut self, source: HealSource, heal_type: HealItemType) -> Result<()> { let mut task = HealTask::new(&source.bucket, &source.object, &source.version_id, &self.setting); if let Some(opts) = source.opts { task.opts = opts; @@ -348,7 +349,7 @@ pub async fn heal_sequence_start(h: Arc) { pub struct AllHealState { mu: RwLock, - heal_seq_map: HashMap, + heal_seq_map: HashMap>>, heal_local_disks: HashMap, heal_status: HashMap, } @@ -449,7 +450,8 @@ impl AllHealState { let mut keys_to_reomve = Vec::new(); for (k, v) in self.heal_seq_map.iter() { - if v.has_ended().await && (UNIX_EPOCH + Duration::from_secs(*(v.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now { + let r = v.read().await; + if r.has_ended().await && (UNIX_EPOCH + Duration::from_secs(*(r.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now { keys_to_reomve.push(k.clone()) } } @@ -458,11 +460,12 @@ impl AllHealState { } } - async fn get_heal_sequence_by_token(&self, token: &str) -> (Option, bool) { + pub async fn get_heal_sequence_by_token(&self, token: &str) -> (Option>>, bool) { let _ = self.mu.read().await; for v in self.heal_seq_map.values() { - if v.client_token == token { + let r = v.read().await; + if r.client_token == token { return (Some(v.clone()), true); } } @@ -470,7 +473,7 @@ impl AllHealState { (None, false) } - async fn get_heal_sequence(&self, path: &str) -> Option { + async fn get_heal_sequence(&self, path: &str) -> Option>> { let _ = self.mu.read().await; self.heal_seq_map.get(path).cloned() @@ -479,6 +482,7 @@ impl AllHealState { async fn stop_heal_sequence(&mut self, path: &str) -> Result> { let mut hsp = HealStopSuccess::default(); if let Some(he) = self.get_heal_sequence(path).await { + let he = he.read().await; let client_token = he.client_token.clone(); if *GLOBAL_IsDistErasure.read().await { // TODO: proxy @@ -525,7 +529,7 @@ impl AllHealState { self.stop_heal_sequence(path_s).await?; } else { if let Some(hs) = self.get_heal_sequence(path_s).await { - if !hs.has_ended().await { + if !hs.read().await.has_ended().await { return Err(Error::from_string(format!("Heal is already running on the given path (use force-start option to stop and start afresh). The heal was started by IP {} at {}, token is {}", heal_sequence.client_address, heal_sequence.start_time, heal_sequence.client_token))); } } @@ -534,7 +538,7 @@ impl AllHealState { let _ = self.mu.write().await; for (k, v) in self.heal_seq_map.iter() { - if !v.has_ended().await && (has_profix(k, path_s) || has_profix(path_s, k)) { + if !v.read().await.has_ended().await && (has_profix(&k, path_s) || has_profix(path_s, &k)) { return Err(Error::from_string(format!( "The provided heal sequence path overlaps with an existing heal path: {}", k @@ -542,7 +546,7 @@ impl AllHealState { } } - self.heal_seq_map.insert(path_s.to_string(), heal_sequence.clone()); + self.heal_seq_map.insert(path_s.to_string(), Arc::new(RwLock::new(heal_sequence.clone()))); let client_token = heal_sequence.client_token.clone(); if *GLOBAL_IsDistErasure.read().await { diff --git a/ecstore/src/heal/mod.rs b/ecstore/src/heal/mod.rs index f477be10e..9a3c28273 100644 --- a/ecstore/src/heal/mod.rs +++ b/ecstore/src/heal/mod.rs @@ -2,6 +2,7 @@ pub mod background_heal_ops; pub mod data_scanner; pub mod data_scanner_metric; pub mod data_usage; +pub mod error; pub mod heal_commands; pub mod heal_ops; pub mod data_usage_cache; diff --git a/ecstore/src/peer.rs b/ecstore/src/peer.rs index a56fdb426..e76cbf765 100644 --- a/ecstore/src/peer.rs +++ b/ecstore/src/peer.rs @@ -528,7 +528,7 @@ fn is_reserved_bucket(bucket_name: &str) -> bool { } // 检查桶名是否为保留名或无效名 -fn is_reserved_or_invalid_bucket(bucket_entry: &str, strict: bool) -> bool { +pub fn is_reserved_or_invalid_bucket(bucket_entry: &str, strict: bool) -> bool { if bucket_entry.is_empty() { return true; } diff --git a/ecstore/src/utils/path.rs b/ecstore/src/utils/path.rs index b505bd72f..654333ec2 100644 --- a/ecstore/src/utils/path.rs +++ b/ecstore/src/utils/path.rs @@ -69,6 +69,19 @@ pub fn path_join(elem: &[PathBuf]) -> PathBuf { joined_path } +pub fn path_to_bucket_object_with_base_path(bash_path: &str, path: &str) -> (String, String) { + let path = path.trim_start_matches(bash_path).trim_start_matches(SLASH_SEPARATOR); + if let Some(m) = path.find(SLASH_SEPARATOR) { + return (path[..m].to_string(), path[m + SLASH_SEPARATOR.len()..].to_string()); + } + + (path.to_string(), "".to_string()) +} + +pub fn path_to_bucket_object(s: &str) -> (String, String) { + path_to_bucket_object_with_base_path("", s) +} + pub fn base_dir_from_prefix(prefix: &str) -> String { let mut base_dir = dir(prefix).to_owned(); if base_dir == "." || base_dir == "./" || base_dir == "/" { From caad7a38a4e8cceae2dbc3a7994328c3e76caee0 Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Thu, 14 Nov 2024 10:47:51 +0800 Subject: [PATCH 03/11] rebase main Signed-off-by: junxiang Mu <1948535941@qq.com> --- Cargo.lock | 6 -- Cargo.toml | 2 +- common/common/src/lib.rs | 3 +- ecstore/Cargo.toml | 2 - ecstore/src/disk/mod.rs | 14 ++++- ecstore/src/disk/remote.rs | 8 ++- ecstore/src/erasure.rs | 10 ++- ecstore/src/global.rs | 5 +- ecstore/src/heal/background_heal_ops.rs | 12 +++- ecstore/src/heal/data_scanner.rs | 3 +- ecstore/src/heal/data_scanner_metric.rs | 5 +- ecstore/src/heal/data_usage_cache.rs | 82 ++++++++++++++----------- ecstore/src/heal/error.rs | 2 +- ecstore/src/heal/heal_commands.rs | 8 ++- ecstore/src/heal/heal_ops.rs | 10 +-- ecstore/src/heal/mod.rs | 2 +- ecstore/src/sets.rs | 26 ++++---- ecstore/src/store.rs | 31 ++++++---- ecstore/src/store_api.rs | 16 ++--- ecstore/src/store_init.rs | 17 +++-- ecstore/src/utils/bool_flag.rs | 8 +-- ecstore/src/utils/mod.rs | 2 +- 22 files changed, 168 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 880e5d497..5a24b8a1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,12 +336,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" -[[package]] -name = "bytesize" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" - [[package]] name = "bytestring" version = "1.3.1" diff --git a/Cargo.toml b/Cargo.toml index 77f3121ba..b5ac976ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ version = "0.0.1" async-trait = "0.1.83" backon = "1.2.0" bytes = "1.8.0" +bytesize = "1.3.0" clap = { version = "4.5.20", features = ["derive"] } ecstore = { path = "./ecstore" } flatbuffers = "24.3.25" @@ -84,4 +85,3 @@ uuid = { version = "1.11.0", features = [ log = "0.4.22" axum = "0.7.7" md-5 = "0.10.6" -bytesize = "1.3.0" diff --git a/common/common/src/lib.rs b/common/common/src/lib.rs index f3b5db329..dc9ee425c 100644 --- a/common/common/src/lib.rs +++ b/common/common/src/lib.rs @@ -2,7 +2,8 @@ pub mod error; pub mod globals; /// Defers evaluation of a block of code until the end of the scope. -#[macro_export] macro_rules! defer { +#[macro_export] +macro_rules! defer { ($($body:tt)*) => { let _guard = { pub struct Guard(Option); diff --git a/ecstore/Cargo.toml b/ecstore/Cargo.toml index 8b8028904..79370b32f 100644 --- a/ecstore/Cargo.toml +++ b/ecstore/Cargo.toml @@ -13,7 +13,6 @@ async-trait.workspace = true backon.workspace = true blake2 = "0.10.6" bytes.workspace = true -bytesize = "1.3.0" common.workspace = true reader.workspace = true glob = "0.3.1" @@ -42,7 +41,6 @@ protos.workspace = true rmp-serde = "1.3.0" tokio-util = { version = "0.7.12", features = ["io", "compat"] } crc32fast = "1.4.2" -rand = "0.8.5" siphasher = "1.0.1" base64-simd = "0.8.0" sha2 = { version = "0.11.0-pre.4" } diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index 920ca072d..a9056d52b 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -14,7 +14,7 @@ pub const FORMAT_CONFIG_FILE: &str = "format.json"; const STORAGE_FORMAT_FILE: &str = "xl.meta"; use crate::{ - erasure::{ReadAt, Writer}, + erasure::Writer, error::{Error, Result}, file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion}, heal::{ @@ -342,6 +342,18 @@ impl DiskAPI for Disk { Disk::Remote(remote_disk) => remote_disk.disk_info(opts).await, } } + + async fn ns_scanner( + &self, + cache: &DataUsageCache, + updates: Sender, + scan_mode: HealScanMode, + ) -> Result { + match self { + Disk::Local(local_disk) => local_disk.ns_scanner(cache, updates, scan_mode).await, + Disk::Remote(remote_disk) => remote_disk.ns_scanner(cache, updates, scan_mode).await, + } + } } pub async fn new_disk(ep: &endpoint::Endpoint, opt: &DiskOption) -> Result { diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index aff542350..4eba96bf2 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -21,7 +21,13 @@ use super::{ RemoteFileWriter, RenameDataResp, UpdateMetadataOpts, VolumeInfo, WalkDirOptions, }; use crate::{ - disk::error::DiskError, error::{Error, Result}, heal::{data_usage_cache::{DataUsageCache, DataUsageEntry}, heal_commands::HealScanMode}, store_api::{FileInfo, RawFileInfo} + disk::error::DiskError, + error::{Error, Result}, + heal::{ + data_usage_cache::{DataUsageCache, DataUsageEntry}, + heal_commands::HealScanMode, + }, + store_api::{FileInfo, RawFileInfo}, }; use protos::proto_gen::node_service::RenamePartRequst; diff --git a/ecstore/src/erasure.rs b/ecstore/src/erasure.rs index 769995d60..d0322532e 100644 --- a/ecstore/src/erasure.rs +++ b/ecstore/src/erasure.rs @@ -419,7 +419,13 @@ impl Erasure { till_offset } - pub async fn heal(&self, writers: &mut [Option], readers: Vec>, total_length: usize, prefer: &[bool]) -> Result<()> { + pub async fn heal( + &self, + writers: &mut [Option], + readers: Vec>, + total_length: usize, + prefer: &[bool], + ) -> Result<()> { if writers.len() != self.parity_shards + self.data_shards { return Err(Error::from_string("invalid argument")); } @@ -451,7 +457,7 @@ impl Erasure { continue; } match w.as_mut().unwrap().write(shards[i].as_ref()).await { - Ok(_) => {}, + Ok(_) => {} Err(e) => errs.push(e), } } diff --git a/ecstore/src/global.rs b/ecstore/src/global.rs index a602fc728..39c35b15a 100644 --- a/ecstore/src/global.rs +++ b/ecstore/src/global.rs @@ -4,7 +4,10 @@ use tokio::sync::RwLock; use uuid::Uuid; use crate::{ - disk::DiskStore, endpoints::{EndpointServerPools, PoolEndpoints, SetupType}, heal::{background_heal_ops::HealRoutine, heal_ops::AllHealState}, store::ECStore + disk::DiskStore, + endpoints::{EndpointServerPools, PoolEndpoints, SetupType}, + heal::{background_heal_ops::HealRoutine, heal_ops::AllHealState}, + store::ECStore, }; pub const DISK_ASSUME_UNKNOWN_SIZE: u64 = 1 << 30; diff --git a/ecstore/src/heal/background_heal_ops.rs b/ecstore/src/heal/background_heal_ops.rs index f0de47329..4c305b24b 100644 --- a/ecstore/src/heal/background_heal_ops.rs +++ b/ecstore/src/heal/background_heal_ops.rs @@ -4,12 +4,18 @@ use tokio::{ select, sync::{ broadcast::Receiver as B_Receiver, - mpsc::{self, Receiver, Sender}, RwLock, + mpsc::{self, Receiver, Sender}, + RwLock, }, }; use crate::{ - disk::error::DiskError, error::{Error, Result}, heal::heal_ops::NOP_HEAL, new_object_layer_fn, store_api::StorageAPI, utils::path::SLASH_SEPARATOR + disk::error::DiskError, + error::{Error, Result}, + heal::heal_ops::NOP_HEAL, + new_object_layer_fn, + store_api::StorageAPI, + utils::path::SLASH_SEPARATOR, }; use super::{ @@ -148,7 +154,7 @@ async fn heal_disk_format(opts: HealOpts) -> Result<(HealResultItem, Option= interval.start && size <= interval.end { + if size >= interval.start && size <= interval.end { self.0[idx] += 1; break; } @@ -167,7 +167,7 @@ impl Default for VersionsHistogram { impl VersionsHistogram { fn add(&mut self, size: u64) { for (idx, interval) in OBJECTS_VERSION_COUNT_INTERVALS.iter().enumerate() { - if size >= interval.start && size <= interval.end { + if size >= interval.start && size <= interval.end { self.0[idx] += 1; break; } @@ -259,7 +259,10 @@ impl DataUsageEntry { replication_stats.replica_count += summary.replica_count as u64; for (arn, st) in &summary.repl_target_stats { - let tgt_stat = replication_stats.targets.entry(arn.to_string()).or_insert(ReplicationStats::default()); + let tgt_stat = replication_stats + .targets + .entry(arn.to_string()) + .or_insert(ReplicationStats::default()); tgt_stat.pending_size += st.pending_size as u64; tgt_stat.failed_size += st.failed_size as u64; tgt_stat.replicated_size += st.replicated_size as u64; @@ -412,7 +415,7 @@ impl DataUsageCache { } Ok(d) } - + pub async fn save(&self, name: &str) -> Result<()> { let buf = self.marshal_msg()?; let buf_clone = buf.clone(); @@ -429,7 +432,7 @@ impl DataUsageCache { }); save_config(&store, name, &buf).await } - + pub fn replace(&mut self, path: &str, parent: &str, e: DataUsageEntry) { let hash = hash_path(path); self.cache.insert(hash.key(), e); @@ -447,7 +450,10 @@ impl DataUsageCache { pub fn replace_hashed(&mut self, hash: &DataUsageHash, parent: &Option, e: &DataUsageEntry) { self.cache.insert(hash.key(), e.clone()); if let Some(parent) = parent { - self.cache.entry(parent.key()).or_insert(DataUsageEntry::default()).add_child(hash); + self.cache + .entry(parent.key()) + .or_insert(DataUsageEntry::default()) + .add_child(hash); } } @@ -456,7 +462,11 @@ impl DataUsageCache { } pub fn find_children_copy(&mut self, h: DataUsageHash) -> DataUsageHashMap { - self.cache.entry(h.string()).or_insert(DataUsageEntry::default()).children.clone() + self.cache + .entry(h.string()) + .or_insert(DataUsageEntry::default()) + .children + .clone() } pub fn flatten(&self, root: &DataUsageEntry) -> DataUsageEntry { @@ -488,7 +498,7 @@ impl DataUsageCache { let p = self.cache.entry(parent.key()).or_insert(DataUsageEntry::default()); p.add_child(hash); } - }, + } None => return, } } @@ -517,8 +527,8 @@ impl DataUsageCache { flat.replication_stats = None; } return Some(flat); - }, - None => None + } + None => None, } } @@ -544,10 +554,8 @@ impl DataUsageCache { pub fn is_compacted(&self, hash: &DataUsageHash) -> bool { match self.cache.get(&hash.key()) { - Some(due) => { - due.compacted - }, - None => false + Some(due) => due.compacted, + None => false, } } @@ -576,9 +584,7 @@ impl DataUsageCache { let mut leaves = Vec::new(); let mut remove = total - limit; add(self, path, &mut leaves); - leaves.sort_by(|a, b| { - a.objects.cmp(&b.objects) - }); + leaves.sort_by(|a, b| a.objects.cmp(&b.objects)); while remove > 0 && leaves.len() > 0 { let e = leaves.first().unwrap(); @@ -602,7 +608,6 @@ impl DataUsageCache { remove -= removing; leaves.remove(0); } - } pub fn total_children_rec(&self, path: &str) -> usize { @@ -652,8 +657,13 @@ fn add(data_usage_cache: &DataUsageCache, path: &DataUsageHash, leaves: &mut Vec return; } - let sz = data_usage_cache.size_recursive(&path.key()).unwrap_or(DataUsageEntry::default()); - leaves.push(Inner{objects: sz.objects, path: path.clone()}); + let sz = data_usage_cache + .size_recursive(&path.key()) + .unwrap_or(DataUsageEntry::default()); + leaves.push(Inner { + objects: sz.objects, + path: path.clone(), + }); for ch in e.children.iter() { add(data_usage_cache, &DataUsageHash(ch.clone()), leaves); } diff --git a/ecstore/src/heal/error.rs b/ecstore/src/heal/error.rs index 9b5e9d0cd..1b6cd6741 100644 --- a/ecstore/src/heal/error.rs +++ b/ecstore/src/heal/error.rs @@ -1 +1 @@ -pub const ERR_IGNORE_FILE_CONTRIB: &str = "ignore this file's contribution toward data-usage"; \ No newline at end of file +pub const ERR_IGNORE_FILE_CONTRIB: &str = "ignore this file's contribution toward data-usage"; diff --git a/ecstore/src/heal/heal_commands.rs b/ecstore/src/heal/heal_commands.rs index 5c208d309..7c3df3495 100644 --- a/ecstore/src/heal/heal_commands.rs +++ b/ecstore/src/heal/heal_commands.rs @@ -7,7 +7,13 @@ use serde::{Deserialize, Serialize}; use tokio::sync::RwLock; use crate::{ - disk::{DeleteOptions, DiskAPI, DiskStore, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, error::{Error, Result}, global::GLOBAL_BackgroundHealState, heal::heal_ops::HEALING_TRACKER_FILENAME, new_object_layer_fn, store_api::{BucketInfo, StorageAPI}, utils::fs::read_file + disk::{DeleteOptions, DiskAPI, DiskStore, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, + error::{Error, Result}, + global::GLOBAL_BackgroundHealState, + heal::heal_ops::HEALING_TRACKER_FILENAME, + new_object_layer_fn, + store_api::{BucketInfo, StorageAPI}, + utils::fs::read_file, }; pub type HealScanMode = usize; diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index de79a66f2..6c1e716f1 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -142,7 +142,6 @@ impl HealSequence { ..Default::default() } } - } impl HealSequence { @@ -447,11 +446,13 @@ impl AllHealState { async fn periodic_heal_seqs_clean(&mut self) { let _ = self.mu.write().await; let now = SystemTime::now(); - + let mut keys_to_reomve = Vec::new(); for (k, v) in self.heal_seq_map.iter() { let r = v.read().await; - if r.has_ended().await && (UNIX_EPOCH + Duration::from_secs(*(r.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now { + if r.has_ended().await + && (UNIX_EPOCH + Duration::from_secs(*(r.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now + { keys_to_reomve.push(k.clone()) } } @@ -546,7 +547,8 @@ impl AllHealState { } } - self.heal_seq_map.insert(path_s.to_string(), Arc::new(RwLock::new(heal_sequence.clone()))); + self.heal_seq_map + .insert(path_s.to_string(), Arc::new(RwLock::new(heal_sequence.clone()))); let client_token = heal_sequence.client_token.clone(); if *GLOBAL_IsDistErasure.read().await { diff --git a/ecstore/src/heal/mod.rs b/ecstore/src/heal/mod.rs index 9a3c28273..f4a8e486c 100644 --- a/ecstore/src/heal/mod.rs +++ b/ecstore/src/heal/mod.rs @@ -2,7 +2,7 @@ pub mod background_heal_ops; pub mod data_scanner; pub mod data_scanner_metric; pub mod data_usage; +pub mod data_usage_cache; pub mod error; pub mod heal_commands; pub mod heal_ops; -pub mod data_usage_cache; diff --git a/ecstore/src/sets.rs b/ecstore/src/sets.rs index 30d8c5a04..2fb852f47 100644 --- a/ecstore/src/sets.rs +++ b/ecstore/src/sets.rs @@ -12,7 +12,7 @@ use crate::{ disk::{ error::DiskError, format::{DistributionAlgoVersion, FormatV3}, - new_disk, DiskInfo, DiskOption, DiskStore, + new_disk, DiskAPI, DiskInfo, DiskOption, DiskStore, }, endpoints::{Endpoints, PoolEndpoints}, error::{Error, Result}, @@ -31,8 +31,7 @@ use crate::{ ObjectToDelete, PartInfo, PutObjReader, StorageAPI, }, store_init::{check_format_erasure_values, get_format_erasure_in_quorum, load_format_erasure_all, save_format_file}, - - utils::hash,, + utils::hash, }; use tokio::time::Duration; @@ -522,7 +521,7 @@ impl StorageAPI for Sets { let before_derives = formats_to_drives_info(&self.endpoints.endpoints, &formats, &errs); res.before = vec![HealDriveInfo::default(); before_derives.len()]; res.after = vec![HealDriveInfo::default(); before_derives.len()]; - + for v in before_derives.iter() { res.before.push(v.clone()); res.after.push(v.clone()); @@ -536,15 +535,16 @@ impl StorageAPI for Sets { } let format_op_id = Uuid::new_v4().to_string(); - let (new_format_sets, current_disks_info) = new_heal_format_sets(&ref_format, self.set_count, self.set_drive_count, &formats, &errs); + let (new_format_sets, current_disks_info) = + new_heal_format_sets(&ref_format, self.set_count, self.set_drive_count, &formats, &errs); if !dry_run { - let mut tmp_new_formats = vec![None; self.set_count*self.set_drive_count]; + let mut tmp_new_formats = vec![None; self.set_count * self.set_drive_count]; for (i, set) in new_format_sets.iter().enumerate() { for (j, fm) in set.iter().enumerate() { if let Some(fm) = fm { - res.after[i*self.set_drive_count+j].uuid = fm.erasure.this.to_string(); - res.after[i*self.set_drive_count+j].state = DRIVE_STATE_OK.to_string(); - tmp_new_formats[i*self.set_drive_count+j] = Some(fm.clone()); + res.after[i * self.set_drive_count + j].uuid = fm.erasure.this.to_string(); + res.after[i * self.set_drive_count + j].state = DRIVE_STATE_OK.to_string(); + tmp_new_formats[i * self.set_drive_count + j] = Some(fm.clone()); } } } @@ -690,7 +690,7 @@ fn new_heal_format_sets( let mut current_disks_info = vec![vec![DiskInfo::default(); set_drive_count]; set_count]; for (i, set) in ref_format.erasure.sets.iter().enumerate() { for (j, value) in set.iter().enumerate() { - if let Some(Some(err)) = errs.get(i*set_drive_count+j) { + if let Some(Some(err)) = errs.get(i * set_drive_count + j) { match err.downcast_ref::() { Some(DiskError::UnformattedDisk) => { let mut fm = FormatV3::new(set_count, set_drive_count); @@ -702,11 +702,11 @@ fn new_heal_format_sets( fm.erasure.version = ref_format.erasure.version.clone(); fm.erasure.distribution_algo = ref_format.erasure.distribution_algo.clone(); new_formats[i][j] = Some(fm); - }, - _ => {}, + } + _ => {} } } - if let (Some(format), None) = (&formats[i*set_drive_count+j], &errs[i*set_drive_count+j]) { + if let (Some(format), None) = (&formats[i * set_drive_count + j], &errs[i * set_drive_count + j]) { if let Some(info) = &format.disk_info { if !info.endpoint.is_empty() { current_disks_info[i][j] = info.clone(); diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index b9d1c492e..27e663b96 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -44,7 +44,6 @@ use http::HeaderMap; use lazy_static::lazy_static; use rand::Rng; use s3s::dto::{BucketVersioningStatus, ObjectLockConfiguration, ObjectLockEnabled, VersioningConfiguration}; -use tokio::sync::mpsc::Sender; use std::cmp::Ordering; use std::slice::Iter; use std::{ @@ -54,11 +53,12 @@ use std::{ }; use time::OffsetDateTime; use tokio::fs; +use tokio::sync::mpsc::Sender; use tokio::sync::{mpsc, RwLock, Semaphore}; +use crate::heal::data_usage_cache::DataUsageCache; use tracing::{debug, info, warn}; use uuid::Uuid; -use crate::heal::data_usage_cache::DataUsageCache; const MAX_UPLOADS_LIST: usize = 10000; @@ -491,7 +491,12 @@ impl ECStore { internal_get_pool_info_existing_with_opts(&self.pools, bucket, object, opts).await } - pub async fn ns_scanner(&self, updates: Sender, want_cycle: usize, heal_scan_mode: HealScanMode) -> Result<()> { + pub async fn ns_scanner( + &self, + updates: Sender, + want_cycle: usize, + heal_scan_mode: HealScanMode, + ) -> Result<()> { let all_buckets = self.list_bucket(&BucketOptions::default()).await?; if all_buckets.is_empty() { let _ = updates.send(DataUsageInfo::default()).await; @@ -509,21 +514,21 @@ impl ECStore { for set in pool.disk_set.iter() { let index = result_index; let results_clone = results.clone(); - futures.push(async move { + futures.push(async move { let (tx, mut rx) = mpsc::channel(100); let task = tokio::spawn(async move { loop { match rx.recv().await { Some(info) => { results_clone.write().await[index] = info; - }, + } None => { - return ; + return; } } } }); - + let _ = task.await; }); result_index += 1; @@ -1427,9 +1432,8 @@ impl StorageAPI for ECStore { match err.downcast_ref::() { Some(DiskError::NoHealRequired) => { count_no_heal += 1; - }, + } _ => { - continue; } } @@ -1438,7 +1442,6 @@ impl StorageAPI for ECStore { r.set_count += result.set_count; r.before.append(&mut result.before); r.after.append(&mut result.after); - } if count_no_heal == self.pools.len() { return Ok((r, Some(Error::new(DiskError::NoHealRequired)))); @@ -1449,7 +1452,13 @@ impl StorageAPI for ECStore { async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { unimplemented!() } - async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result<(HealResultItem, Option)> { + async fn heal_object( + &self, + bucket: &str, + object: &str, + version_id: &str, + opts: &HealOpts, + ) -> Result<(HealResultItem, Option)> { let object = utils::path::encode_dir_object(object); let errs = Arc::new(RwLock::new(vec![None; self.pools.len()])); let results = Arc::new(RwLock::new(vec![HealResultItem::default(); self.pools.len()])); diff --git a/ecstore/src/store_api.rs b/ecstore/src/store_api.rs index c64180d2b..dc8c91141 100644 --- a/ecstore/src/store_api.rs +++ b/ecstore/src/store_api.rs @@ -102,12 +102,6 @@ impl FileInfo { false } - pub fn inline_data(&self) -> bool { - self.metadata.as_ref().map_or(false, |metadata| { - metadata.contains_key(&format!("{}inline-data", RESERVED_METADATA_PREFIX_LOWER)) && !self.is_remote() - }) - } - pub fn get_etag(&self) -> Option { if let Some(meta) = &self.metadata { meta.get("etag").cloned() @@ -917,9 +911,15 @@ pub trait StorageAPI: ObjectIO { async fn put_object_tags(&self, bucket: &str, object: &str, tags: &str, opts: &ObjectOptions) -> Result; async fn delete_object_tags(&self, bucket: &str, object: &str, opts: &ObjectOptions) -> Result; - async fn heal_format(&self, dry_run: bool) ->Result<(HealResultItem, Option)>; + async fn heal_format(&self, dry_run: bool) -> Result<(HealResultItem, Option)>; async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result; - async fn heal_object(&self, bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Result<(HealResultItem, Option)>; + async fn heal_object( + &self, + bucket: &str, + object: &str, + version_id: &str, + opts: &HealOpts, + ) -> Result<(HealResultItem, Option)>; async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()>; async fn get_pool_and_set(&self, id: &str) -> Result<(Option, Option, Option)>; async fn check_abandoned_parts(&self, bucket: &str, object: &str, opts: &HealOpts) -> Result<()>; diff --git a/ecstore/src/store_init.rs b/ecstore/src/store_init.rs index e531d6470..583c5546a 100644 --- a/ecstore/src/store_init.rs +++ b/ecstore/src/store_init.rs @@ -2,10 +2,13 @@ use crate::config::{storageclass, KVS}; use crate::disk::DiskAPI; use crate::{ disk::{ - error::DiskError, format::{FormatErasureVersion, FormatMetaVersion, FormatV3}, new_disk, DiskInfoOptions, DiskOption, DiskStore, FORMAT_CONFIG_FILE, RUSTFS_META_BUCKET + error::DiskError, + format::{FormatErasureVersion, FormatMetaVersion, FormatV3}, + new_disk, DiskInfoOptions, DiskOption, DiskStore, FORMAT_CONFIG_FILE, RUSTFS_META_BUCKET, }, endpoints::Endpoints, - error::{Error, Result}, heal::heal_commands::init_healing_tracker, + error::{Error, Result}, + heal::heal_commands::init_healing_tracker, }; use futures::future::join_all; use std::{ @@ -232,10 +235,12 @@ pub async fn load_format_erasure(disk: &DiskStore, heal: bool) -> Result Result { match str { - "1"| "t"| "T"| "true"| "TRUE"| "True"| "on"| "ON"| "On"| "enabled" => { + "1" | "t" | "T" | "true" | "TRUE" | "True" | "on" | "ON" | "On" | "enabled" => { return Ok(true); - }, - "0"| "f"| "F"| "false"| "FALSE"| "False"| "off"| "OFF"| "Off"| "disabled" => { + } + "0" | "f" | "F" | "false" | "FALSE" | "False" | "off" | "OFF" | "Off" | "disabled" => { return Ok(false); } _ => { return Err(Error::from_string(format!("ParseBool: parsing {}", str))); } } -} \ No newline at end of file +} diff --git a/ecstore/src/utils/mod.rs b/ecstore/src/utils/mod.rs index c1f6ce7d8..65aac72b2 100644 --- a/ecstore/src/utils/mod.rs +++ b/ecstore/src/utils/mod.rs @@ -1,6 +1,6 @@ +pub mod bool_flag; pub mod crypto; pub mod ellipses; -pub mod bool_flag; pub mod fs; pub mod hash; pub mod net; From 2defaa801bc47e4561eb33e9d1c1d8dfdedf613f Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Thu, 14 Nov 2024 07:43:20 +0000 Subject: [PATCH 04/11] temp(3) Signed-off-by: junxiang Mu <1948535941@qq.com> --- ecstore/src/heal/data_scanner.rs | 153 ++++++++++++++++++------ ecstore/src/heal/data_scanner_metric.rs | 34 +++++- ecstore/src/heal/data_usage_cache.rs | 38 +++++- 3 files changed, 183 insertions(+), 42 deletions(-) diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs index 15916d17e..b9d82f2e5 100644 --- a/ecstore/src/heal/data_scanner.rs +++ b/ecstore/src/heal/data_scanner.rs @@ -6,7 +6,7 @@ use std::{ path::{Path, PathBuf}, pin::Pin, sync::{ - atomic::{AtomicU32, AtomicU64}, + atomic::{AtomicBool, AtomicU32, AtomicU64, Ordering}, Arc, }, time::{Duration, SystemTime, UNIX_EPOCH}, @@ -28,13 +28,22 @@ use tokio::{ }; use tracing::{error, info}; +use super::{ + data_scanner_metric::globalScannerMetrics, + data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, + data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash}, + heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}, +}; +use crate::disk::DiskAPI; +use crate::heal::data_scanner_metric::current_path_updater; +use crate::heal::data_usage::DATA_USAGE_ROOT; use crate::{ cache_value::metacache_set::{list_path_raw, ListPathRawOptions}, config::{ common::{read_config, save_config}, heal::Config, }, - disk::{error::DiskError, DiskStore, MetaCacheEntries, MetaCacheEntry, MetadataResolutionParams}, + disk::{error::DiskError, DiskInfoOptions, DiskStore, MetaCacheEntries, MetaCacheEntry, MetadataResolutionParams}, error::{Error, Result}, global::{GLOBAL_BackgroundHealState, GLOBAL_IsErasure, GLOBAL_IsErasureSD}, heal::{ @@ -50,19 +59,12 @@ use crate::{ utils::path::{path_join, path_to_bucket_object, path_to_bucket_object_with_base_path, SLASH_SEPARATOR}, }; -use super::{ - data_scanner_metric::globalScannerMetrics, - data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, - data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash}, - heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}, -}; - const DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16; // Visit all folders every n cycles. const DATA_SCANNER_COMPACT_LEAST_OBJECT: u64 = 500; // Compact when there are less than this many objects in a branch. const DATA_SCANNER_COMPACT_AT_CHILDREN: u64 = 10000; // Compact when there are this many children in a branch. const DATA_SCANNER_COMPACT_AT_FOLDERS: u64 = DATA_SCANNER_COMPACT_AT_CHILDREN / 4; // Compact when this many subfolders in a single folder. -const DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS: u64 = 250_000; // Compact when this many subfolders in a single folder (even top level). +pub const DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS: u64 = 250_000; // Compact when this many subfolders in a single folder (even top level). const DATA_SCANNER_START_DELAY: Duration = Duration::from_secs(60); // Time to wait on startup and between cycles. const HEAL_DELETE_DANGLING: bool = true; @@ -333,7 +335,7 @@ struct Heal { bitrot: bool, } -struct ScannerItem { +pub struct ScannerItem { path: String, bucket: String, prefix: String, @@ -399,7 +401,9 @@ struct CachedFolder { object_heal_prob_div: u32, } -type GetSizeFn = Box Pin>>> + Send + 'static>; +pub type GetSizeFn = + Box Pin> + Send>> + Send + Sync + 'static>; +pub type UpdateCurrentPathFn = Arc Pin + Send>> + Send + Sync + 'static>; struct FolderScanner { root: String, @@ -410,15 +414,32 @@ struct FolderScanner { data_usage_scanner_debug: bool, heal_object_select: u32, scan_mode: HealScanMode, - should_heal: Arc bool + Send + Sync>, disks: Vec>, disks_quorum: usize, updates: Sender, last_update: SystemTime, - update_current_path: Arc, + update_current_path: UpdateCurrentPathFn, + skip_heal: AtomicBool, + drive: DiskStore, } impl FolderScanner { + async fn should_heal(&self) -> bool { + if self.skip_heal.load(Ordering::SeqCst) { + return false; + } + if self.heal_object_select == 0 { + return false; + } + if let Ok(info) = self.drive.disk_info(&DiskInfoOptions::default()).await { + if info.healing { + self.skip_heal.store(true, Ordering::SeqCst); + return false; + } + } + true + } + async fn scan_folder(&mut self, folder: &CachedFolder, into: &mut DataUsageEntry) -> Result<()> { let this_hash = hash_path(&folder.name); let was_compacted = into.compacted; @@ -499,7 +520,7 @@ impl FolderScanner { item.heal.enabled = this_hash.mod_alt( self.old_cache.info.next_cycle / folder.object_heal_prob_div, self.heal_object_select / folder.object_heal_prob_div, - ) && (self.should_heal)(); + ) && self.should_heal().await; item.heal.bitrot = self.scan_mode == HEAL_DEEP_SCAN; let (sz, err) = match (self.get_size)(&item).await { @@ -592,7 +613,7 @@ impl FolderScanner { .replace_hashed(&h, &Some(this_hash.clone()), &DataUsageEntry::default()); } } - (self.update_current_path)(&folder.name); + (self.update_current_path)(&folder.name).await; scan(folder, into, self).await; // Add new folders if this is new and we don't have existing. if !into.compacted { @@ -617,12 +638,12 @@ impl FolderScanner { continue; } } - (self.update_current_path)(&folder.name); + (self.update_current_path)(&folder.name).await; scan(folder, into, self).await; } // Scan for healing - if abandoned_children.is_empty() || !(self.should_heal)() { + if abandoned_children.is_empty() || !self.should_heal().await { break; } @@ -649,12 +670,12 @@ impl FolderScanner { }; for k in abandoned_children.iter() { - if !(self.should_heal)() { + if !self.should_heal().await { break; } let (bucket, prefix) = path_to_bucket_object(k); - (self.update_current_path)(k); + (self.update_current_path)(k).await; if bucket != resolver.bucket { let _ = bg_seq @@ -675,11 +696,10 @@ impl FolderScanner { let found_objs = Arc::new(RwLock::new(false)); let found_objs_clone = found_objs.clone(); let (tx, rx) = broadcast::channel(1); - let tx_partial = tx.clone(); + // let tx_partial = tx.clone(); let tx_finished = tx.clone(); let update_current_path_agreed = self.update_current_path.clone(); let update_current_path_partial = self.update_current_path.clone(); - let should_heal_clone = self.should_heal.clone(); let resolver_clone = resolver.clone(); let bg_seq_clone = bg_seq.clone(); let lopts = ListPathRawOptions { @@ -693,24 +713,24 @@ impl FolderScanner { Box::pin({ let update_current_path_agreed = update_current_path_agreed.clone(); async move { - update_current_path_agreed(&entry.name); + update_current_path_agreed(&entry.name).await; } }) })), partial: Some(Box::new(move |entries: MetaCacheEntries, _: &[Option]| { Box::pin({ let update_current_path_partial = update_current_path_partial.clone(); - let should_heal_partial = should_heal_clone.clone(); - let tx_partial = tx_partial.clone(); + // let tx_partial = tx_partial.clone(); let resolver_partial = resolver_clone.clone(); let bucket_partial = bucket.clone(); let found_objs_clone = found_objs_clone.clone(); let bg_seq_partial = bg_seq_clone.clone(); async move { - if !should_heal_partial() { - let _ = tx_partial.send(true); - return; - } + // Todo + // if !fs.should_heal().await { + // let _ = tx_partial.send(true); + // return; + // } let entry = match entries.resolve(resolver_partial) { Ok(Some(entry)) => entry, _ => match entries.first_found() { @@ -719,7 +739,7 @@ impl FolderScanner { }, }; - update_current_path_partial(&entry.name); + update_current_path_partial(&entry.name).await; let mut custom = HashMap::new(); if entry.is_dir() { return; @@ -766,8 +786,8 @@ impl FolderScanner { .queue_heal_task( HealSource { bucket: bucket_partial.clone(), - object: entry.name.clone(), - version_id: "".to_string(), + object: fiv.name.clone(), + version_id: ver.version_id.map_or("".to_string(), |ver_id| ver_id.to_string()), ..Default::default() }, HEAL_ITEM_OBJECT.to_string(), @@ -787,7 +807,7 @@ impl FolderScanner { } }) })), - finished: Some(Box::new(move |err: &[Option]| { + finished: Some(Box::new(move |_: &[Option]| { Box::pin({ let tx_finished = tx_finished.clone(); async move { @@ -820,12 +840,11 @@ impl FolderScanner { .size_recursive(&this_hash.key()) .unwrap_or(DataUsageEntry::default()); flat.compacted = true; - let mut compact = false; - if flat.objects < DATA_SCANNER_COMPACT_LEAST_OBJECT.try_into().unwrap() { - compact = true; + let compact = if flat.objects < DATA_SCANNER_COMPACT_LEAST_OBJECT.try_into().unwrap() { + true } else { // Compact if we only have objects as children... - compact = true; + let mut compact = true; for k in into.children.iter() { if let Some(v) = self.new_cache.cache.get(k) { if !v.children.is_empty() || v.objects > 1 { @@ -834,7 +853,8 @@ impl FolderScanner { } } } - } + compact + }; if compact { self.new_cache.delete_recursive(&this_hash); self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), &flat); @@ -930,3 +950,60 @@ pub fn has_active_rules(config: &ReplicationConfiguration, prefix: &str, recursi } false } + +pub async fn scan_data_folder( + disks: &[Option], + drive: &DiskStore, + cache: &DataUsageCache, + get_size_fn: GetSizeFn, + heal_scan_mode: HealScanMode, +) -> Result { + if cache.info.name.is_empty() || cache.info.name == DATA_USAGE_ROOT { + return Err(Error::from_string("internal error: root scan attempted")); + } + + let base_path = drive.to_string(); + let (update_path, close_disk) = current_path_updater(&base_path, &cache.info.name); + let mut s = FolderScanner { + root: base_path, + get_size: get_size_fn, + old_cache: cache.clone(), + new_cache: DataUsageCache::default(), + update_cache: DataUsageCache::default(), + data_usage_scanner_debug: false, + heal_object_select: 0, + scan_mode: heal_scan_mode, + updates: cache.info.updates.clone().unwrap(), + last_update: SystemTime::now(), + update_current_path: update_path, + disks: disks.to_vec(), + disks_quorum: disks.len() / 2, + skip_heal: if *GLOBAL_IsErasure.read().await || cache.info.skip_healing { + AtomicBool::new(true) + } else { + AtomicBool::new(false) + }, + drive: drive.clone(), + }; + + if *GLOBAL_IsErasure.read().await || !cache.info.skip_healing { + s.heal_object_select = HEAL_OBJECT_SELECT_PROB as u32; + } + + let mut root = DataUsageEntry::default(); + let folder = CachedFolder { + name: cache.info.name.clone(), + object_heal_prob_div: 1, + parent: DataUsageHash("".to_string()), + }; + + if s.scan_folder(&folder, &mut root).await.is_err() { + close_disk().await; + } + s.new_cache + .force_compact(DATA_SCANNER_COMPACT_AT_CHILDREN.try_into().unwrap()); + s.new_cache.info.last_update = SystemTime::now(); + s.new_cache.info.next_cycle = cache.info.next_cycle; + close_disk().await; + Ok(s.new_cache) +} diff --git a/ecstore/src/heal/data_scanner_metric.rs b/ecstore/src/heal/data_scanner_metric.rs index a5e66efe3..4947aa812 100644 --- a/ecstore/src/heal/data_scanner_metric.rs +++ b/ecstore/src/heal/data_scanner_metric.rs @@ -1,3 +1,6 @@ +use lazy_static::lazy_static; +use std::future::Future; +use std::pin::Pin; use std::{ collections::HashMap, sync::{ @@ -6,11 +9,9 @@ use std::{ }, time::SystemTime, }; - -use lazy_static::lazy_static; use tokio::sync::RwLock; -use super::data_scanner::CurrentScannerCycle; +use super::data_scanner::{CurrentScannerCycle, UpdateCurrentPathFn}; lazy_static! { pub static ref globalScannerMetrics: Arc> = Arc::new(RwLock::new(ScannerMetrics::new())); @@ -55,6 +56,7 @@ pub enum ScannerMetric { pub struct ScannerMetrics { operations: Vec, cycle_info: RwLock>, + current_paths: HashMap, } impl ScannerMetrics { @@ -62,6 +64,7 @@ impl ScannerMetrics { Self { operations: (0..ScannerMetric::Last as usize).map(|_| AtomicU32::new(0)).collect(), cycle_info: RwLock::new(None), + current_paths: HashMap::new(), } } @@ -75,3 +78,28 @@ impl ScannerMetrics { *self.cycle_info.write().await = c; } } + +pub type CloseDiskFn = Arc Pin + Send>> + Send + 'static>; +pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) { + let disk_1 = disk.to_string(); + let disk_2 = disk.to_string(); + ( + Arc::new(move |path: &str| { + let disk_inner = disk_1.clone(); + let path = path.to_string(); + Box::pin(async move { + globalScannerMetrics + .write() + .await + .current_paths + .insert(disk_inner, path.to_string()); + }) + }), + Arc::new(move || { + let disk_inner = disk_2.clone(); + Box::pin(async move { + globalScannerMetrics.write().await.current_paths.remove(&disk_inner); + }) + }), + ) +} diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs index 4ebc3ced7..820bc858b 100644 --- a/ecstore/src/heal/data_usage_cache.rs +++ b/ecstore/src/heal/data_usage_cache.rs @@ -22,7 +22,7 @@ use std::u64; use tokio::sync::mpsc::Sender; use tokio::time::sleep; -use super::data_scanner::SizeSummary; +use super::data_scanner::{SizeSummary, DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS}; use super::data_usage::DATA_USAGE_ROOT; // DATA_USAGE_BUCKET_LEN must be length of ObjectsHistogramIntervals @@ -559,6 +559,33 @@ impl DataUsageCache { } } + pub fn force_compact(&mut self, limit: usize) { + if self.cache.len() < limit { + return; + } + let top = hash_path(&self.info.name).key(); + let top_e = match self.find(&top) { + Some(e) => e, + None => return, + }; + if top_e.children.len() > DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS.try_into().unwrap() { + self.reduce_children_of(&hash_path(&self.info.name), limit, true); + } + if self.cache.len() <= limit { + return; + } + + let mut found = HashSet::new(); + found.insert(top); + mark(self, &top_e, &mut found); + self.cache.retain(|k, _| { + if !found.contains(k) { + return false; + } + true + }); + } + pub fn reduce_children_of(&mut self, path: &DataUsageHash, limit: usize, compact_self: bool) { let e = match self.cache.get(&path.key()) { Some(e) => e, @@ -669,6 +696,15 @@ fn add(data_usage_cache: &DataUsageCache, path: &DataUsageHash, leaves: &mut Vec } } +fn mark(duc: &DataUsageCache, entry: &DataUsageEntry, found: &mut HashSet) { + for k in entry.children.iter() { + found.insert(k.to_string()); + if let Some(ch) = duc.cache.get(k) { + mark(duc, ch, found); + } + } +} + #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct DataUsageHash(pub String); From 7eed1a6db374b4687697114d2226a577ecb14f37 Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Sat, 16 Nov 2024 12:57:31 +0800 Subject: [PATCH 05/11] temp(4) Signed-off-by: junxiang Mu <1948535941@qq.com> --- common/common/src/last_minute.rs | 106 + common/common/src/lib.rs | 1 + .../generated/flatbuffers_generated/models.rs | 207 +- .../src/generated/proto_gen/node_service.rs | 1876 +++++++++++++---- ecstore/src/disk/local.rs | 121 +- ecstore/src/disk/mod.rs | 12 +- ecstore/src/disk/remote.rs | 4 +- ecstore/src/heal/data_scanner.rs | 117 +- ecstore/src/heal/data_scanner_metric.rs | 125 +- ecstore/src/heal/data_usage.rs | 87 +- ecstore/src/heal/data_usage_cache.rs | 158 +- ecstore/src/heal/error.rs | 1 + ecstore/src/store.rs | 88 +- 13 files changed, 2289 insertions(+), 614 deletions(-) create mode 100644 common/common/src/last_minute.rs diff --git a/common/common/src/last_minute.rs b/common/common/src/last_minute.rs new file mode 100644 index 000000000..6141a3180 --- /dev/null +++ b/common/common/src/last_minute.rs @@ -0,0 +1,106 @@ +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +#[derive(Clone, Debug, Default)] +pub struct AccElem { + pub total: u64, + pub size: u64, + pub n: u64, +} + +impl AccElem { + pub fn add(&mut self, dur: &Duration) { + let dur = dur.as_secs(); + self.total += dur; + self.n += 1; + } + + pub fn merge(&mut self, b: &AccElem) { + self.n += b.n; + self.total += b.total; + self.size += b.size; + } + + pub fn avg(&self) -> Duration { + if self.n >= 1 && self.total > 0 { + return Duration::from_secs(self.total / self.n); + } + Duration::from_secs(0) + } +} + +#[derive(Clone)] +pub struct LastMinuteLatency { + pub totals: Vec, + pub last_sec: u64, +} + +impl Default for LastMinuteLatency { + fn default() -> Self { + Self { + totals: vec![AccElem::default(); 60], + last_sec: Default::default(), + } + } +} + +impl LastMinuteLatency { + pub fn merge(&mut self, o: &mut LastMinuteLatency) -> LastMinuteLatency { + let mut merged = LastMinuteLatency::default(); + if self.last_sec > o.last_sec { + o.forward_to(self.last_sec); + merged.last_sec = self.last_sec; + } else { + self.forward_to(o.last_sec); + merged.last_sec = o.last_sec; + } + + for i in 0..merged.totals.len() { + merged.totals[i] = AccElem { + total: self.totals[i].total + o.totals[i].total, + n: self.totals[i].n + o.totals[i].n, + size: self.totals[i].size + o.totals[i].size, + } + } + merged + } + + pub fn add(&mut self, t: &Duration) { + let sec = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs(); + self.forward_to(sec); + let win_idx = sec % 60; + self.totals[win_idx as usize].add(t); + self.last_sec = sec; + } + + pub fn add_all(&mut self, sec: u64, a: &AccElem) { + self.forward_to(sec); + let win_idx = sec % 60; + self.totals[win_idx as usize].merge(a); + self.last_sec = sec; + } + + pub fn get_total(&mut self) -> AccElem { + let mut res = AccElem::default(); + let sec = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs(); + self.forward_to(sec); + for elem in self.totals.iter() { + res.merge(elem); + } + res + } + + pub fn forward_to(&mut self, t: u64) { + if self.last_sec >= t { + return; + } + if t - self.last_sec >= 60 { + self.totals = vec![AccElem::default(); 60]; + return; + } + while self.last_sec != t { + let idx = (self.last_sec + 1) % 60; + self.totals[idx as usize] = AccElem::default(); + self.last_sec += 1; + } + } +} diff --git a/common/common/src/lib.rs b/common/common/src/lib.rs index dc9ee425c..a8998fee0 100644 --- a/common/common/src/lib.rs +++ b/common/common/src/lib.rs @@ -1,5 +1,6 @@ pub mod error; pub mod globals; +pub mod last_minute; /// Defers evaluation of a block of code until the end of the scope. #[macro_export] diff --git a/common/protos/src/generated/flatbuffers_generated/models.rs b/common/protos/src/generated/flatbuffers_generated/models.rs index e4949fdcf..aa1f6ae2f 100644 --- a/common/protos/src/generated/flatbuffers_generated/models.rs +++ b/common/protos/src/generated/flatbuffers_generated/models.rs @@ -1,9 +1,10 @@ // automatically generated by the FlatBuffers compiler, do not modify + // @generated -use core::cmp::Ordering; use core::mem; +use core::cmp::Ordering; extern crate flatbuffers; use self::flatbuffers::{EndianScalar, Follow}; @@ -11,114 +12,112 @@ use self::flatbuffers::{EndianScalar, Follow}; #[allow(unused_imports, dead_code)] pub mod models { - use core::cmp::Ordering; - use core::mem; + use core::mem; + use core::cmp::Ordering; - extern crate flatbuffers; - use self::flatbuffers::{EndianScalar, Follow}; + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; - pub enum PingBodyOffset {} - #[derive(Copy, Clone, PartialEq)] +pub enum PingBodyOffset {} +#[derive(Copy, Clone, PartialEq)] - pub struct PingBody<'a> { - pub _tab: flatbuffers::Table<'a>, +pub struct PingBody<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { + type Inner = PingBody<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> PingBody<'a> { + pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; + + pub const fn get_fully_qualified_name() -> &'static str { + "models.PingBody" + } + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + PingBody { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args PingBodyArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = PingBodyBuilder::new(_fbb); + if let Some(x) = args.payload { builder.add_payload(x); } + builder.finish() + } + + + #[inline] + pub fn payload(&self) -> Option> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>(PingBody::VT_PAYLOAD, None)} + } +} + +impl flatbuffers::Verifiable for PingBody<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>("payload", Self::VT_PAYLOAD, false)? + .finish(); + Ok(()) + } +} +pub struct PingBodyArgs<'a> { + pub payload: Option>>, +} +impl<'a> Default for PingBodyArgs<'a> { + #[inline] + fn default() -> Self { + PingBodyArgs { + payload: None, } + } +} - impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { - type Inner = PingBody<'a>; - #[inline] - unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { - _tab: flatbuffers::Table::new(buf, loc), - } - } +pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { + #[inline] + pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { + self.fbb_.push_slot_always::>(PingBody::VT_PAYLOAD, payload); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + PingBodyBuilder { + fbb_: _fbb, + start_: start, } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} - impl<'a> PingBody<'a> { - pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; +impl core::fmt::Debug for PingBody<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("PingBody"); + ds.field("payload", &self.payload()); + ds.finish() + } +} +} // pub mod models - pub const fn get_fully_qualified_name() -> &'static str { - "models.PingBody" - } - - #[inline] - pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - PingBody { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, - args: &'args PingBodyArgs<'args>, - ) -> flatbuffers::WIPOffset> { - let mut builder = PingBodyBuilder::new(_fbb); - if let Some(x) = args.payload { - builder.add_payload(x); - } - builder.finish() - } - - #[inline] - pub fn payload(&self) -> Option> { - // Safety: - // Created from valid Table for this object - // which contains a valid value in this slot - unsafe { - self._tab - .get::>>(PingBody::VT_PAYLOAD, None) - } - } - } - - impl flatbuffers::Verifiable for PingBody<'_> { - #[inline] - fn run_verifier(v: &mut flatbuffers::Verifier, pos: usize) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>>("payload", Self::VT_PAYLOAD, false)? - .finish(); - Ok(()) - } - } - pub struct PingBodyArgs<'a> { - pub payload: Option>>, - } - impl<'a> Default for PingBodyArgs<'a> { - #[inline] - fn default() -> Self { - PingBodyArgs { payload: None } - } - } - - pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - start_: flatbuffers::WIPOffset, - } - impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { - #[inline] - pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { - self.fbb_ - .push_slot_always::>(PingBody::VT_PAYLOAD, payload); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { - let start = _fbb.start_table(); - PingBodyBuilder { - fbb_: _fbb, - start_: start, - } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } - } - - impl core::fmt::Debug for PingBody<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut ds = f.debug_struct("PingBody"); - ds.field("payload", &self.payload()); - ds.finish() - } - } -} // pub mod models diff --git a/common/protos/src/generated/proto_gen/node_service.rs b/common/protos/src/generated/proto_gen/node_service.rs index 2a4fcf8ea..9d13aa58b 100644 --- a/common/protos/src/generated/proto_gen/node_service.rs +++ b/common/protos/src/generated/proto_gen/node_service.rs @@ -580,9 +580,15 @@ pub struct GenerallyLockResponse { } /// Generated client implementations. pub mod node_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] - use tonic::codegen::http::Uri; + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; + use tonic::codegen::http::Uri; #[derive(Debug, Clone)] pub struct NodeServiceClient { inner: tonic::client::Grpc, @@ -613,16 +619,22 @@ pub mod node_service_client { let inner = tonic::client::Grpc::with_origin(inner, origin); Self { inner } } - pub fn with_interceptor(inner: T, interceptor: F) -> NodeServiceClient> + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> NodeServiceClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, - Response = http::Response<>::ResponseBody>, + Response = http::Response< + >::ResponseBody, + >, >, - >>::Error: - Into + std::marker::Send + std::marker::Sync, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, { NodeServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -665,9 +677,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Ping"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Ping", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Ping")); @@ -676,13 +694,22 @@ pub mod node_service_client { pub async fn list_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListBucket")); @@ -691,13 +718,22 @@ pub mod node_service_client { pub async fn make_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeBucket")); @@ -706,13 +742,22 @@ pub mod node_service_client { pub async fn get_bucket_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/GetBucketInfo"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/GetBucketInfo", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "GetBucketInfo")); @@ -721,13 +766,22 @@ pub mod node_service_client { pub async fn delete_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteBucket")); @@ -736,13 +790,22 @@ pub mod node_service_client { pub async fn read_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAll"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadAll", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAll")); @@ -751,13 +814,22 @@ pub mod node_service_client { pub async fn write_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteAll"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteAll", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteAll")); @@ -770,9 +842,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Delete"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Delete", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Delete")); @@ -781,13 +859,22 @@ pub mod node_service_client { pub async fn verify_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/VerifyFile"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/VerifyFile", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "VerifyFile")); @@ -796,13 +883,22 @@ pub mod node_service_client { pub async fn check_parts( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/CheckParts"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/CheckParts", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "CheckParts")); @@ -811,13 +907,22 @@ pub mod node_service_client { pub async fn rename_part( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenamePart"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenamePart", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenamePart")); @@ -826,13 +931,22 @@ pub mod node_service_client { pub async fn rename_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameFile"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenameFile", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameFile")); @@ -845,9 +959,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Write"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Write", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Write")); @@ -856,13 +976,22 @@ pub mod node_service_client { pub async fn write_stream( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result>, tonic::Status> { + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteStream"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteStream", + ); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteStream")); @@ -872,13 +1001,22 @@ pub mod node_service_client { pub async fn read_at( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result>, tonic::Status> { + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAt"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadAt", + ); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAt")); @@ -887,13 +1025,22 @@ pub mod node_service_client { pub async fn list_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListDir"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListDir", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListDir")); @@ -902,13 +1049,22 @@ pub mod node_service_client { pub async fn walk_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WalkDir"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WalkDir", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WalkDir")); @@ -917,13 +1073,22 @@ pub mod node_service_client { pub async fn rename_data( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameData"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenameData", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameData")); @@ -932,13 +1097,22 @@ pub mod node_service_client { pub async fn make_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolumes"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeVolumes", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolumes")); @@ -947,13 +1121,22 @@ pub mod node_service_client { pub async fn make_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolume")); @@ -962,13 +1145,22 @@ pub mod node_service_client { pub async fn list_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListVolumes"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListVolumes", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListVolumes")); @@ -977,13 +1169,22 @@ pub mod node_service_client { pub async fn stat_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/StatVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/StatVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "StatVolume")); @@ -992,13 +1193,22 @@ pub mod node_service_client { pub async fn delete_paths( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeletePaths"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeletePaths", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeletePaths")); @@ -1007,13 +1217,22 @@ pub mod node_service_client { pub async fn update_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UpdateMetadata"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/UpdateMetadata", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UpdateMetadata")); @@ -1022,13 +1241,22 @@ pub mod node_service_client { pub async fn write_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteMetadata"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteMetadata", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteMetadata")); @@ -1037,13 +1265,22 @@ pub mod node_service_client { pub async fn read_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadVersion"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadVersion", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadVersion")); @@ -1056,9 +1293,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadXL"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadXL", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadXL")); @@ -1067,13 +1310,22 @@ pub mod node_service_client { pub async fn delete_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersion"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVersion", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersion")); @@ -1082,13 +1334,22 @@ pub mod node_service_client { pub async fn delete_versions( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersions"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVersions", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersions")); @@ -1097,13 +1358,22 @@ pub mod node_service_client { pub async fn read_multiple( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadMultiple"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadMultiple", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadMultiple")); @@ -1112,13 +1382,22 @@ pub mod node_service_client { pub async fn delete_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVolume")); @@ -1127,13 +1406,22 @@ pub mod node_service_client { pub async fn disk_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DiskInfo"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DiskInfo", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DiskInfo")); @@ -1142,13 +1430,22 @@ pub mod node_service_client { pub async fn lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Lock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Lock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Lock")); @@ -1157,13 +1454,22 @@ pub mod node_service_client { pub async fn un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/UnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UnLock")); @@ -1172,13 +1478,22 @@ pub mod node_service_client { pub async fn r_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RLock")); @@ -1187,13 +1502,22 @@ pub mod node_service_client { pub async fn r_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RUnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RUnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RUnLock")); @@ -1202,13 +1526,22 @@ pub mod node_service_client { pub async fn force_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ForceUnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ForceUnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ForceUnLock")); @@ -1217,13 +1550,22 @@ pub mod node_service_client { pub async fn refresh( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Refresh"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Refresh", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Refresh")); @@ -1233,7 +1575,13 @@ pub mod node_service_client { } /// Generated server implementations. pub mod node_service_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; /// Generated trait containing gRPC methods that should be implemented for use with NodeServiceServer. #[async_trait] @@ -1246,19 +1594,31 @@ pub mod node_service_server { async fn list_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn get_bucket_info( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_all( &self, request: tonic::Request, @@ -1266,7 +1626,10 @@ pub mod node_service_server { async fn write_all( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete( &self, request: tonic::Request, @@ -1274,33 +1637,52 @@ pub mod node_service_server { async fn verify_file( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn check_parts( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn rename_part( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn rename_file( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn write( &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the WriteStream method. - type WriteStreamStream: tonic::codegen::tokio_stream::Stream> + type WriteStreamStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + 'static; async fn write_stream( &self, request: tonic::Request>, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Server streaming response type for the ReadAt method. - type ReadAtStream: tonic::codegen::tokio_stream::Stream> + type ReadAtStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + 'static; /// rpc Append(AppendRequest) returns (AppendResponse) {}; @@ -1319,39 +1701,66 @@ pub mod node_service_server { async fn rename_data( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_volumes( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn list_volumes( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn stat_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_paths( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn update_metadata( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn write_metadata( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_version( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_xl( &self, request: tonic::Request, @@ -1359,47 +1768,80 @@ pub mod node_service_server { async fn delete_version( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_versions( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_multiple( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn disk_info( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn r_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn r_un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn force_un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn refresh( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct NodeServiceServer { @@ -1422,7 +1864,10 @@ pub mod node_service_server { max_encoding_message_size: None, } } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService where F: tonic::service::Interceptor, { @@ -1466,7 +1911,10 @@ pub mod node_service_server { type Response = http::Response; type Error = std::convert::Infallible; type Future = BoxFuture; - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: http::Request) -> Self::Future { @@ -1474,12 +1922,21 @@ pub mod node_service_server { "/node_service.NodeService/Ping" => { #[allow(non_camel_case_types)] struct PingSvc(pub Arc); - impl tonic::server::UnaryService for PingSvc { + impl tonic::server::UnaryService + for PingSvc { type Response = super::PingResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::ping(&inner, request).await }; + let fut = async move { + ::ping(&inner, request).await + }; Box::pin(fut) } } @@ -1492,8 +1949,14 @@ pub mod node_service_server { let method = PingSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1502,12 +1965,23 @@ pub mod node_service_server { "/node_service.NodeService/ListBucket" => { #[allow(non_camel_case_types)] struct ListBucketSvc(pub Arc); - impl tonic::server::UnaryService for ListBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListBucketSvc { type Response = super::ListBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_bucket(&inner, request).await }; + let fut = async move { + ::list_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1520,8 +1994,14 @@ pub mod node_service_server { let method = ListBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1530,12 +2010,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeBucket" => { #[allow(non_camel_case_types)] struct MakeBucketSvc(pub Arc); - impl tonic::server::UnaryService for MakeBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeBucketSvc { type Response = super::MakeBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_bucket(&inner, request).await }; + let fut = async move { + ::make_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1548,8 +2039,14 @@ pub mod node_service_server { let method = MakeBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1558,12 +2055,23 @@ pub mod node_service_server { "/node_service.NodeService/GetBucketInfo" => { #[allow(non_camel_case_types)] struct GetBucketInfoSvc(pub Arc); - impl tonic::server::UnaryService for GetBucketInfoSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for GetBucketInfoSvc { type Response = super::GetBucketInfoResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::get_bucket_info(&inner, request).await }; + let fut = async move { + ::get_bucket_info(&inner, request).await + }; Box::pin(fut) } } @@ -1576,8 +2084,14 @@ pub mod node_service_server { let method = GetBucketInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1586,12 +2100,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteBucket" => { #[allow(non_camel_case_types)] struct DeleteBucketSvc(pub Arc); - impl tonic::server::UnaryService for DeleteBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteBucketSvc { type Response = super::DeleteBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_bucket(&inner, request).await }; + let fut = async move { + ::delete_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1604,8 +2129,14 @@ pub mod node_service_server { let method = DeleteBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1614,12 +2145,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadAll" => { #[allow(non_camel_case_types)] struct ReadAllSvc(pub Arc); - impl tonic::server::UnaryService for ReadAllSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadAllSvc { type Response = super::ReadAllResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_all(&inner, request).await }; + let fut = async move { + ::read_all(&inner, request).await + }; Box::pin(fut) } } @@ -1632,8 +2174,14 @@ pub mod node_service_server { let method = ReadAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1642,12 +2190,23 @@ pub mod node_service_server { "/node_service.NodeService/WriteAll" => { #[allow(non_camel_case_types)] struct WriteAllSvc(pub Arc); - impl tonic::server::UnaryService for WriteAllSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WriteAllSvc { type Response = super::WriteAllResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_all(&inner, request).await }; + let fut = async move { + ::write_all(&inner, request).await + }; Box::pin(fut) } } @@ -1660,8 +2219,14 @@ pub mod node_service_server { let method = WriteAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1670,12 +2235,23 @@ pub mod node_service_server { "/node_service.NodeService/Delete" => { #[allow(non_camel_case_types)] struct DeleteSvc(pub Arc); - impl tonic::server::UnaryService for DeleteSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteSvc { type Response = super::DeleteResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete(&inner, request).await }; + let fut = async move { + ::delete(&inner, request).await + }; Box::pin(fut) } } @@ -1688,8 +2264,14 @@ pub mod node_service_server { let method = DeleteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1698,12 +2280,23 @@ pub mod node_service_server { "/node_service.NodeService/VerifyFile" => { #[allow(non_camel_case_types)] struct VerifyFileSvc(pub Arc); - impl tonic::server::UnaryService for VerifyFileSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for VerifyFileSvc { type Response = super::VerifyFileResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::verify_file(&inner, request).await }; + let fut = async move { + ::verify_file(&inner, request).await + }; Box::pin(fut) } } @@ -1716,8 +2309,14 @@ pub mod node_service_server { let method = VerifyFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1726,12 +2325,23 @@ pub mod node_service_server { "/node_service.NodeService/CheckParts" => { #[allow(non_camel_case_types)] struct CheckPartsSvc(pub Arc); - impl tonic::server::UnaryService for CheckPartsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for CheckPartsSvc { type Response = super::CheckPartsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::check_parts(&inner, request).await }; + let fut = async move { + ::check_parts(&inner, request).await + }; Box::pin(fut) } } @@ -1744,8 +2354,14 @@ pub mod node_service_server { let method = CheckPartsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1754,12 +2370,23 @@ pub mod node_service_server { "/node_service.NodeService/RenamePart" => { #[allow(non_camel_case_types)] struct RenamePartSvc(pub Arc); - impl tonic::server::UnaryService for RenamePartSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenamePartSvc { type Response = super::RenamePartResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_part(&inner, request).await }; + let fut = async move { + ::rename_part(&inner, request).await + }; Box::pin(fut) } } @@ -1772,8 +2399,14 @@ pub mod node_service_server { let method = RenamePartSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1782,12 +2415,23 @@ pub mod node_service_server { "/node_service.NodeService/RenameFile" => { #[allow(non_camel_case_types)] struct RenameFileSvc(pub Arc); - impl tonic::server::UnaryService for RenameFileSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenameFileSvc { type Response = super::RenameFileResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_file(&inner, request).await }; + let fut = async move { + ::rename_file(&inner, request).await + }; Box::pin(fut) } } @@ -1800,8 +2444,14 @@ pub mod node_service_server { let method = RenameFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1810,12 +2460,21 @@ pub mod node_service_server { "/node_service.NodeService/Write" => { #[allow(non_camel_case_types)] struct WriteSvc(pub Arc); - impl tonic::server::UnaryService for WriteSvc { + impl tonic::server::UnaryService + for WriteSvc { type Response = super::WriteResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write(&inner, request).await }; + let fut = async move { + ::write(&inner, request).await + }; Box::pin(fut) } } @@ -1828,8 +2487,14 @@ pub mod node_service_server { let method = WriteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1838,13 +2503,26 @@ pub mod node_service_server { "/node_service.NodeService/WriteStream" => { #[allow(non_camel_case_types)] struct WriteStreamSvc(pub Arc); - impl tonic::server::StreamingService for WriteStreamSvc { + impl< + T: NodeService, + > tonic::server::StreamingService + for WriteStreamSvc { type Response = super::WriteResponse; type ResponseStream = T::WriteStreamStream; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request>) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_stream(&inner, request).await }; + let fut = async move { + ::write_stream(&inner, request).await + }; Box::pin(fut) } } @@ -1857,8 +2535,14 @@ pub mod node_service_server { let method = WriteStreamSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -1867,13 +2551,26 @@ pub mod node_service_server { "/node_service.NodeService/ReadAt" => { #[allow(non_camel_case_types)] struct ReadAtSvc(pub Arc); - impl tonic::server::StreamingService for ReadAtSvc { + impl< + T: NodeService, + > tonic::server::StreamingService + for ReadAtSvc { type Response = super::ReadAtResponse; type ResponseStream = T::ReadAtStream; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request>) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_at(&inner, request).await }; + let fut = async move { + ::read_at(&inner, request).await + }; Box::pin(fut) } } @@ -1886,8 +2583,14 @@ pub mod node_service_server { let method = ReadAtSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -1896,12 +2599,23 @@ pub mod node_service_server { "/node_service.NodeService/ListDir" => { #[allow(non_camel_case_types)] struct ListDirSvc(pub Arc); - impl tonic::server::UnaryService for ListDirSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListDirSvc { type Response = super::ListDirResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_dir(&inner, request).await }; + let fut = async move { + ::list_dir(&inner, request).await + }; Box::pin(fut) } } @@ -1914,8 +2628,14 @@ pub mod node_service_server { let method = ListDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1924,12 +2644,23 @@ pub mod node_service_server { "/node_service.NodeService/WalkDir" => { #[allow(non_camel_case_types)] struct WalkDirSvc(pub Arc); - impl tonic::server::UnaryService for WalkDirSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WalkDirSvc { type Response = super::WalkDirResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::walk_dir(&inner, request).await }; + let fut = async move { + ::walk_dir(&inner, request).await + }; Box::pin(fut) } } @@ -1942,8 +2673,14 @@ pub mod node_service_server { let method = WalkDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1952,12 +2689,23 @@ pub mod node_service_server { "/node_service.NodeService/RenameData" => { #[allow(non_camel_case_types)] struct RenameDataSvc(pub Arc); - impl tonic::server::UnaryService for RenameDataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenameDataSvc { type Response = super::RenameDataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_data(&inner, request).await }; + let fut = async move { + ::rename_data(&inner, request).await + }; Box::pin(fut) } } @@ -1970,8 +2718,14 @@ pub mod node_service_server { let method = RenameDataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1980,12 +2734,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolumes" => { #[allow(non_camel_case_types)] struct MakeVolumesSvc(pub Arc); - impl tonic::server::UnaryService for MakeVolumesSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeVolumesSvc { type Response = super::MakeVolumesResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_volumes(&inner, request).await }; + let fut = async move { + ::make_volumes(&inner, request).await + }; Box::pin(fut) } } @@ -1998,8 +2763,14 @@ pub mod node_service_server { let method = MakeVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2008,12 +2779,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolume" => { #[allow(non_camel_case_types)] struct MakeVolumeSvc(pub Arc); - impl tonic::server::UnaryService for MakeVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeVolumeSvc { type Response = super::MakeVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_volume(&inner, request).await }; + let fut = async move { + ::make_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2026,8 +2808,14 @@ pub mod node_service_server { let method = MakeVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2036,12 +2824,23 @@ pub mod node_service_server { "/node_service.NodeService/ListVolumes" => { #[allow(non_camel_case_types)] struct ListVolumesSvc(pub Arc); - impl tonic::server::UnaryService for ListVolumesSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListVolumesSvc { type Response = super::ListVolumesResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_volumes(&inner, request).await }; + let fut = async move { + ::list_volumes(&inner, request).await + }; Box::pin(fut) } } @@ -2054,8 +2853,14 @@ pub mod node_service_server { let method = ListVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2064,12 +2869,23 @@ pub mod node_service_server { "/node_service.NodeService/StatVolume" => { #[allow(non_camel_case_types)] struct StatVolumeSvc(pub Arc); - impl tonic::server::UnaryService for StatVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for StatVolumeSvc { type Response = super::StatVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::stat_volume(&inner, request).await }; + let fut = async move { + ::stat_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2082,8 +2898,14 @@ pub mod node_service_server { let method = StatVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2092,12 +2914,23 @@ pub mod node_service_server { "/node_service.NodeService/DeletePaths" => { #[allow(non_camel_case_types)] struct DeletePathsSvc(pub Arc); - impl tonic::server::UnaryService for DeletePathsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeletePathsSvc { type Response = super::DeletePathsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_paths(&inner, request).await }; + let fut = async move { + ::delete_paths(&inner, request).await + }; Box::pin(fut) } } @@ -2110,8 +2943,14 @@ pub mod node_service_server { let method = DeletePathsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2120,12 +2959,23 @@ pub mod node_service_server { "/node_service.NodeService/UpdateMetadata" => { #[allow(non_camel_case_types)] struct UpdateMetadataSvc(pub Arc); - impl tonic::server::UnaryService for UpdateMetadataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for UpdateMetadataSvc { type Response = super::UpdateMetadataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::update_metadata(&inner, request).await }; + let fut = async move { + ::update_metadata(&inner, request).await + }; Box::pin(fut) } } @@ -2138,8 +2988,14 @@ pub mod node_service_server { let method = UpdateMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2148,12 +3004,23 @@ pub mod node_service_server { "/node_service.NodeService/WriteMetadata" => { #[allow(non_camel_case_types)] struct WriteMetadataSvc(pub Arc); - impl tonic::server::UnaryService for WriteMetadataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WriteMetadataSvc { type Response = super::WriteMetadataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_metadata(&inner, request).await }; + let fut = async move { + ::write_metadata(&inner, request).await + }; Box::pin(fut) } } @@ -2166,8 +3033,14 @@ pub mod node_service_server { let method = WriteMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2176,12 +3049,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadVersion" => { #[allow(non_camel_case_types)] struct ReadVersionSvc(pub Arc); - impl tonic::server::UnaryService for ReadVersionSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadVersionSvc { type Response = super::ReadVersionResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_version(&inner, request).await }; + let fut = async move { + ::read_version(&inner, request).await + }; Box::pin(fut) } } @@ -2194,8 +3078,14 @@ pub mod node_service_server { let method = ReadVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2204,12 +3094,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadXL" => { #[allow(non_camel_case_types)] struct ReadXLSvc(pub Arc); - impl tonic::server::UnaryService for ReadXLSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadXLSvc { type Response = super::ReadXlResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_xl(&inner, request).await }; + let fut = async move { + ::read_xl(&inner, request).await + }; Box::pin(fut) } } @@ -2222,8 +3123,14 @@ pub mod node_service_server { let method = ReadXLSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2232,12 +3139,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersion" => { #[allow(non_camel_case_types)] struct DeleteVersionSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVersionSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVersionSvc { type Response = super::DeleteVersionResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_version(&inner, request).await }; + let fut = async move { + ::delete_version(&inner, request).await + }; Box::pin(fut) } } @@ -2250,8 +3168,14 @@ pub mod node_service_server { let method = DeleteVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2260,12 +3184,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersions" => { #[allow(non_camel_case_types)] struct DeleteVersionsSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVersionsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVersionsSvc { type Response = super::DeleteVersionsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_versions(&inner, request).await }; + let fut = async move { + ::delete_versions(&inner, request).await + }; Box::pin(fut) } } @@ -2278,8 +3213,14 @@ pub mod node_service_server { let method = DeleteVersionsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2288,12 +3229,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadMultiple" => { #[allow(non_camel_case_types)] struct ReadMultipleSvc(pub Arc); - impl tonic::server::UnaryService for ReadMultipleSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadMultipleSvc { type Response = super::ReadMultipleResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_multiple(&inner, request).await }; + let fut = async move { + ::read_multiple(&inner, request).await + }; Box::pin(fut) } } @@ -2306,8 +3258,14 @@ pub mod node_service_server { let method = ReadMultipleSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2316,12 +3274,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVolume" => { #[allow(non_camel_case_types)] struct DeleteVolumeSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVolumeSvc { type Response = super::DeleteVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_volume(&inner, request).await }; + let fut = async move { + ::delete_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2334,8 +3303,14 @@ pub mod node_service_server { let method = DeleteVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2344,12 +3319,23 @@ pub mod node_service_server { "/node_service.NodeService/DiskInfo" => { #[allow(non_camel_case_types)] struct DiskInfoSvc(pub Arc); - impl tonic::server::UnaryService for DiskInfoSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DiskInfoSvc { type Response = super::DiskInfoResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::disk_info(&inner, request).await }; + let fut = async move { + ::disk_info(&inner, request).await + }; Box::pin(fut) } } @@ -2362,8 +3348,14 @@ pub mod node_service_server { let method = DiskInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2372,12 +3364,23 @@ pub mod node_service_server { "/node_service.NodeService/Lock" => { #[allow(non_camel_case_types)] struct LockSvc(pub Arc); - impl tonic::server::UnaryService for LockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for LockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::lock(&inner, request).await }; + let fut = async move { + ::lock(&inner, request).await + }; Box::pin(fut) } } @@ -2390,8 +3393,14 @@ pub mod node_service_server { let method = LockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2400,12 +3409,23 @@ pub mod node_service_server { "/node_service.NodeService/UnLock" => { #[allow(non_camel_case_types)] struct UnLockSvc(pub Arc); - impl tonic::server::UnaryService for UnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for UnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::un_lock(&inner, request).await }; + let fut = async move { + ::un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2418,8 +3438,14 @@ pub mod node_service_server { let method = UnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2428,12 +3454,23 @@ pub mod node_service_server { "/node_service.NodeService/RLock" => { #[allow(non_camel_case_types)] struct RLockSvc(pub Arc); - impl tonic::server::UnaryService for RLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::r_lock(&inner, request).await }; + let fut = async move { + ::r_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2446,8 +3483,14 @@ pub mod node_service_server { let method = RLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2456,12 +3499,23 @@ pub mod node_service_server { "/node_service.NodeService/RUnLock" => { #[allow(non_camel_case_types)] struct RUnLockSvc(pub Arc); - impl tonic::server::UnaryService for RUnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::r_un_lock(&inner, request).await }; + let fut = async move { + ::r_un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2474,8 +3528,14 @@ pub mod node_service_server { let method = RUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2484,12 +3544,23 @@ pub mod node_service_server { "/node_service.NodeService/ForceUnLock" => { #[allow(non_camel_case_types)] struct ForceUnLockSvc(pub Arc); - impl tonic::server::UnaryService for ForceUnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ForceUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::force_un_lock(&inner, request).await }; + let fut = async move { + ::force_un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2502,8 +3573,14 @@ pub mod node_service_server { let method = ForceUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2512,12 +3589,23 @@ pub mod node_service_server { "/node_service.NodeService/Refresh" => { #[allow(non_camel_case_types)] struct RefreshSvc(pub Arc); - impl tonic::server::UnaryService for RefreshSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RefreshSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::refresh(&inner, request).await }; + let fut = async move { + ::refresh(&inner, request).await + }; Box::pin(fut) } } @@ -2530,20 +3618,36 @@ pub mod node_service_server { let method = RefreshSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } - _ => Box::pin(async move { - let mut response = http::Response::new(empty_body()); - let headers = response.headers_mut(); - headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into()); - headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE); - Ok(response) - }), + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } } } } diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index 75ebc2642..d70c04a12 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -19,15 +19,17 @@ use crate::disk::os::{check_path_length, is_empty_dir}; use crate::disk::{LocalFileReader, LocalFileWriter, STORAGE_FORMAT_FILE}; use crate::error::{Error, Result}; use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold}; -use crate::heal::data_scanner::has_active_rules; -use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry}; +use crate::heal::data_scanner::{has_active_rules, scan_data_folder, ScannerItem, SizeSummary}; +use crate::heal::data_scanner_metric::{globalScannerMetrics, ScannerMetric, ScannerMetrics}; +use crate::heal::data_usage_cache::{self, DataUsageCache, DataUsageEntry}; +use crate::heal::error::{ERR_IGNORE_FILE_CONTRIB, ERR_SKIP_FILE}; use crate::heal::heal_commands::HealScanMode; use crate::new_object_layer_fn; 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::store_api::{BitrotAlgorithm, StorageAPI}; 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, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR}; @@ -39,13 +41,13 @@ use crate::{ use common::defer; use path_absolutize::Absolutize; use s3s::dto::{ReplicationConfiguration, ReplicationRuleStatus}; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::io::Cursor; use std::os::unix::fs::MetadataExt; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; -use std::time::Duration; +use std::time::{Duration, SystemTime}; use std::{ fs::Metadata, path::{Path, PathBuf}, @@ -1878,7 +1880,7 @@ impl DiskAPI for LocalDisk { } async fn ns_scanner( - &self, + self: Arc, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, @@ -1904,7 +1906,112 @@ impl DiskAPI for LocalDisk { Some(s) => s, None => return Err(Error::msg("errServerNotInitialized")), }; - todo!() + let loc = self.get_disk_location(); + let disks = store.get_disks(loc.pool_idx.unwrap(), loc.disk_idx.unwrap()).await?; + let disk = self.clone(); + let disk_clone = disk.clone(); + let mut cache = cache.clone(); + cache.info.updates = Some(updates.clone()); + let mut data_usage_info = scan_data_folder( + &disks, + disk, + &cache, + Box::new(move |item: &ScannerItem| { + let mut item = item.clone(); + let disk = disk_clone.clone(); + Box::pin(async move { + if item.path.ends_with(&format!("{}{}", SLASH_SEPARATOR, STORAGE_FORMAT_FILE)) { + return Err(Error::from_string(ERR_SKIP_FILE)); + } + let stop_fn = ScannerMetrics::log(ScannerMetric::ScanObject); + let mut res = HashMap::new(); + let done_sz = ScannerMetrics::time_size(ScannerMetric::ReadMetadata); + let buf = match disk.read_metadata(item.path.clone()).await { + Ok(buf) => buf, + Err(err) => { + res.insert("err".to_string(), err.to_string()); + stop_fn(&res).await; + return Err(Error::from_string(ERR_SKIP_FILE)); + } + }; + done_sz(buf.len() as u64).await; + res.insert("metasize".to_string(), buf.len().to_string()); + item.transform_meda_dir(); + let meta_cache = MetaCacheEntry { + name: item.object_path().to_string_lossy().to_string(), + metadata: buf, + ..Default::default() + }; + let fivs = match meta_cache.file_info_versions(&item.bucket) { + Ok(fivs) => fivs, + Err(err) => { + res.insert("err".to_string(), err.to_string()); + stop_fn(&res).await; + return Err(Error::from_string(ERR_SKIP_FILE)); + } + }; + let mut size_s = SizeSummary::default(); + let done = ScannerMetrics::time(ScannerMetric::ApplyAll); + let obj_infos = match item.apply_versions_actions(&fivs.versions).await { + Ok(obj_infos) => obj_infos, + Err(err) => { + res.insert("err".to_string(), err.to_string()); + stop_fn(&res).await; + return Err(Error::from_string(ERR_SKIP_FILE)); + } + }; + + let versioned = false; + let mut obj_deleted = false; + for info in obj_infos.iter() { + let done = ScannerMetrics::time(ScannerMetric::ApplyVersion); + let mut sz = 0; + (obj_deleted, sz) = item.apply_actions(&info, &size_s).await; + done().await; + + if obj_deleted { + break; + } + + let actual_sz = match info.get_actual_size() { + Ok(size) => size, + Err(_) => continue, + }; + + if info.delete_marker { + size_s.delete_markers += 1; + } + + if info.version_id.is_some() && sz == actual_sz { + size_s.versions += 1; + } + + size_s.total_size += sz; + + if info.delete_marker { + continue; + } + } + + for frer_version in fivs.free_versions.iter() { + let _obj_info = frer_version.to_object_info(&item.bucket, &item.object_path().to_string_lossy(), versioned); + let done = ScannerMetrics::time(ScannerMetric::TierObjSweep); + done().await; + } + + // todo: global trace + if obj_deleted { + return Err(Error::from_string(ERR_IGNORE_FILE_CONTRIB)); + } + done().await; + Ok(size_s) + }) + }), + scan_mode, + ) + .await?; + data_usage_info.info.last_update = Some(SystemTime::now()); + Ok(data_usage_info) } } diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index a9056d52b..880ffd59e 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -16,7 +16,7 @@ const STORAGE_FORMAT_FILE: &str = "xl.meta"; use crate::{ erasure::Writer, error::{Error, Result}, - file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion}, + file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion, FileMetaVersion}, heal::{ data_usage_cache::{DataUsageCache, DataUsageEntry}, heal_commands::HealScanMode, @@ -344,14 +344,14 @@ impl DiskAPI for Disk { } async fn ns_scanner( - &self, + self: Arc, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, ) -> Result { - match self { - Disk::Local(local_disk) => local_disk.ns_scanner(cache, updates, scan_mode).await, - Disk::Remote(remote_disk) => remote_disk.ns_scanner(cache, updates, scan_mode).await, + match &*self { + Disk::Local(local_disk) => Arc::new(local_disk).ns_scanner(cache, updates, scan_mode).await, + Disk::Remote(remote_disk) => Arc::new(remote_disk).ns_scanner(cache, updates, scan_mode).await, } } } @@ -453,7 +453,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static { async fn read_all(&self, volume: &str, path: &str) -> Result>; async fn disk_info(&self, opts: &DiskInfoOptions) -> Result; async fn ns_scanner( - &self, + self: Arc, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index 4eba96bf2..fe7df93b3 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::{path::PathBuf, sync::Arc}; use futures::lock::Mutex; use protos::{ @@ -736,7 +736,7 @@ impl DiskAPI for RemoteDisk { } async fn ns_scanner( - &self, + self: Arc, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs index b9d82f2e5..0ad14e232 100644 --- a/ecstore/src/heal/data_scanner.rs +++ b/ecstore/src/heal/data_scanner.rs @@ -12,7 +12,7 @@ use std::{ time::{Duration, SystemTime, UNIX_EPOCH}, }; -use byteorder::{LittleEndian, ReadBytesExt}; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use lazy_static::lazy_static; use rand::Rng; use rmp_serde::{Deserializer, Serializer}; @@ -29,12 +29,11 @@ use tokio::{ use tracing::{error, info}; use super::{ - data_scanner_metric::globalScannerMetrics, + data_scanner_metric::{globalScannerMetrics, ScannerMetric, ScannerMetrics}, data_usage::{store_data_usage_in_backend, DATA_USAGE_BLOOM_NAME_PATH}, data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash}, heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}, }; -use crate::disk::DiskAPI; use crate::heal::data_scanner_metric::current_path_updater; use crate::heal::data_usage::DATA_USAGE_ROOT; use crate::{ @@ -58,6 +57,10 @@ use crate::{ store::{ECStore, ListPathOptions}, utils::path::{path_join, path_to_bucket_object, path_to_bucket_object_with_base_path, SLASH_SEPARATOR}, }; +use crate::{ + disk::DiskAPI, + store_api::{FileInfo, ObjectInfo}, +}; const DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16; // Visit all folders every n cycles. @@ -132,6 +135,7 @@ async fn run_data_scanner() { } loop { + let stop_fn = ScannerMetrics::log(ScannerMetric::ScanCycle); cycle_info.current = cycle_info.next; cycle_info.started = SystemTime::now(); { @@ -155,6 +159,26 @@ async fn run_data_scanner() { tokio::spawn(async { store_data_usage_in_backend(rx).await; }); + let mut res = HashMap::new(); + res.insert("cycle".to_string(), cycle_info.current.to_string()); + match store.ns_scanner(tx, cycle_info.current as usize, scan_mode).await { + Ok(_) => { + cycle_info.next += 1; + cycle_info.current = 0; + cycle_info.cycle_completed.push(SystemTime::now()); + if cycle_info.cycle_completed.len() > DATA_USAGE_UPDATE_DIR_CYCLES as usize { + cycle_info.cycle_completed = cycle_info.cycle_completed[cycle_info.cycle_completed.len() - DATA_USAGE_UPDATE_DIR_CYCLES as usize..].to_vec(); + } + globalScannerMetrics.write().await.set_cycle(Some(cycle_info.clone())).await; + let mut tmp = Vec::new(); + tmp.write_u64::(cycle_info.next).unwrap(); + let _ = save_config(store, &DATA_USAGE_BLOOM_NAME_PATH, &tmp).await; + }, + Err(err) => { + res.insert("error".to_string(), err.to_string()); + }, + } + stop_fn(&res).await; sleep(Duration::from_secs(SCANNER_CYCLE.load(std::sync::atomic::Ordering::SeqCst))).await; } } @@ -241,7 +265,7 @@ impl Default for CurrentScannerCycle { } impl CurrentScannerCycle { - pub fn marshal_msg(&self) -> Result> { + pub fn marshal_msg(&self, buf: &[u8]) -> Result> { let len: u32 = 4; let mut wr = Vec::new(); @@ -267,8 +291,9 @@ impl CurrentScannerCycle { .serialize(&mut Serializer::new(&mut buf)) .expect("Serialization failed"); rmp::encode::write_bin(&mut wr, &buf)?; - - Ok(wr) + let mut result = buf.to_vec(); + result.extend(wr.iter()); + Ok(result) } #[tracing::instrument] @@ -295,10 +320,10 @@ impl CurrentScannerCycle { self.current = u; } - "next" => { - let u: u64 = rmp::decode::read_int(&mut cur)?; - self.next = u; - } + // "next" => { + // let u: u64 = rmp::decode::read_int(&mut cur)?; + // self.next = u; + // } "started" => { let u: u64 = rmp::decode::read_int(&mut cur)?; let started = timestamp_to_system_time(u); @@ -329,22 +354,23 @@ fn timestamp_to_system_time(timestamp: u64) -> SystemTime { UNIX_EPOCH + std::time::Duration::new(timestamp, 0) } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] struct Heal { enabled: bool, bitrot: bool, } +#[derive(Clone)] pub struct ScannerItem { - path: String, - bucket: String, - prefix: String, - object_name: String, - replication: Option, + pub path: String, + pub bucket: String, + pub prefix: String, + pub object_name: String, + pub replication: Option, // todo: lifecycle // typ: fs::Permissions, - heal: Heal, - debug: bool, + pub heal: Heal, + pub debug: bool, } impl ScannerItem { @@ -365,6 +391,43 @@ impl ScannerItem { pub fn object_path(&self) -> PathBuf { path_join(&[PathBuf::from(self.prefix.clone()), PathBuf::from(self.object_name.clone())]) } + + pub async fn apply_versions_actions(&self, fivs: &[FileInfo]) -> Result> { + let obj_infos = self.apply_newer_noncurrent_version_limit(fivs).await?; + if obj_infos.len() >= SCANNER_EXCESS_OBJECT_VERSIONS.load(Ordering::SeqCst).try_into().unwrap() { + // todo + } + + let mut cumulative_size = 0; + for obj_info in obj_infos.iter() { + cumulative_size += obj_info.size; + } + + if cumulative_size >= SCANNER_EXCESS_OBJECT_VERSIONS_TOTAL_SIZE.load(Ordering::SeqCst).try_into().unwrap() { + //todo + } + + Ok(obj_infos) + } + + pub async fn apply_newer_noncurrent_version_limit(&self, fivs: &[FileInfo]) -> Result> { + let done = ScannerMetrics::time(ScannerMetric::ApplyNonCurrent); + let mut object_infos = Vec::new(); + for info in fivs.iter() { + object_infos.push(info.to_object_info(&self.bucket, &self.object_path().to_string_lossy(), false)); + } + done().await; + + Ok(object_infos) + } + + pub async fn apply_actions(&self, oi: &ObjectInfo, size_s: &SizeSummary) -> (bool, usize) { + let done = ScannerMetrics::time(ScannerMetric::Ilm); + //todo: lifecycle + done().await; + + (false, 0) + } } #[derive(Debug, Default)] @@ -420,7 +483,7 @@ struct FolderScanner { last_update: SystemTime, update_current_path: UpdateCurrentPathFn, skip_heal: AtomicBool, - drive: DiskStore, + drive: LocalDrive, } impl FolderScanner { @@ -951,9 +1014,10 @@ pub fn has_active_rules(config: &ReplicationConfiguration, prefix: &str, recursi false } +pub type LocalDrive = Arc; pub async fn scan_data_folder( disks: &[Option], - drive: &DiskStore, + drive: LocalDrive, cache: &DataUsageCache, get_size_fn: GetSizeFn, heal_scan_mode: HealScanMode, @@ -964,6 +1028,11 @@ pub async fn scan_data_folder( let base_path = drive.to_string(); let (update_path, close_disk) = current_path_updater(&base_path, &cache.info.name); + let skip_heal = if *GLOBAL_IsErasure.read().await || cache.info.skip_healing { + AtomicBool::new(true) + } else { + AtomicBool::new(false) + }; let mut s = FolderScanner { root: base_path, get_size: get_size_fn, @@ -978,11 +1047,7 @@ pub async fn scan_data_folder( update_current_path: update_path, disks: disks.to_vec(), disks_quorum: disks.len() / 2, - skip_heal: if *GLOBAL_IsErasure.read().await || cache.info.skip_healing { - AtomicBool::new(true) - } else { - AtomicBool::new(false) - }, + skip_heal, drive: drive.clone(), }; @@ -1002,7 +1067,7 @@ pub async fn scan_data_folder( } s.new_cache .force_compact(DATA_SCANNER_COMPACT_AT_CHILDREN.try_into().unwrap()); - s.new_cache.info.last_update = SystemTime::now(); + s.new_cache.info.last_update = Some(SystemTime::now()); s.new_cache.info.next_cycle = cache.info.next_cycle; close_disk().await; Ok(s.new_cache) diff --git a/ecstore/src/heal/data_scanner_metric.rs b/ecstore/src/heal/data_scanner_metric.rs index 4947aa812..325beaa5c 100644 --- a/ecstore/src/heal/data_scanner_metric.rs +++ b/ecstore/src/heal/data_scanner_metric.rs @@ -1,6 +1,10 @@ +use common::last_minute::{AccElem, LastMinuteLatency}; use lazy_static::lazy_static; use std::future::Future; use std::pin::Pin; +use std::sync::atomic::AtomicU64; +use std::sync::Once; +use std::time::{Duration, UNIX_EPOCH}; use std::{ collections::HashMap, sync::{ @@ -53,8 +57,75 @@ pub enum ScannerMetric { Last, } +static INIT: Once = Once::new(); + +#[derive(Default)] +pub struct LockedLastMinuteLatency { + cached_sec: AtomicU64, + cached: AccElem, + mu: RwLock, + latency: LastMinuteLatency, +} + +impl Clone for LockedLastMinuteLatency { + fn clone(&self) -> Self { + Self { + cached_sec: AtomicU64::new(0), + cached: self.cached.clone(), + mu: RwLock::new(true), + latency: self.latency.clone(), + } + } +} + +impl LockedLastMinuteLatency { + pub fn add(&mut self, value: &Duration) { + self.add_size(value, 0); + } + + pub async fn add_size(&mut self, value: &Duration, sz: u64) { + let t = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); + INIT.call_once(|| { + self.cached = AccElem::default(); + self.cached_sec.store(t, Ordering::SeqCst); + }); + let last_t = self.cached_sec.load(Ordering::SeqCst); + if last_t != t + && self + .cached_sec + .compare_exchange(last_t, t, Ordering::SeqCst, Ordering::SeqCst) + .is_ok() + { + let old = self.cached.clone(); + self.cached = AccElem::default(); + let mut a = AccElem::default(); + a.size = old.size; + a.total = old.total; + a.n = old.n; + self.mu.write().await; + self.latency.add_all(t - 1, &a); + } + self.cached.n += 1; + self.cached.total += value.as_secs(); + self.cached.size != sz; + } + + pub async fn total(&mut self) -> AccElem { + self.mu.read().await; + self.latency.get_total() + } +} + +pub type LogFn = Arc) -> Pin + Send>> + Send + Sync + 'static>; +pub type TimeSizeFn = Arc Pin + Send>> + Send + Sync + 'static>; +pub type TimeFn = Arc Pin + Send>> + Send + Sync + 'static>; + pub struct ScannerMetrics { operations: Vec, + latency: Vec, cycle_info: RwLock>, current_paths: HashMap, } @@ -63,23 +134,63 @@ impl ScannerMetrics { pub fn new() -> Self { Self { operations: (0..ScannerMetric::Last as usize).map(|_| AtomicU32::new(0)).collect(), + latency: vec![LockedLastMinuteLatency::default(); ScannerMetric::LastRealtime as usize], cycle_info: RwLock::new(None), current_paths: HashMap::new(), } } - pub fn log(&mut self, s: ScannerMetric, _paths: &[String], _custom: &HashMap, _start_time: SystemTime) { - // let duration = start_time.duration_since(start_time); - self.operations[s.clone() as usize].fetch_add(1, Ordering::SeqCst); - // Dodo - } - pub async fn set_cycle(&mut self, c: Option) { *self.cycle_info.write().await = c; } + + pub fn log(s: ScannerMetric) -> LogFn { + let start = SystemTime::now(); + let s_clone = s as usize; + Arc::new(move |custom: &HashMap| { + Box::pin(async move { + let duration = SystemTime::now().duration_since(start).unwrap_or(Duration::from_secs(0)); + let mut sm_w = globalScannerMetrics.write().await; + sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); + if s_clone < ScannerMetric::LastRealtime as usize { + sm_w.latency[s_clone].add(&duration); + } + }) + }) + } + + pub fn time_size(s: ScannerMetric) -> TimeSizeFn { + let start = SystemTime::now(); + let s_clone = s as usize; + Arc::new(move |sz: u64| { + Box::pin(async move { + let duration = SystemTime::now().duration_since(start).unwrap_or(Duration::from_secs(0)); + let mut sm_w = globalScannerMetrics.write().await; + sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); + if s_clone < ScannerMetric::LastRealtime as usize { + sm_w.latency[s_clone].add_size(&duration, sz); + } + }) + }) + } + + pub fn time(s: ScannerMetric) -> TimeFn { + let start = SystemTime::now(); + let s_clone = s as usize; + Arc::new(move || { + Box::pin(async move { + let duration = SystemTime::now().duration_since(start).unwrap_or(Duration::from_secs(0)); + let mut sm_w = globalScannerMetrics.write().await; + sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); + if s_clone < ScannerMetric::LastRealtime as usize { + sm_w.latency[s_clone].add(&duration); + } + }) + }) + } } -pub type CloseDiskFn = Arc Pin + Send>> + Send + 'static>; +pub type CloseDiskFn = Arc Pin + Send>> + Send + Sync + 'static>; pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) { let disk_1 = disk.to_string(); let disk_2 = disk.to_string(); diff --git a/ecstore/src/heal/data_usage.rs b/ecstore/src/heal/data_usage.rs index 3ffa3453d..75dce2bff 100644 --- a/ecstore/src/heal/data_usage.rs +++ b/ecstore/src/heal/data_usage.rs @@ -34,13 +34,13 @@ lazy_static! { // - replica failed count #[derive(Debug, Default, Serialize, Deserialize)] pub struct BucketTargetUsageInfo { - replication_pending_size: u64, - replication_failed_size: u64, - replicated_size: u64, - replica_size: u64, - replication_pending_count: u64, - replication_failed_count: u64, - replicated_count: u64, + pub replication_pending_size: u64, + pub replication_failed_size: u64, + pub replicated_size: u64, + pub replica_size: u64, + pub replication_pending_count: u64, + pub replication_failed_count: u64, + pub replicated_count: u64, } // BucketUsageInfo - bucket usage info provides @@ -49,82 +49,63 @@ pub struct BucketTargetUsageInfo { // - object size histogram per bucket #[derive(Debug, Default, Serialize, Deserialize)] pub struct BucketUsageInfo { - size: u64, + pub size: u64, // Following five fields suffixed with V1 are here for backward compatibility // Total Size for objects that have not yet been replicated - replication_pending_size_v1: u64, + pub replication_pending_size_v1: u64, // Total size for objects that have witness one or more failures and will be retried - replication_failed_size_v1: u64, + pub replication_failed_size_v1: u64, // Total size for objects that have been replicated to destination - replicated_size_v1: u64, + pub replicated_size_v1: u64, // Total number of objects pending replication - replication_pending_count_v1: u64, + pub replication_pending_count_v1: u64, // Total number of objects that failed replication - replication_failed_count_v1: u64, + pub replication_failed_count_v1: u64, - objects_count: u64, - object_size_histogram: HashMap, - object_versions_histogram: HashMap, - versions_count: u64, - delete_markers_count: u64, - replica_size: u64, - replica_count: u64, - replication_info: HashMap, + pub objects_count: u64, + pub object_size_histogram: HashMap, + pub object_versions_histogram: HashMap, + pub versions_count: u64, + pub delete_markers_count: u64, + pub replica_size: u64, + pub replica_count: u64, + pub replication_info: HashMap, } // DataUsageInfo represents data usage stats of the underlying Object API -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct DataUsageInfo { - total_capacity: u64, - total_used_capacity: u64, - total_free_capacity: u64, + pub total_capacity: u64, + pub total_used_capacity: u64, + pub total_free_capacity: u64, // LastUpdate is the timestamp of when the data usage info was last updated. // This does not indicate a full scan. - last_update: SystemTime, + pub last_update: Option, // Objects total count across all buckets - objects_total_count: u64, + pub objects_total_count: u64, // Versions total count across all buckets - versions_total_count: u64, + pub versions_total_count: u64, // Delete markers total count across all buckets - delete_markers_total_count: u64, + pub delete_markers_total_count: u64, // Objects total size across all buckets - objects_total_size: u64, - replication_info: HashMap, + pub objects_total_size: u64, + pub replication_info: HashMap, // Total number of buckets in this cluster - buckets_count: u64, + pub buckets_count: u64, // Buckets usage info provides following information across all buckets // - total size of the bucket // - total objects in a bucket // - object size histogram per bucket - buckets_usage: HashMap, + pub buckets_usage: HashMap, // Deprecated kept here for backward compatibility reasons. - bucket_sizes: HashMap, + pub bucket_sizes: HashMap, // Todo: TierStats // TierStats contains per-tier stats of all configured remote tiers } -impl Default for DataUsageInfo { - fn default() -> Self { - Self { - total_capacity: Default::default(), - total_used_capacity: Default::default(), - total_free_capacity: Default::default(), - last_update: SystemTime::now(), - objects_total_count: Default::default(), - versions_total_count: Default::default(), - delete_markers_total_count: Default::default(), - objects_total_size: Default::default(), - replication_info: Default::default(), - buckets_count: Default::default(), - buckets_usage: Default::default(), - bucket_sizes: Default::default(), - } - } -} - pub async fn store_data_usage_in_backend(mut rx: Receiver) { let layer = new_object_layer_fn(); let lock = layer.read().await; diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs index 820bc858b..9da7b6351 100644 --- a/ecstore/src/heal/data_usage_cache.rs +++ b/ecstore/src/heal/data_usage_cache.rs @@ -4,7 +4,8 @@ use crate::disk::{BUCKET_META_PREFIX, RUSTFS_META_BUCKET}; use crate::error::{Error, Result}; use crate::new_object_layer_fn; use crate::set_disk::SetDisks; -use crate::store_api::{HTTPRangeSpec, ObjectIO, ObjectOptions}; +use crate::store_api::{BucketInfo, HTTPRangeSpec, ObjectIO, ObjectOptions}; +use bytes::Bytes; use bytesize::ByteSize; use http::HeaderMap; use path_clean::PathClean; @@ -23,7 +24,7 @@ use tokio::sync::mpsc::Sender; use tokio::time::sleep; use super::data_scanner::{SizeSummary, DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS}; -use super::data_usage::DATA_USAGE_ROOT; +use super::data_usage::{BucketTargetUsageInfo, BucketUsageInfo, DataUsageInfo, DATA_USAGE_ROOT}; // DATA_USAGE_BUCKET_LEN must be length of ObjectsHistogramIntervals pub const DATA_USAGE_BUCKET_LEN: usize = 11; @@ -152,6 +153,22 @@ impl SizeHistogram { } } } + + pub fn to_map(&self) -> HashMap { + let mut res = HashMap::new(); + let mut spl_count = 0; + for (count, oh) in self.0.iter().zip(OBJECTS_HISTOGRAM_INTERVALS.iter()) { + if ByteSize::kib(1).as_u64() == oh.start && oh.end == ByteSize::mib(1).as_u64() - 1 { + res.insert(oh.name.to_string(), spl_count); + } else if ByteSize::kib(1).as_u64() <= oh.start && oh.end <= ByteSize::mib(1).as_u64() - 1 { + spl_count += count; + res.insert(oh.name.to_string(), *count); + } else { + res.insert(oh.name.to_string(), *count); + } + } + res + } } // versionsHistogram is a histogram of number of versions in an object. @@ -173,6 +190,14 @@ impl VersionsHistogram { } } } + + pub fn to_map(&self) -> HashMap { + let mut res = HashMap::new(); + for (count, ov) in self.0.iter().zip(OBJECTS_VERSION_COUNT_INTERVALS.iter()) { + res.insert(ov.name.to_string(), *count); + } + res + } } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -319,11 +344,11 @@ pub struct DataUsageEntryInfo { pub entry: DataUsageEntry, } -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone, Default, Serialize, Deserialize)] pub struct DataUsageCacheInfo { pub name: String, pub next_cycle: u32, - pub last_update: SystemTime, + pub last_update: Option, pub skip_healing: bool, // todo: life_cycle // pub life_cycle: @@ -333,18 +358,18 @@ pub struct DataUsageCacheInfo { pub replication: Option, } -impl Default for DataUsageCacheInfo { - fn default() -> Self { - Self { - name: Default::default(), - next_cycle: Default::default(), - last_update: SystemTime::now(), - skip_healing: Default::default(), - updates: Default::default(), - replication: Default::default(), - } - } -} +// impl Default for DataUsageCacheInfo { +// fn default() -> Self { +// Self { +// name: Default::default(), +// next_cycle: Default::default(), +// last_update: SystemTime::now(), +// skip_healing: Default::default(), +// updates: Default::default(), +// replication: Default::default(), +// } +// } +// } #[derive(Clone, Default, Serialize, Deserialize)] pub struct DataUsageCache { @@ -410,8 +435,11 @@ impl DataUsageCache { }, } retries += 1; - let mut rng = rand::thread_rng(); - sleep(Duration::from_millis(rng.gen_range(0..1_000))).await; + let dur = { + let mut rng = rand::thread_rng(); + rng.gen_range(0..1_000) + }; + sleep(Duration::from_millis(dur)).await; } Ok(d) } @@ -655,6 +683,100 @@ impl DataUsageCache { n } + pub fn merge(&mut self, o: &DataUsageCache) { + let mut existing_root = self.root(); + let other_root = o.root(); + if existing_root.is_none() && other_root.is_none() { + return; + } + if other_root.is_none() { + return; + } + if existing_root.is_none() { + *self = o.clone(); + return; + } + if o.info.last_update.gt(&self.info.last_update) { + self.info.last_update = o.info.last_update; + } + + existing_root.as_mut().unwrap().merge(other_root.as_ref().unwrap()); + self.cache.insert(hash_path(&self.info.name).key(), existing_root.unwrap()); + let e_hash = self.root_hash(); + for key in other_root.as_ref().unwrap().children.iter() { + let entry = &o.cache[key]; + let flat = o.flatten(entry); + let mut existing = self.cache[key].clone(); + existing.merge(&flat); + self.replace_hashed(&DataUsageHash(key.clone()), &Some(e_hash.clone()), &existing); + } + } + + pub fn root_hash(&self) -> DataUsageHash { + hash_path(&self.info.name) + } + + pub fn root(&self) -> Option { + self.find(&self.info.name) + } + + pub fn dui(&self, path: &str, buckets: &[BucketInfo]) -> DataUsageInfo { + let e = match self.find(path) { + Some(e) => e, + None => return DataUsageInfo::default(), + }; + let flat = self.flatten(&e); + let dui = DataUsageInfo { + last_update: self.info.last_update, + objects_total_count: flat.objects as u64, + versions_total_count: flat.versions as u64, + delete_markers_total_count: flat.delete_markers as u64, + objects_total_size: flat.size as u64, + buckets_count: e.children.len() as u64, + buckets_usage: self.buckets_usage_info(buckets), + ..Default::default() + }; + dui + } + + pub fn buckets_usage_info(&self, buckets: &[BucketInfo]) -> HashMap { + let mut dst = HashMap::new(); + for bucket in buckets.iter() { + let e = match self.find(&bucket.name) { + Some(e) => e, + None => continue, + }; + let flat = self.flatten(&e); + let mut bui = BucketUsageInfo { + size: flat.size as u64, + versions_count: flat.versions as u64, + objects_count: flat.objects as u64, + delete_markers_count: flat.delete_markers as u64, + object_size_histogram: flat.obj_sizes.to_map(), + object_versions_histogram: flat.obj_versions.to_map(), + ..Default::default() + }; + if let Some(rs) = &flat.replication_stats { + bui.replica_size = rs.replica_size; + bui.replica_count = rs.replica_count; + + for (arn, stat) in rs.targets.iter() { + bui.replication_info.insert(arn.clone(), BucketTargetUsageInfo { + replication_pending_size: stat.pending_size, + replicated_size: stat.replicated_size, + replication_failed_size: stat.failed_size, + replication_pending_count: stat.pending_count, + replication_failed_count: stat.failed_count, + replicated_count: stat.replicated_count, + ..Default::default() + }); + } + } + dst.insert(bucket.name.clone(), bui); + } + dst + } + pub fn marshal_msg(&self) -> Result> { let mut buf = Vec::new(); diff --git a/ecstore/src/heal/error.rs b/ecstore/src/heal/error.rs index 1b6cd6741..ff6c90f72 100644 --- a/ecstore/src/heal/error.rs +++ b/ecstore/src/heal/error.rs @@ -1 +1,2 @@ pub const ERR_IGNORE_FILE_CONTRIB: &str = "ignore this file's contribution toward data-usage"; +pub const ERR_SKIP_FILE: &str = "skip this file"; diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index 27e663b96..3d0ddcaca 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -10,7 +10,7 @@ use crate::global::{ is_dist_erasure, is_erasure_sd, set_global_deployment_id, set_object_layer, DISK_ASSUME_UNKNOWN_SIZE, DISK_FILL_FRACTION, DISK_MIN_INODES, DISK_RESERVE_FRACTION, GLOBAL_LOCAL_DISK_MAP, GLOBAL_LOCAL_DISK_SET_DRIVES, }; -use crate::heal::data_usage::DataUsageInfo; +use crate::heal::data_usage::{DataUsageInfo, DATA_USAGE_ROOT}; use crate::heal::heal_commands::{HealOpts, HealResultItem, HealScanMode, HEAL_ITEM_METADATA}; use crate::heal::heal_ops::HealObjectFn; use crate::new_object_layer_fn; @@ -44,19 +44,21 @@ use http::HeaderMap; use lazy_static::lazy_static; use rand::Rng; use s3s::dto::{BucketVersioningStatus, ObjectLockConfiguration, ObjectLockEnabled, VersioningConfiguration}; +use tokio::time::interval; use std::cmp::Ordering; use std::slice::Iter; +use std::time::SystemTime; use std::{ collections::{HashMap, HashSet}, sync::Arc, time::Duration, }; use time::OffsetDateTime; -use tokio::fs; +use tokio::{fs, select}; use tokio::sync::mpsc::Sender; -use tokio::sync::{mpsc, RwLock, Semaphore}; +use tokio::sync::{broadcast, mpsc, RwLock, Semaphore}; -use crate::heal::data_usage_cache::DataUsageCache; +use crate::heal::data_usage_cache::{DataUsageCache, DataUsageCacheInfo}; use tracing::{debug, info, warn}; use uuid::Uuid; @@ -509,11 +511,16 @@ impl ECStore { total_results += pool.disk_set.len(); }); let mut results = Arc::new(RwLock::new(vec![DataUsageCache::default(); total_results])); + let (cancel, _) = broadcast::channel(100); + let first_err = Arc::new(RwLock::new(None)); let mut futures = Vec::new(); for pool in self.pools.iter() { for set in pool.disk_set.iter() { let index = result_index; let results_clone = results.clone(); + let first_err_clone = first_err.clone(); + let cancel_clone = cancel.clone(); + let all_buckets_clone = all_buckets.clone(); futures.push(async move { let (tx, mut rx) = mpsc::channel(100); let task = tokio::spawn(async move { @@ -528,12 +535,61 @@ impl ECStore { } } }); - + if let Err(err) = set.ns_scanner(&all_buckets_clone, want_cycle.try_into().unwrap(), tx, heal_scan_mode).await { + let mut f_w = first_err_clone.write().await; + if f_w.is_none() { + *f_w = Some(err); + } + let _ = cancel_clone.send(true); + return ; + } let _ = task.await; }); result_index += 1; } } + let (update_closer_tx, mut update_close_rx) = mpsc::channel(10); + let mut ctx_clone = cancel.subscribe(); + let all_buckets_clone = all_buckets.clone(); + let task = tokio::spawn(async move { + let mut last_update = None; + let mut interval = interval(Duration::from_secs(30)); + let all_merged = Arc::new(RwLock::new(DataUsageCache::default())); + loop { + select! { + _ = ctx_clone.recv() => { + return; + } + _ = update_close_rx.recv() => { + last_update = match tokio::spawn(update_scan(all_merged.clone(), results.clone(), last_update.clone(), all_buckets_clone.clone(), updates.clone())).await { + Ok(v) => v, + Err(_) => return, + }; + return; + } + _ = interval.tick() => { + last_update = match tokio::spawn(update_scan(all_merged.clone(), results.clone(), last_update.clone(), all_buckets_clone.clone(), updates.clone())).await { + Ok(v) => v, + Err(_) => return, + }; + } + } + } + }); + let _ = join_all(futures).await; + let mut ctx_closer = cancel.subscribe(); + select! { + _ = update_closer_tx.send(true) => { + + } + _ = ctx_closer.recv() => { + + } + } + let _ = task.await; + if let Some(err) = first_err.read().await.as_ref() { + return Err(err.clone()); + } Ok(()) } @@ -632,6 +688,28 @@ impl ECStore { } } +async fn update_scan(all_merged: Arc>, results: Arc>>, last_update: Option, all_buckets: Vec, updates: Sender) -> Option { + let mut w = all_merged.write().await; + *w = DataUsageCache { + info: DataUsageCacheInfo { + name: DATA_USAGE_ROOT.to_string(), + ..Default::default() + }, + ..Default::default() + }; + for info in results.read().await.iter() { + if info.info.last_update.is_none() { + return last_update; + } + w.merge(info); + } + if w.info.last_update > last_update && w.root().is_none() { + let _ = updates.send(w.dui(&w.info.name, &all_buckets)).await; + return w.info.last_update; + } + last_update +} + pub async fn find_local_disk(disk_path: &String) -> Option { let disk_path = match fs::canonicalize(disk_path).await { Ok(disk_path) => disk_path, From 01e0e4b6736ed507a48b9156ba97f25915b50c1f Mon Sep 17 00:00:00 2001 From: root Date: Sat, 16 Nov 2024 20:43:34 +0800 Subject: [PATCH 06/11] auto heal(1) Signed-off-by: root --- common/common/src/last_minute.rs | 10 +- .../generated/flatbuffers_generated/models.rs | 207 +- .../src/generated/proto_gen/node_service.rs | 1952 ++++------------- common/protos/src/node.proto | 14 + ecstore/src/bucket/metadata.rs | 1 - ecstore/src/cache_value/metacache_set.rs | 10 +- ecstore/src/disk/local.rs | 16 +- ecstore/src/disk/mod.rs | 16 +- ecstore/src/disk/remote.rs | 46 +- ecstore/src/erasure.rs | 4 +- ecstore/src/heal/background_heal_ops.rs | 156 +- ecstore/src/heal/data_scanner.rs | 35 +- ecstore/src/heal/data_scanner_metric.rs | 22 +- ecstore/src/heal/data_usage_cache.rs | 23 +- ecstore/src/heal/heal_commands.rs | 14 +- ecstore/src/heal/heal_ops.rs | 101 +- ecstore/src/sets.rs | 19 +- ecstore/src/store.rs | 28 +- rustfs/src/grpc.rs | 103 +- rustfs/src/main.rs | 2 - 20 files changed, 988 insertions(+), 1791 deletions(-) diff --git a/common/common/src/last_minute.rs b/common/common/src/last_minute.rs index 6141a3180..c7609d763 100644 --- a/common/common/src/last_minute.rs +++ b/common/common/src/last_minute.rs @@ -65,7 +65,10 @@ impl LastMinuteLatency { } pub fn add(&mut self, t: &Duration) { - let sec = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs(); + let sec = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); self.forward_to(sec); let win_idx = sec % 60; self.totals[win_idx as usize].add(t); @@ -81,7 +84,10 @@ impl LastMinuteLatency { pub fn get_total(&mut self) -> AccElem { let mut res = AccElem::default(); - let sec = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards").as_secs(); + let sec = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("Time went backwards") + .as_secs(); self.forward_to(sec); for elem in self.totals.iter() { res.merge(elem); diff --git a/common/protos/src/generated/flatbuffers_generated/models.rs b/common/protos/src/generated/flatbuffers_generated/models.rs index aa1f6ae2f..e4949fdcf 100644 --- a/common/protos/src/generated/flatbuffers_generated/models.rs +++ b/common/protos/src/generated/flatbuffers_generated/models.rs @@ -1,10 +1,9 @@ // automatically generated by the FlatBuffers compiler, do not modify - // @generated -use core::mem; use core::cmp::Ordering; +use core::mem; extern crate flatbuffers; use self::flatbuffers::{EndianScalar, Follow}; @@ -12,112 +11,114 @@ use self::flatbuffers::{EndianScalar, Follow}; #[allow(unused_imports, dead_code)] pub mod models { - use core::mem; - use core::cmp::Ordering; + use core::cmp::Ordering; + use core::mem; - extern crate flatbuffers; - use self::flatbuffers::{EndianScalar, Follow}; + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; -pub enum PingBodyOffset {} -#[derive(Copy, Clone, PartialEq)] + pub enum PingBodyOffset {} + #[derive(Copy, Clone, PartialEq)] -pub struct PingBody<'a> { - pub _tab: flatbuffers::Table<'a>, -} - -impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { - type Inner = PingBody<'a>; - #[inline] - unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { _tab: flatbuffers::Table::new(buf, loc) } - } -} - -impl<'a> PingBody<'a> { - pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; - - pub const fn get_fully_qualified_name() -> &'static str { - "models.PingBody" - } - - #[inline] - pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - PingBody { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, - args: &'args PingBodyArgs<'args> - ) -> flatbuffers::WIPOffset> { - let mut builder = PingBodyBuilder::new(_fbb); - if let Some(x) = args.payload { builder.add_payload(x); } - builder.finish() - } - - - #[inline] - pub fn payload(&self) -> Option> { - // Safety: - // Created from valid Table for this object - // which contains a valid value in this slot - unsafe { self._tab.get::>>(PingBody::VT_PAYLOAD, None)} - } -} - -impl flatbuffers::Verifiable for PingBody<'_> { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>>("payload", Self::VT_PAYLOAD, false)? - .finish(); - Ok(()) - } -} -pub struct PingBodyArgs<'a> { - pub payload: Option>>, -} -impl<'a> Default for PingBodyArgs<'a> { - #[inline] - fn default() -> Self { - PingBodyArgs { - payload: None, + pub struct PingBody<'a> { + pub _tab: flatbuffers::Table<'a>, } - } -} -pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - start_: flatbuffers::WIPOffset, -} -impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { - #[inline] - pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { - self.fbb_.push_slot_always::>(PingBody::VT_PAYLOAD, payload); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { - let start = _fbb.start_table(); - PingBodyBuilder { - fbb_: _fbb, - start_: start, + impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { + type Inner = PingBody<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } -} -impl core::fmt::Debug for PingBody<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut ds = f.debug_struct("PingBody"); - ds.field("payload", &self.payload()); - ds.finish() - } -} -} // pub mod models + impl<'a> PingBody<'a> { + pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; + pub const fn get_fully_qualified_name() -> &'static str { + "models.PingBody" + } + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + PingBody { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args PingBodyArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = PingBodyBuilder::new(_fbb); + if let Some(x) = args.payload { + builder.add_payload(x); + } + builder.finish() + } + + #[inline] + pub fn payload(&self) -> Option> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>>(PingBody::VT_PAYLOAD, None) + } + } + } + + impl flatbuffers::Verifiable for PingBody<'_> { + #[inline] + fn run_verifier(v: &mut flatbuffers::Verifier, pos: usize) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>("payload", Self::VT_PAYLOAD, false)? + .finish(); + Ok(()) + } + } + pub struct PingBodyArgs<'a> { + pub payload: Option>>, + } + impl<'a> Default for PingBodyArgs<'a> { + #[inline] + fn default() -> Self { + PingBodyArgs { payload: None } + } + } + + pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, + } + impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { + #[inline] + pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { + self.fbb_ + .push_slot_always::>(PingBody::VT_PAYLOAD, payload); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + PingBodyBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } + } + + impl core::fmt::Debug for PingBody<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("PingBody"); + ds.field("payload", &self.payload()); + ds.finish() + } + } +} // pub mod models diff --git a/common/protos/src/generated/proto_gen/node_service.rs b/common/protos/src/generated/proto_gen/node_service.rs index 9d13aa58b..7c7d31a57 100644 --- a/common/protos/src/generated/proto_gen/node_service.rs +++ b/common/protos/src/generated/proto_gen/node_service.rs @@ -565,6 +565,26 @@ pub struct DiskInfoResponse { #[prost(string, optional, tag = "3")] pub error_info: ::core::option::Option<::prost::alloc::string::String>, } +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NsScannerRequest { + #[prost(string, tag = "1")] + pub disk: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub cache: ::prost::alloc::string::String, + #[prost(uint64, tag = "3")] + pub scan_mode: u64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct NsScannerResponse { + #[prost(bool, tag = "1")] + pub success: bool, + #[prost(string, tag = "2")] + pub update: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub data_usage_cache: ::prost::alloc::string::String, + #[prost(string, optional, tag = "4")] + pub error_info: ::core::option::Option<::prost::alloc::string::String>, +} /// lock api have same argument type #[derive(Clone, PartialEq, ::prost::Message)] pub struct GenerallyLockRequest { @@ -580,15 +600,9 @@ pub struct GenerallyLockResponse { } /// Generated client implementations. pub mod node_service_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; + #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] use tonic::codegen::http::Uri; + use tonic::codegen::*; #[derive(Debug, Clone)] pub struct NodeServiceClient { inner: tonic::client::Grpc, @@ -619,22 +633,16 @@ pub mod node_service_client { let inner = tonic::client::Grpc::with_origin(inner, origin); Self { inner } } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> NodeServiceClient> + pub fn with_interceptor(inner: T, interceptor: F) -> NodeServiceClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, - Response = http::Response< - >::ResponseBody, - >, + Response = http::Response<>::ResponseBody>, >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, + >>::Error: + Into + std::marker::Send + std::marker::Sync, { NodeServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -677,15 +685,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Ping", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Ping"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Ping")); @@ -694,22 +696,13 @@ pub mod node_service_client { pub async fn list_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListBucket")); @@ -718,22 +711,13 @@ pub mod node_service_client { pub async fn make_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeBucket")); @@ -742,22 +726,13 @@ pub mod node_service_client { pub async fn get_bucket_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/GetBucketInfo", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/GetBucketInfo"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "GetBucketInfo")); @@ -766,22 +741,13 @@ pub mod node_service_client { pub async fn delete_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteBucket")); @@ -790,22 +756,13 @@ pub mod node_service_client { pub async fn read_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadAll", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAll"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAll")); @@ -814,22 +771,13 @@ pub mod node_service_client { pub async fn write_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteAll", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteAll"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteAll")); @@ -842,15 +790,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Delete", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Delete"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Delete")); @@ -859,22 +801,13 @@ pub mod node_service_client { pub async fn verify_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/VerifyFile", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/VerifyFile"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "VerifyFile")); @@ -883,22 +816,13 @@ pub mod node_service_client { pub async fn check_parts( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/CheckParts", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/CheckParts"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "CheckParts")); @@ -907,22 +831,13 @@ pub mod node_service_client { pub async fn rename_part( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenamePart", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenamePart"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenamePart")); @@ -931,22 +846,13 @@ pub mod node_service_client { pub async fn rename_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenameFile", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameFile"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameFile")); @@ -959,15 +865,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Write", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Write"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Write")); @@ -976,22 +876,13 @@ pub mod node_service_client { pub async fn write_stream( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteStream", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteStream"); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteStream")); @@ -1001,22 +892,13 @@ pub mod node_service_client { pub async fn read_at( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadAt", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAt"); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAt")); @@ -1025,22 +907,13 @@ pub mod node_service_client { pub async fn list_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListDir", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListDir"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListDir")); @@ -1049,22 +922,13 @@ pub mod node_service_client { pub async fn walk_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WalkDir", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WalkDir"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WalkDir")); @@ -1073,22 +937,13 @@ pub mod node_service_client { pub async fn rename_data( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenameData", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameData"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameData")); @@ -1097,22 +952,13 @@ pub mod node_service_client { pub async fn make_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeVolumes", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolumes"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolumes")); @@ -1121,22 +967,13 @@ pub mod node_service_client { pub async fn make_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolume")); @@ -1145,22 +982,13 @@ pub mod node_service_client { pub async fn list_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListVolumes", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListVolumes"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListVolumes")); @@ -1169,22 +997,13 @@ pub mod node_service_client { pub async fn stat_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/StatVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/StatVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "StatVolume")); @@ -1193,22 +1012,13 @@ pub mod node_service_client { pub async fn delete_paths( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeletePaths", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeletePaths"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeletePaths")); @@ -1217,22 +1027,13 @@ pub mod node_service_client { pub async fn update_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/UpdateMetadata", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UpdateMetadata"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UpdateMetadata")); @@ -1241,22 +1042,13 @@ pub mod node_service_client { pub async fn write_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteMetadata", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteMetadata"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteMetadata")); @@ -1265,22 +1057,13 @@ pub mod node_service_client { pub async fn read_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadVersion", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadVersion"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadVersion")); @@ -1293,15 +1076,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadXL", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadXL"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadXL")); @@ -1310,22 +1087,13 @@ pub mod node_service_client { pub async fn delete_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVersion", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersion"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersion")); @@ -1334,22 +1102,13 @@ pub mod node_service_client { pub async fn delete_versions( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVersions", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersions"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersions")); @@ -1358,22 +1117,13 @@ pub mod node_service_client { pub async fn read_multiple( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadMultiple", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadMultiple"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadMultiple")); @@ -1382,22 +1132,13 @@ pub mod node_service_client { pub async fn delete_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVolume")); @@ -1406,46 +1147,43 @@ pub mod node_service_client { pub async fn disk_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DiskInfo", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DiskInfo"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DiskInfo")); self.inner.unary(req, path, codec).await } - pub async fn lock( + pub async fn ns_scanner( &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + request: impl tonic::IntoStreamingRequest, + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Lock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/NsScanner"); + let mut req = request.into_streaming_request(); + req.extensions_mut() + .insert(GrpcMethod::new("node_service.NodeService", "NsScanner")); + self.inner.streaming(req, path, codec).await + } + pub async fn lock( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Lock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Lock")); @@ -1454,22 +1192,13 @@ pub mod node_service_client { pub async fn un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/UnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UnLock")); @@ -1478,22 +1207,13 @@ pub mod node_service_client { pub async fn r_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RLock")); @@ -1502,22 +1222,13 @@ pub mod node_service_client { pub async fn r_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RUnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RUnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RUnLock")); @@ -1526,22 +1237,13 @@ pub mod node_service_client { pub async fn force_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ForceUnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ForceUnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ForceUnLock")); @@ -1550,22 +1252,13 @@ pub mod node_service_client { pub async fn refresh( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Refresh", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Refresh"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Refresh")); @@ -1575,13 +1268,7 @@ pub mod node_service_client { } /// Generated server implementations. pub mod node_service_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] + #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] use tonic::codegen::*; /// Generated trait containing gRPC methods that should be implemented for use with NodeServiceServer. #[async_trait] @@ -1594,31 +1281,19 @@ pub mod node_service_server { async fn list_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn get_bucket_info( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_all( &self, request: tonic::Request, @@ -1626,10 +1301,7 @@ pub mod node_service_server { async fn write_all( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete( &self, request: tonic::Request, @@ -1637,52 +1309,33 @@ pub mod node_service_server { async fn verify_file( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn check_parts( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn rename_part( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn rename_file( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn write( &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the WriteStream method. - type WriteStreamStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + type WriteStreamStream: tonic::codegen::tokio_stream::Stream> + std::marker::Send + 'static; async fn write_stream( &self, request: tonic::Request>, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the ReadAt method. - type ReadAtStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + type ReadAtStream: tonic::codegen::tokio_stream::Stream> + std::marker::Send + 'static; /// rpc Append(AppendRequest) returns (AppendResponse) {}; @@ -1701,66 +1354,39 @@ pub mod node_service_server { async fn rename_data( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_volumes( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn list_volumes( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn stat_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_paths( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn update_metadata( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn write_metadata( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_version( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_xl( &self, request: tonic::Request, @@ -1768,80 +1394,55 @@ pub mod node_service_server { async fn delete_version( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_versions( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_multiple( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn disk_info( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; + /// Server streaming response type for the NsScanner method. + type NsScannerStream: tonic::codegen::tokio_stream::Stream> + + std::marker::Send + + 'static; + async fn ns_scanner( + &self, + request: tonic::Request>, + ) -> std::result::Result, tonic::Status>; async fn lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn r_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn r_un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn force_un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn refresh( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; } #[derive(Debug)] pub struct NodeServiceServer { @@ -1864,10 +1465,7 @@ pub mod node_service_server { max_encoding_message_size: None, } } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService + pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService where F: tonic::service::Interceptor, { @@ -1911,10 +1509,7 @@ pub mod node_service_server { type Response = http::Response; type Error = std::convert::Infallible; type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: http::Request) -> Self::Future { @@ -1922,21 +1517,12 @@ pub mod node_service_server { "/node_service.NodeService/Ping" => { #[allow(non_camel_case_types)] struct PingSvc(pub Arc); - impl tonic::server::UnaryService - for PingSvc { + impl tonic::server::UnaryService for PingSvc { type Response = super::PingResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::ping(&inner, request).await - }; + let fut = async move { ::ping(&inner, request).await }; Box::pin(fut) } } @@ -1949,14 +1535,8 @@ pub mod node_service_server { let method = PingSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1965,23 +1545,12 @@ pub mod node_service_server { "/node_service.NodeService/ListBucket" => { #[allow(non_camel_case_types)] struct ListBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListBucketSvc { + impl tonic::server::UnaryService for ListBucketSvc { type Response = super::ListBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_bucket(&inner, request).await - }; + let fut = async move { ::list_bucket(&inner, request).await }; Box::pin(fut) } } @@ -1994,14 +1563,8 @@ pub mod node_service_server { let method = ListBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2010,23 +1573,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeBucket" => { #[allow(non_camel_case_types)] struct MakeBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeBucketSvc { + impl tonic::server::UnaryService for MakeBucketSvc { type Response = super::MakeBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_bucket(&inner, request).await - }; + let fut = async move { ::make_bucket(&inner, request).await }; Box::pin(fut) } } @@ -2039,14 +1591,8 @@ pub mod node_service_server { let method = MakeBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2055,23 +1601,12 @@ pub mod node_service_server { "/node_service.NodeService/GetBucketInfo" => { #[allow(non_camel_case_types)] struct GetBucketInfoSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for GetBucketInfoSvc { + impl tonic::server::UnaryService for GetBucketInfoSvc { type Response = super::GetBucketInfoResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::get_bucket_info(&inner, request).await - }; + let fut = async move { ::get_bucket_info(&inner, request).await }; Box::pin(fut) } } @@ -2084,14 +1619,8 @@ pub mod node_service_server { let method = GetBucketInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2100,23 +1629,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteBucket" => { #[allow(non_camel_case_types)] struct DeleteBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteBucketSvc { + impl tonic::server::UnaryService for DeleteBucketSvc { type Response = super::DeleteBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_bucket(&inner, request).await - }; + let fut = async move { ::delete_bucket(&inner, request).await }; Box::pin(fut) } } @@ -2129,14 +1647,8 @@ pub mod node_service_server { let method = DeleteBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2145,23 +1657,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadAll" => { #[allow(non_camel_case_types)] struct ReadAllSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadAllSvc { + impl tonic::server::UnaryService for ReadAllSvc { type Response = super::ReadAllResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_all(&inner, request).await - }; + let fut = async move { ::read_all(&inner, request).await }; Box::pin(fut) } } @@ -2174,14 +1675,8 @@ pub mod node_service_server { let method = ReadAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2190,23 +1685,12 @@ pub mod node_service_server { "/node_service.NodeService/WriteAll" => { #[allow(non_camel_case_types)] struct WriteAllSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WriteAllSvc { + impl tonic::server::UnaryService for WriteAllSvc { type Response = super::WriteAllResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_all(&inner, request).await - }; + let fut = async move { ::write_all(&inner, request).await }; Box::pin(fut) } } @@ -2219,14 +1703,8 @@ pub mod node_service_server { let method = WriteAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2235,23 +1713,12 @@ pub mod node_service_server { "/node_service.NodeService/Delete" => { #[allow(non_camel_case_types)] struct DeleteSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteSvc { + impl tonic::server::UnaryService for DeleteSvc { type Response = super::DeleteResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete(&inner, request).await - }; + let fut = async move { ::delete(&inner, request).await }; Box::pin(fut) } } @@ -2264,14 +1731,8 @@ pub mod node_service_server { let method = DeleteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2280,23 +1741,12 @@ pub mod node_service_server { "/node_service.NodeService/VerifyFile" => { #[allow(non_camel_case_types)] struct VerifyFileSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for VerifyFileSvc { + impl tonic::server::UnaryService for VerifyFileSvc { type Response = super::VerifyFileResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::verify_file(&inner, request).await - }; + let fut = async move { ::verify_file(&inner, request).await }; Box::pin(fut) } } @@ -2309,14 +1759,8 @@ pub mod node_service_server { let method = VerifyFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2325,23 +1769,12 @@ pub mod node_service_server { "/node_service.NodeService/CheckParts" => { #[allow(non_camel_case_types)] struct CheckPartsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for CheckPartsSvc { + impl tonic::server::UnaryService for CheckPartsSvc { type Response = super::CheckPartsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::check_parts(&inner, request).await - }; + let fut = async move { ::check_parts(&inner, request).await }; Box::pin(fut) } } @@ -2354,14 +1787,8 @@ pub mod node_service_server { let method = CheckPartsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2370,23 +1797,12 @@ pub mod node_service_server { "/node_service.NodeService/RenamePart" => { #[allow(non_camel_case_types)] struct RenamePartSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenamePartSvc { + impl tonic::server::UnaryService for RenamePartSvc { type Response = super::RenamePartResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_part(&inner, request).await - }; + let fut = async move { ::rename_part(&inner, request).await }; Box::pin(fut) } } @@ -2399,14 +1815,8 @@ pub mod node_service_server { let method = RenamePartSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2415,23 +1825,12 @@ pub mod node_service_server { "/node_service.NodeService/RenameFile" => { #[allow(non_camel_case_types)] struct RenameFileSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenameFileSvc { + impl tonic::server::UnaryService for RenameFileSvc { type Response = super::RenameFileResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_file(&inner, request).await - }; + let fut = async move { ::rename_file(&inner, request).await }; Box::pin(fut) } } @@ -2444,14 +1843,8 @@ pub mod node_service_server { let method = RenameFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2460,21 +1853,12 @@ pub mod node_service_server { "/node_service.NodeService/Write" => { #[allow(non_camel_case_types)] struct WriteSvc(pub Arc); - impl tonic::server::UnaryService - for WriteSvc { + impl tonic::server::UnaryService for WriteSvc { type Response = super::WriteResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write(&inner, request).await - }; + let fut = async move { ::write(&inner, request).await }; Box::pin(fut) } } @@ -2487,14 +1871,8 @@ pub mod node_service_server { let method = WriteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2503,26 +1881,13 @@ pub mod node_service_server { "/node_service.NodeService/WriteStream" => { #[allow(non_camel_case_types)] struct WriteStreamSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::StreamingService - for WriteStreamSvc { + impl tonic::server::StreamingService for WriteStreamSvc { type Response = super::WriteResponse; type ResponseStream = T::WriteStreamStream; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - tonic::Streaming, - >, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_stream(&inner, request).await - }; + let fut = async move { ::write_stream(&inner, request).await }; Box::pin(fut) } } @@ -2535,14 +1900,8 @@ pub mod node_service_server { let method = WriteStreamSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -2551,26 +1910,13 @@ pub mod node_service_server { "/node_service.NodeService/ReadAt" => { #[allow(non_camel_case_types)] struct ReadAtSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::StreamingService - for ReadAtSvc { + impl tonic::server::StreamingService for ReadAtSvc { type Response = super::ReadAtResponse; type ResponseStream = T::ReadAtStream; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - tonic::Streaming, - >, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_at(&inner, request).await - }; + let fut = async move { ::read_at(&inner, request).await }; Box::pin(fut) } } @@ -2583,14 +1929,8 @@ pub mod node_service_server { let method = ReadAtSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -2599,23 +1939,12 @@ pub mod node_service_server { "/node_service.NodeService/ListDir" => { #[allow(non_camel_case_types)] struct ListDirSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListDirSvc { + impl tonic::server::UnaryService for ListDirSvc { type Response = super::ListDirResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_dir(&inner, request).await - }; + let fut = async move { ::list_dir(&inner, request).await }; Box::pin(fut) } } @@ -2628,14 +1957,8 @@ pub mod node_service_server { let method = ListDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2644,23 +1967,12 @@ pub mod node_service_server { "/node_service.NodeService/WalkDir" => { #[allow(non_camel_case_types)] struct WalkDirSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WalkDirSvc { + impl tonic::server::UnaryService for WalkDirSvc { type Response = super::WalkDirResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::walk_dir(&inner, request).await - }; + let fut = async move { ::walk_dir(&inner, request).await }; Box::pin(fut) } } @@ -2673,14 +1985,8 @@ pub mod node_service_server { let method = WalkDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2689,23 +1995,12 @@ pub mod node_service_server { "/node_service.NodeService/RenameData" => { #[allow(non_camel_case_types)] struct RenameDataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenameDataSvc { + impl tonic::server::UnaryService for RenameDataSvc { type Response = super::RenameDataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_data(&inner, request).await - }; + let fut = async move { ::rename_data(&inner, request).await }; Box::pin(fut) } } @@ -2718,14 +2013,8 @@ pub mod node_service_server { let method = RenameDataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2734,23 +2023,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolumes" => { #[allow(non_camel_case_types)] struct MakeVolumesSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeVolumesSvc { + impl tonic::server::UnaryService for MakeVolumesSvc { type Response = super::MakeVolumesResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_volumes(&inner, request).await - }; + let fut = async move { ::make_volumes(&inner, request).await }; Box::pin(fut) } } @@ -2763,14 +2041,8 @@ pub mod node_service_server { let method = MakeVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2779,23 +2051,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolume" => { #[allow(non_camel_case_types)] struct MakeVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeVolumeSvc { + impl tonic::server::UnaryService for MakeVolumeSvc { type Response = super::MakeVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_volume(&inner, request).await - }; + let fut = async move { ::make_volume(&inner, request).await }; Box::pin(fut) } } @@ -2808,14 +2069,8 @@ pub mod node_service_server { let method = MakeVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2824,23 +2079,12 @@ pub mod node_service_server { "/node_service.NodeService/ListVolumes" => { #[allow(non_camel_case_types)] struct ListVolumesSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListVolumesSvc { + impl tonic::server::UnaryService for ListVolumesSvc { type Response = super::ListVolumesResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_volumes(&inner, request).await - }; + let fut = async move { ::list_volumes(&inner, request).await }; Box::pin(fut) } } @@ -2853,14 +2097,8 @@ pub mod node_service_server { let method = ListVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2869,23 +2107,12 @@ pub mod node_service_server { "/node_service.NodeService/StatVolume" => { #[allow(non_camel_case_types)] struct StatVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for StatVolumeSvc { + impl tonic::server::UnaryService for StatVolumeSvc { type Response = super::StatVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::stat_volume(&inner, request).await - }; + let fut = async move { ::stat_volume(&inner, request).await }; Box::pin(fut) } } @@ -2898,14 +2125,8 @@ pub mod node_service_server { let method = StatVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2914,23 +2135,12 @@ pub mod node_service_server { "/node_service.NodeService/DeletePaths" => { #[allow(non_camel_case_types)] struct DeletePathsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeletePathsSvc { + impl tonic::server::UnaryService for DeletePathsSvc { type Response = super::DeletePathsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_paths(&inner, request).await - }; + let fut = async move { ::delete_paths(&inner, request).await }; Box::pin(fut) } } @@ -2943,14 +2153,8 @@ pub mod node_service_server { let method = DeletePathsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2959,23 +2163,12 @@ pub mod node_service_server { "/node_service.NodeService/UpdateMetadata" => { #[allow(non_camel_case_types)] struct UpdateMetadataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for UpdateMetadataSvc { + impl tonic::server::UnaryService for UpdateMetadataSvc { type Response = super::UpdateMetadataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::update_metadata(&inner, request).await - }; + let fut = async move { ::update_metadata(&inner, request).await }; Box::pin(fut) } } @@ -2988,14 +2181,8 @@ pub mod node_service_server { let method = UpdateMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3004,23 +2191,12 @@ pub mod node_service_server { "/node_service.NodeService/WriteMetadata" => { #[allow(non_camel_case_types)] struct WriteMetadataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WriteMetadataSvc { + impl tonic::server::UnaryService for WriteMetadataSvc { type Response = super::WriteMetadataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_metadata(&inner, request).await - }; + let fut = async move { ::write_metadata(&inner, request).await }; Box::pin(fut) } } @@ -3033,14 +2209,8 @@ pub mod node_service_server { let method = WriteMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3049,23 +2219,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadVersion" => { #[allow(non_camel_case_types)] struct ReadVersionSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadVersionSvc { + impl tonic::server::UnaryService for ReadVersionSvc { type Response = super::ReadVersionResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_version(&inner, request).await - }; + let fut = async move { ::read_version(&inner, request).await }; Box::pin(fut) } } @@ -3078,14 +2237,8 @@ pub mod node_service_server { let method = ReadVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3094,23 +2247,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadXL" => { #[allow(non_camel_case_types)] struct ReadXLSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadXLSvc { + impl tonic::server::UnaryService for ReadXLSvc { type Response = super::ReadXlResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_xl(&inner, request).await - }; + let fut = async move { ::read_xl(&inner, request).await }; Box::pin(fut) } } @@ -3123,14 +2265,8 @@ pub mod node_service_server { let method = ReadXLSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3139,23 +2275,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersion" => { #[allow(non_camel_case_types)] struct DeleteVersionSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVersionSvc { + impl tonic::server::UnaryService for DeleteVersionSvc { type Response = super::DeleteVersionResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_version(&inner, request).await - }; + let fut = async move { ::delete_version(&inner, request).await }; Box::pin(fut) } } @@ -3168,14 +2293,8 @@ pub mod node_service_server { let method = DeleteVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3184,23 +2303,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersions" => { #[allow(non_camel_case_types)] struct DeleteVersionsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVersionsSvc { + impl tonic::server::UnaryService for DeleteVersionsSvc { type Response = super::DeleteVersionsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_versions(&inner, request).await - }; + let fut = async move { ::delete_versions(&inner, request).await }; Box::pin(fut) } } @@ -3213,14 +2321,8 @@ pub mod node_service_server { let method = DeleteVersionsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3229,23 +2331,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadMultiple" => { #[allow(non_camel_case_types)] struct ReadMultipleSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadMultipleSvc { + impl tonic::server::UnaryService for ReadMultipleSvc { type Response = super::ReadMultipleResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_multiple(&inner, request).await - }; + let fut = async move { ::read_multiple(&inner, request).await }; Box::pin(fut) } } @@ -3258,14 +2349,8 @@ pub mod node_service_server { let method = ReadMultipleSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3274,23 +2359,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVolume" => { #[allow(non_camel_case_types)] struct DeleteVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVolumeSvc { + impl tonic::server::UnaryService for DeleteVolumeSvc { type Response = super::DeleteVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_volume(&inner, request).await - }; + let fut = async move { ::delete_volume(&inner, request).await }; Box::pin(fut) } } @@ -3303,14 +2377,8 @@ pub mod node_service_server { let method = DeleteVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3319,23 +2387,12 @@ pub mod node_service_server { "/node_service.NodeService/DiskInfo" => { #[allow(non_camel_case_types)] struct DiskInfoSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DiskInfoSvc { + impl tonic::server::UnaryService for DiskInfoSvc { type Response = super::DiskInfoResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::disk_info(&inner, request).await - }; + let fut = async move { ::disk_info(&inner, request).await }; Box::pin(fut) } } @@ -3348,39 +2405,51 @@ pub mod node_service_server { let method = DiskInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } + "/node_service.NodeService/NsScanner" => { + #[allow(non_camel_case_types)] + struct NsScannerSvc(pub Arc); + impl tonic::server::StreamingService for NsScannerSvc { + type Response = super::NsScannerResponse; + type ResponseStream = T::NsScannerStream; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::ns_scanner(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = NsScannerSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + let res = grpc.streaming(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/node_service.NodeService/Lock" => { #[allow(non_camel_case_types)] struct LockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for LockSvc { + impl tonic::server::UnaryService for LockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::lock(&inner, request).await - }; + let fut = async move { ::lock(&inner, request).await }; Box::pin(fut) } } @@ -3393,14 +2462,8 @@ pub mod node_service_server { let method = LockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3409,23 +2472,12 @@ pub mod node_service_server { "/node_service.NodeService/UnLock" => { #[allow(non_camel_case_types)] struct UnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for UnLockSvc { + impl tonic::server::UnaryService for UnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::un_lock(&inner, request).await - }; + let fut = async move { ::un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3438,14 +2490,8 @@ pub mod node_service_server { let method = UnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3454,23 +2500,12 @@ pub mod node_service_server { "/node_service.NodeService/RLock" => { #[allow(non_camel_case_types)] struct RLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RLockSvc { + impl tonic::server::UnaryService for RLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::r_lock(&inner, request).await - }; + let fut = async move { ::r_lock(&inner, request).await }; Box::pin(fut) } } @@ -3483,14 +2518,8 @@ pub mod node_service_server { let method = RLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3499,23 +2528,12 @@ pub mod node_service_server { "/node_service.NodeService/RUnLock" => { #[allow(non_camel_case_types)] struct RUnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RUnLockSvc { + impl tonic::server::UnaryService for RUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::r_un_lock(&inner, request).await - }; + let fut = async move { ::r_un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3528,14 +2546,8 @@ pub mod node_service_server { let method = RUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3544,23 +2556,12 @@ pub mod node_service_server { "/node_service.NodeService/ForceUnLock" => { #[allow(non_camel_case_types)] struct ForceUnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ForceUnLockSvc { + impl tonic::server::UnaryService for ForceUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::force_un_lock(&inner, request).await - }; + let fut = async move { ::force_un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3573,14 +2574,8 @@ pub mod node_service_server { let method = ForceUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3589,23 +2584,12 @@ pub mod node_service_server { "/node_service.NodeService/Refresh" => { #[allow(non_camel_case_types)] struct RefreshSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RefreshSvc { + impl tonic::server::UnaryService for RefreshSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::refresh(&inner, request).await - }; + let fut = async move { ::refresh(&inner, request).await }; Box::pin(fut) } } @@ -3618,36 +2602,20 @@ pub mod node_service_server { let method = RefreshSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } - _ => { - Box::pin(async move { - let mut response = http::Response::new(empty_body()); - let headers = response.headers_mut(); - headers - .insert( - tonic::Status::GRPC_STATUS, - (tonic::Code::Unimplemented as i32).into(), - ); - headers - .insert( - http::header::CONTENT_TYPE, - tonic::metadata::GRPC_CONTENT_TYPE, - ); - Ok(response) - }) - } + _ => Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into()); + headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE); + Ok(response) + }), } } } diff --git a/common/protos/src/node.proto b/common/protos/src/node.proto index f789a302f..79e234ee6 100644 --- a/common/protos/src/node.proto +++ b/common/protos/src/node.proto @@ -382,6 +382,19 @@ message DiskInfoResponse { optional string error_info = 3; } +message NsScannerRequest { + string disk = 1; + string cache = 2; + uint64 scan_mode = 3; +} + +message NsScannerResponse { + bool success = 1; + string update = 2; + string data_usage_cache = 3; + optional string error_info = 4; +} + // lock api have same argument type message GenerallyLockRequest { string args = 1; @@ -432,6 +445,7 @@ service NodeService { rpc ReadMultiple(ReadMultipleRequest) returns (ReadMultipleResponse) {}; rpc DeleteVolume(DeleteVolumeRequest) returns (DeleteVolumeResponse) {}; rpc DiskInfo(DiskInfoRequest) returns (DiskInfoResponse) {}; + rpc NsScanner(stream NsScannerRequest) returns (stream NsScannerResponse) {}; /* -------------------------------lock service-------------------------- */ diff --git a/ecstore/src/bucket/metadata.rs b/ecstore/src/bucket/metadata.rs index ac0134d86..a296a973f 100644 --- a/ecstore/src/bucket/metadata.rs +++ b/ecstore/src/bucket/metadata.rs @@ -9,7 +9,6 @@ use s3s::dto::{ BucketLifecycleConfiguration, NotificationConfiguration, ObjectLockConfiguration, ReplicationConfiguration, ServerSideEncryptionConfiguration, Tagging, VersioningConfiguration, }; -use s3s::xml; use serde::Serializer; use serde::{Deserialize, Serialize}; use std::collections::HashMap; diff --git a/ecstore/src/cache_value/metacache_set.rs b/ecstore/src/cache_value/metacache_set.rs index 18b698a9e..aad3617b6 100644 --- a/ecstore/src/cache_value/metacache_set.rs +++ b/ecstore/src/cache_value/metacache_set.rs @@ -14,8 +14,8 @@ use crate::{ error::{Error, Result}, }; -type AgreedFn = Box Pin>> + Send + 'static>; -type PartialFn = Box]) -> Pin>> + Send + 'static>; +type AgreedFn = Box Pin + Send>> + Send + 'static>; +type PartialFn = Box]) -> Pin + Send>> + Send + 'static>; type FinishedFn = Box]) -> Pin + Send>> + Send + 'static>; #[derive(Default)] @@ -213,7 +213,7 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - if at_eof + has_err == readers.len() { if has_err > 0 { if let Some(finished_fn) = opts.finished.as_ref() { - finished_fn(&errs); + finished_fn(&errs).await; } break; } @@ -221,13 +221,13 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - if agree == readers.len() { if let Some(agreed_fn) = opts.agreed.as_ref() { - agreed_fn(current); + agreed_fn(current).await; } continue; } if let Some(partial_fn) = opts.partial.as_ref() { - partial_fn(MetaCacheEntries(top_entries), &errs); + partial_fn(MetaCacheEntries(top_entries), &errs).await; } } diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index d70c04a12..e7c45195d 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -20,8 +20,8 @@ use crate::disk::{LocalFileReader, LocalFileWriter, STORAGE_FORMAT_FILE}; use crate::error::{Error, Result}; use crate::global::{GLOBAL_IsErasureSD, GLOBAL_RootDiskThreshold}; use crate::heal::data_scanner::{has_active_rules, scan_data_folder, ScannerItem, SizeSummary}; -use crate::heal::data_scanner_metric::{globalScannerMetrics, ScannerMetric, ScannerMetrics}; -use crate::heal::data_usage_cache::{self, DataUsageCache, DataUsageEntry}; +use crate::heal::data_scanner_metric::{ScannerMetric, ScannerMetrics}; +use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry}; use crate::heal::error::{ERR_IGNORE_FILE_CONTRIB, ERR_SKIP_FILE}; use crate::heal::heal_commands::HealScanMode; use crate::new_object_layer_fn; @@ -40,7 +40,6 @@ use crate::{ }; use common::defer; use path_absolutize::Absolutize; -use s3s::dto::{ReplicationConfiguration, ReplicationRuleStatus}; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::io::Cursor; @@ -1880,7 +1879,7 @@ impl DiskAPI for LocalDisk { } async fn ns_scanner( - self: Arc, + &self, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, @@ -1908,7 +1907,7 @@ impl DiskAPI for LocalDisk { }; let loc = self.get_disk_location(); let disks = store.get_disks(loc.pool_idx.unwrap(), loc.disk_idx.unwrap()).await?; - let disk = self.clone(); + let disk = Arc::new(LocalDisk::new(&self.endpoint(), false).await?); let disk_clone = disk.clone(); let mut cache = cache.clone(); cache.info.updates = Some(updates.clone()); @@ -1925,7 +1924,7 @@ impl DiskAPI for LocalDisk { } let stop_fn = ScannerMetrics::log(ScannerMetric::ScanObject); let mut res = HashMap::new(); - let done_sz = ScannerMetrics::time_size(ScannerMetric::ReadMetadata); + let done_sz = ScannerMetrics::time_size(ScannerMetric::ReadMetadata).await; let buf = match disk.read_metadata(item.path.clone()).await { Ok(buf) => buf, Err(err) => { @@ -1965,7 +1964,7 @@ impl DiskAPI for LocalDisk { let mut obj_deleted = false; for info in obj_infos.iter() { let done = ScannerMetrics::time(ScannerMetric::ApplyVersion); - let mut sz = 0; + let sz: usize; (obj_deleted, sz) = item.apply_actions(&info, &size_s).await; done().await; @@ -1994,7 +1993,8 @@ impl DiskAPI for LocalDisk { } for frer_version in fivs.free_versions.iter() { - let _obj_info = frer_version.to_object_info(&item.bucket, &item.object_path().to_string_lossy(), versioned); + let _obj_info = + frer_version.to_object_info(&item.bucket, &item.object_path().to_string_lossy(), versioned); let done = ScannerMetrics::time(ScannerMetric::TierObjSweep); done().await; } diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index 880ffd59e..d903a6f9a 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -1,7 +1,7 @@ pub mod endpoint; pub mod error; pub mod format; -mod local; +pub mod local; pub mod os; pub mod remote; @@ -16,7 +16,7 @@ const STORAGE_FORMAT_FILE: &str = "xl.meta"; use crate::{ erasure::Writer, error::{Error, Result}, - file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion, FileMetaVersion}, + file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion}, heal::{ data_usage_cache::{DataUsageCache, DataUsageEntry}, heal_commands::HealScanMode, @@ -344,14 +344,14 @@ impl DiskAPI for Disk { } async fn ns_scanner( - self: Arc, + &self, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, ) -> Result { match &*self { - Disk::Local(local_disk) => Arc::new(local_disk).ns_scanner(cache, updates, scan_mode).await, - Disk::Remote(remote_disk) => Arc::new(remote_disk).ns_scanner(cache, updates, scan_mode).await, + Disk::Local(local_disk) => local_disk.ns_scanner(cache, updates, scan_mode).await, + Disk::Remote(remote_disk) => remote_disk.ns_scanner(cache, updates, scan_mode).await, } } } @@ -453,7 +453,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static { async fn read_all(&self, volume: &str, path: &str) -> Result>; async fn disk_info(&self, opts: &DiskInfoOptions) -> Result; async fn ns_scanner( - self: Arc, + &self, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, @@ -1303,10 +1303,10 @@ impl Reader for RemoteFileReader { Err(Error::from_string(error_info)) } } - async fn seek(&mut self, offset: usize) -> Result<()> { + async fn seek(&mut self, _offset: usize) -> Result<()> { unimplemented!() } - async fn read_exact(&mut self, buf: &mut [u8]) -> Result { + async fn read_exact(&mut self, _buf: &mut [u8]) -> Result { unimplemented!() } } diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index fe7df93b3..e23508f76 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -1,16 +1,17 @@ -use std::{path::PathBuf, sync::Arc}; +use std::path::PathBuf; 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, + DiskInfoRequest, ListDirRequest, ListVolumesRequest, MakeVolumeRequest, MakeVolumesRequest, NsScannerRequest, + ReadAllRequest, ReadMultipleRequest, ReadVersionRequest, ReadXlRequest, RenameDataRequest, RenameFileRequst, + StatVolumeRequest, UpdateMetadataRequest, VerifyFileRequest, WalkDirRequest, WriteAllRequest, WriteMetadataRequest, }, }; -use tokio::sync::mpsc::Sender; +use tokio::sync::mpsc::{self, Sender}; +use tokio_stream::{wrappers::ReceiverStream, StreamExt}; use tonic::Request; use tracing::info; use uuid::Uuid; @@ -736,11 +737,42 @@ impl DiskAPI for RemoteDisk { } async fn ns_scanner( - self: Arc, + &self, cache: &DataUsageCache, updates: Sender, scan_mode: HealScanMode, ) -> Result { - todo!() + info!("ns_scanner"); + let cache = serde_json::to_string(cache)?; + let mut client = node_service_time_out_client(&self.addr) + .await + .map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?; + + let (tx, rx) = mpsc::channel(10); + let in_stream = ReceiverStream::new(rx); + let mut response = client.ns_scanner(in_stream).await?.into_inner(); + let request = NsScannerRequest { + disk: self.root.to_string_lossy().to_string(), + cache, + scan_mode: scan_mode as u64, + }; + tx.send(request).await?; + + loop { + match response.next().await { + Some(Ok(resp)) => { + if !resp.update.is_empty() { + let data_usage_cache = serde_json::from_str::(&resp.update)?; + let _ = updates.send(data_usage_cache).await; + } else if !resp.data_usage_cache.is_empty() { + let data_usage_cache = serde_json::from_str::(&resp.data_usage_cache)?; + return Ok(data_usage_cache); + } else { + return Err(Error::from_string("scan was interrupted")); + } + } + _ => return Err(Error::from_string("scan was interrupted")), + } + } } } diff --git a/ecstore/src/erasure.rs b/ecstore/src/erasure.rs index d0322532e..5d2bba9e0 100644 --- a/ecstore/src/erasure.rs +++ b/ecstore/src/erasure.rs @@ -424,7 +424,7 @@ impl Erasure { writers: &mut [Option], readers: Vec>, total_length: usize, - prefer: &[bool], + _prefer: &[bool], ) -> Result<()> { if writers.len() != self.parity_shards + self.data_shards { return Err(Error::from_string("invalid argument")); @@ -437,8 +437,6 @@ impl Erasure { end_block += 1; } - let mut bytes_writed = 0; - let mut errs = Vec::new(); for _ in start_block..=end_block { let mut bufs = reader.read().await?; diff --git a/ecstore/src/heal/background_heal_ops.rs b/ecstore/src/heal/background_heal_ops.rs index 4c305b24b..1ac61387e 100644 --- a/ecstore/src/heal/background_heal_ops.rs +++ b/ecstore/src/heal/background_heal_ops.rs @@ -1,17 +1,14 @@ use std::{env, sync::Arc}; -use tokio::{ - select, - sync::{ - broadcast::Receiver as B_Receiver, - mpsc::{self, Receiver, Sender}, - RwLock, - }, +use tokio::sync::{ + mpsc::{self, Receiver, Sender}, + RwLock, }; use crate::{ - disk::error::DiskError, + endpoints::Endpoints, error::{Error, Result}, + global::{GLOBAL_BackgroundHealRoutine, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP}, heal::heal_ops::NOP_HEAL, new_object_layer_fn, store_api::StorageAPI, @@ -20,9 +17,38 @@ use crate::{ use super::{ heal_commands::{HealOpts, HealResultItem}, - heal_ops::HealSequence, + heal_ops::{new_bg_heal_sequence, HealSequence}, }; +pub async fn init_auto_heal() { + init_background_healing().await; + if let Ok(v) = env::var("_RUSTFS_AUTO_DRIVE_HEALING") { + if v == "on" { + // GLOBAL_BackgroundHealState.write().await.push_heal_local_disks(heal_local_disks).await; + } + } +} + +async fn init_background_healing() { + let bg_seq = Arc::new(RwLock::new(new_bg_heal_sequence())); + for _ in 0..GLOBAL_BackgroundHealRoutine.read().await.workers { + let bg_seq_clone = bg_seq.clone(); + tokio::spawn(async { + GLOBAL_BackgroundHealRoutine.write().await.add_worker(bg_seq_clone).await; + }); + } + let _ = GLOBAL_BackgroundHealState + .write() + .await + .launch_new_heal_sequence(bg_seq) + .await; +} + +async fn get_local_disks_to_heal() -> Endpoints { + for (_, disk) in GLOBAL_LOCAL_DISK_MAP.read().await.iter() {} + todo!() +} + #[derive(Clone, Debug)] pub struct HealTask { pub bucket: String, @@ -49,7 +75,7 @@ impl HealTask { pub struct HealResult { pub result: HealResultItem, - err: Option, + _err: Option, } pub struct HealRoutine { @@ -79,66 +105,68 @@ impl HealRoutine { })) } - pub async fn add_worker(&mut self, mut ctx: B_Receiver, bgseq: &mut HealSequence) { + pub async fn add_worker(&mut self, bgseq: Arc>) { loop { - select! { - task = self.tasks_rx.recv() => { - let mut d_res = HealResultItem::default(); - let d_err: Option; - match task { - Some(task) => { - if task.bucket == NOP_HEAL { - d_err = Some(Error::from_string("skip file")); - } else if task.bucket == SLASH_SEPARATOR { - match heal_disk_format(task.opts).await { - Ok((res, err)) => { - d_res = res; - d_err = err; - }, - Err(err) => {d_err = Some(err)}, - } - } else { - let layer = new_object_layer_fn(); - let lock = layer.read().await; - let store = lock - .as_ref() - .expect("Not init"); - if task.object.is_empty() { - match store.heal_object(&task.bucket, &task.object, &task.version_id, &task.opts).await { - Ok((res, err)) => { - d_res = res; - d_err = err; - }, - Err(err) => {d_err = Some(err)}, - } - } else { - match store.heal_object(&task.bucket, &task.object, &task.version_id, &task.opts).await { - Ok((res, err)) => { - d_res = res; - d_err = err; - }, - Err(err) => {d_err = Some(err)}, - } - } + let mut d_res = HealResultItem::default(); + let d_err: Option; + match self.tasks_rx.recv().await { + Some(task) => { + if task.bucket == NOP_HEAL { + d_err = Some(Error::from_string("skip file")); + } else if task.bucket == SLASH_SEPARATOR { + match heal_disk_format(task.opts).await { + Ok((res, err)) => { + d_res = res; + d_err = err; } - if let Some(resp_tx) = task.resp_tx { - let _ = resp_tx.send(HealResult{result: d_res, err: d_err}).await; - } else { - // when respCh is not set caller is not waiting but we - // update the relevant metrics for them - if d_err.is_none() { - bgseq.count_healed(d_res.heal_item_type); - } else { - bgseq.count_failed(d_res.heal_item_type); + Err(err) => d_err = Some(err), + } + } else { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = lock.as_ref().expect("Not init"); + if task.object.is_empty() { + match store + .heal_object(&task.bucket, &task.object, &task.version_id, &task.opts) + .await + { + Ok((res, err)) => { + d_res = res; + d_err = err; } + Err(err) => d_err = Some(err), } - }, - None => return, + } else { + match store + .heal_object(&task.bucket, &task.object, &task.version_id, &task.opts) + .await + { + Ok((res, err)) => { + d_res = res; + d_err = err; + } + Err(err) => d_err = Some(err), + } + } + } + if let Some(resp_tx) = task.resp_tx { + let _ = resp_tx + .send(HealResult { + result: d_res, + _err: d_err, + }) + .await; + } else { + // when respCh is not set caller is not waiting but we + // update the relevant metrics for them + if d_err.is_none() { + bgseq.write().await.count_healed(d_res.heal_item_type); + } else { + bgseq.write().await.count_failed(d_res.heal_item_type); + } } } - _ = ctx.recv() => { - return; - } + None => return, } } } diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs index 0ad14e232..11d960943 100644 --- a/ecstore/src/heal/data_scanner.rs +++ b/ecstore/src/heal/data_scanner.rs @@ -34,7 +34,6 @@ use super::{ data_usage_cache::{DataUsageCache, DataUsageEntry, DataUsageHash}, heal_commands::{HealScanMode, HEAL_DEEP_SCAN, HEAL_NORMAL_SCAN}, }; -use crate::heal::data_scanner_metric::current_path_updater; use crate::heal::data_usage::DATA_USAGE_ROOT; use crate::{ cache_value::metacache_set::{list_path_raw, ListPathRawOptions}, @@ -54,15 +53,16 @@ use crate::{ }, new_object_layer_fn, peer::is_reserved_or_invalid_bucket, - store::{ECStore, ListPathOptions}, + store::ECStore, utils::path::{path_join, path_to_bucket_object, path_to_bucket_object_with_base_path, SLASH_SEPARATOR}, }; +use crate::{disk::local::LocalDisk, heal::data_scanner_metric::current_path_updater}; use crate::{ disk::DiskAPI, store_api::{FileInfo, ObjectInfo}, }; -const DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. +const _DATA_SCANNER_SLEEP_PER_FOLDER: Duration = Duration::from_millis(1); // Time to wait between folders. const DATA_USAGE_UPDATE_DIR_CYCLES: u32 = 16; // Visit all folders every n cycles. const DATA_SCANNER_COMPACT_LEAST_OBJECT: u64 = 500; // Compact when there are less than this many objects in a branch. const DATA_SCANNER_COMPACT_AT_CHILDREN: u64 = 10000; // Compact when there are this many children in a branch. @@ -70,12 +70,12 @@ const DATA_SCANNER_COMPACT_AT_FOLDERS: u64 = DATA_SCANNER_COMPACT_AT_CHILDREN / pub const DATA_SCANNER_FORCE_COMPACT_AT_FOLDERS: u64 = 250_000; // Compact when this many subfolders in a single folder (even top level). const DATA_SCANNER_START_DELAY: Duration = Duration::from_secs(60); // Time to wait on startup and between cycles. -const HEAL_DELETE_DANGLING: bool = true; +pub const HEAL_DELETE_DANGLING: bool = true; const HEAL_OBJECT_SELECT_PROB: u64 = 1024; // Overall probability of a file being scanned; one in n. // static SCANNER_SLEEPER: () = new_dynamic_sleeper(2, Duration::from_secs(1), true); // Keep defaults same as config defaults static SCANNER_CYCLE: AtomicU64 = AtomicU64::new(DATA_SCANNER_START_DELAY.as_secs()); -static SCANNER_IDLE_MODE: AtomicU32 = AtomicU32::new(0); // default is throttled when idle +static _SCANNER_IDLE_MODE: AtomicU32 = AtomicU32::new(0); // default is throttled when idle static SCANNER_EXCESS_OBJECT_VERSIONS: AtomicU64 = AtomicU64::new(100); static SCANNER_EXCESS_OBJECT_VERSIONS_TOTAL_SIZE: AtomicU64 = AtomicU64::new(1024 * 1024 * 1024 * 1024); // 1 TB static SCANNER_EXCESS_FOLDERS: AtomicU64 = AtomicU64::new(50_000); @@ -167,16 +167,18 @@ async fn run_data_scanner() { cycle_info.current = 0; cycle_info.cycle_completed.push(SystemTime::now()); if cycle_info.cycle_completed.len() > DATA_USAGE_UPDATE_DIR_CYCLES as usize { - cycle_info.cycle_completed = cycle_info.cycle_completed[cycle_info.cycle_completed.len() - DATA_USAGE_UPDATE_DIR_CYCLES as usize..].to_vec(); + cycle_info.cycle_completed = cycle_info.cycle_completed + [cycle_info.cycle_completed.len() - DATA_USAGE_UPDATE_DIR_CYCLES as usize..] + .to_vec(); } globalScannerMetrics.write().await.set_cycle(Some(cycle_info.clone())).await; let mut tmp = Vec::new(); tmp.write_u64::(cycle_info.next).unwrap(); let _ = save_config(store, &DATA_USAGE_BLOOM_NAME_PATH, &tmp).await; - }, + } Err(err) => { res.insert("error".to_string(), err.to_string()); - }, + } } stop_fn(&res).await; sleep(Duration::from_secs(SCANNER_CYCLE.load(std::sync::atomic::Ordering::SeqCst))).await; @@ -265,7 +267,7 @@ impl Default for CurrentScannerCycle { } impl CurrentScannerCycle { - pub fn marshal_msg(&self, buf: &[u8]) -> Result> { + pub fn marshal_msg(&self, next_buf: &[u8]) -> Result> { let len: u32 = 4; let mut wr = Vec::new(); @@ -291,7 +293,7 @@ impl CurrentScannerCycle { .serialize(&mut Serializer::new(&mut buf)) .expect("Serialization failed"); rmp::encode::write_bin(&mut wr, &buf)?; - let mut result = buf.to_vec(); + let mut result = next_buf.to_vec(); result.extend(wr.iter()); Ok(result) } @@ -355,7 +357,7 @@ fn timestamp_to_system_time(timestamp: u64) -> SystemTime { } #[derive(Clone, Debug, Default)] -struct Heal { +pub struct Heal { enabled: bool, bitrot: bool, } @@ -403,7 +405,12 @@ impl ScannerItem { cumulative_size += obj_info.size; } - if cumulative_size >= SCANNER_EXCESS_OBJECT_VERSIONS_TOTAL_SIZE.load(Ordering::SeqCst).try_into().unwrap() { + if cumulative_size + >= SCANNER_EXCESS_OBJECT_VERSIONS_TOTAL_SIZE + .load(Ordering::SeqCst) + .try_into() + .unwrap() + { //todo } @@ -421,7 +428,7 @@ impl ScannerItem { Ok(object_infos) } - pub async fn apply_actions(&self, oi: &ObjectInfo, size_s: &SizeSummary) -> (bool, usize) { + pub async fn apply_actions(&self, _oi: &ObjectInfo, _size_s: &SizeSummary) -> (bool, usize) { let done = ScannerMetrics::time(ScannerMetric::Ilm); //todo: lifecycle done().await; @@ -1014,7 +1021,7 @@ pub fn has_active_rules(config: &ReplicationConfiguration, prefix: &str, recursi false } -pub type LocalDrive = Arc; +pub type LocalDrive = Arc; pub async fn scan_data_folder( disks: &[Option], drive: LocalDrive, diff --git a/ecstore/src/heal/data_scanner_metric.rs b/ecstore/src/heal/data_scanner_metric.rs index 325beaa5c..8791726a4 100644 --- a/ecstore/src/heal/data_scanner_metric.rs +++ b/ecstore/src/heal/data_scanner_metric.rs @@ -79,8 +79,8 @@ impl Clone for LockedLastMinuteLatency { } impl LockedLastMinuteLatency { - pub fn add(&mut self, value: &Duration) { - self.add_size(value, 0); + pub async fn add(&mut self, value: &Duration) { + self.add_size(value, 0).await; } pub async fn add_size(&mut self, value: &Duration, sz: u64) { @@ -105,16 +105,16 @@ impl LockedLastMinuteLatency { a.size = old.size; a.total = old.total; a.n = old.n; - self.mu.write().await; + let _ = self.mu.write().await; self.latency.add_all(t - 1, &a); } self.cached.n += 1; self.cached.total += value.as_secs(); - self.cached.size != sz; + self.cached.size += sz; } pub async fn total(&mut self) -> AccElem { - self.mu.read().await; + let _ = self.mu.read().await; self.latency.get_total() } } @@ -147,19 +147,19 @@ impl ScannerMetrics { pub fn log(s: ScannerMetric) -> LogFn { let start = SystemTime::now(); let s_clone = s as usize; - Arc::new(move |custom: &HashMap| { + Arc::new(move |_custom: &HashMap| { Box::pin(async move { let duration = SystemTime::now().duration_since(start).unwrap_or(Duration::from_secs(0)); let mut sm_w = globalScannerMetrics.write().await; sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); if s_clone < ScannerMetric::LastRealtime as usize { - sm_w.latency[s_clone].add(&duration); + sm_w.latency[s_clone].add(&duration).await; } }) }) } - pub fn time_size(s: ScannerMetric) -> TimeSizeFn { + pub async fn time_size(s: ScannerMetric) -> TimeSizeFn { let start = SystemTime::now(); let s_clone = s as usize; Arc::new(move |sz: u64| { @@ -168,7 +168,7 @@ impl ScannerMetrics { let mut sm_w = globalScannerMetrics.write().await; sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); if s_clone < ScannerMetric::LastRealtime as usize { - sm_w.latency[s_clone].add_size(&duration, sz); + sm_w.latency[s_clone].add_size(&duration, sz).await; } }) }) @@ -183,7 +183,7 @@ impl ScannerMetrics { let mut sm_w = globalScannerMetrics.write().await; sm_w.operations[s_clone].fetch_add(1, Ordering::SeqCst); if s_clone < ScannerMetric::LastRealtime as usize { - sm_w.latency[s_clone].add(&duration); + sm_w.latency[s_clone].add(&duration).await; } }) }) @@ -191,7 +191,7 @@ impl ScannerMetrics { } pub type CloseDiskFn = Arc Pin + Send>> + Send + Sync + 'static>; -pub fn current_path_updater(disk: &str, initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) { +pub fn current_path_updater(disk: &str, _initial: &str) -> (UpdateCurrentPathFn, CloseDiskFn) { let disk_1 = disk.to_string(); let disk_2 = disk.to_string(); ( diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs index 9da7b6351..4731eedf4 100644 --- a/ecstore/src/heal/data_usage_cache.rs +++ b/ecstore/src/heal/data_usage_cache.rs @@ -5,7 +5,6 @@ use crate::error::{Error, Result}; use crate::new_object_layer_fn; use crate::set_disk::SetDisks; use crate::store_api::{BucketInfo, HTTPRangeSpec, ObjectIO, ObjectOptions}; -use bytes::Bytes; use bytesize::ByteSize; use http::HeaderMap; use path_clean::PathClean; @@ -17,7 +16,6 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, HashSet}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::Path; -use std::sync::Arc; use std::time::{Duration, SystemTime}; use std::u64; use tokio::sync::mpsc::Sender; @@ -761,15 +759,18 @@ impl DataUsageCache { bui.replica_count = rs.replica_count; for (arn, stat) in rs.targets.iter() { - bui.replication_info.insert(arn.clone(), BucketTargetUsageInfo { - replication_pending_size: stat.pending_size, - replicated_size: stat.replicated_size, - replication_failed_size: stat.failed_size, - replication_pending_count: stat.pending_count, - replication_failed_count: stat.failed_count, - replicated_count: stat.replicated_count, - ..Default::default() - }); + bui.replication_info.insert( + arn.clone(), + BucketTargetUsageInfo { + replication_pending_size: stat.pending_size, + replicated_size: stat.replicated_size, + replication_failed_size: stat.failed_size, + replication_pending_count: stat.pending_count, + replication_failed_count: stat.failed_count, + replicated_count: stat.replicated_count, + ..Default::default() + }, + ); } } dst.insert(bucket.name.clone(), bui); diff --git a/ecstore/src/heal/heal_commands.rs b/ecstore/src/heal/heal_commands.rs index 7c3df3495..8417c8b67 100644 --- a/ecstore/src/heal/heal_commands.rs +++ b/ecstore/src/heal/heal_commands.rs @@ -75,11 +75,21 @@ pub struct HealResultItem { pub object_size: usize, } -#[derive(Debug, Default, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize)] pub struct HealStartSuccess { pub client_token: String, pub client_address: String, - pub start_time: u64, + pub start_time: SystemTime, +} + +impl Default for HealStartSuccess { + fn default() -> Self { + Self { + client_token: Default::default(), + client_address: Default::default(), + start_time: SystemTime::now(), + } + } } pub type HealStopSuccess = HealStartSuccess; diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 6c1e716f1..36f35dc54 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -3,7 +3,7 @@ use crate::{ endpoints::Endpoints, error::{Error, Result}, global::GLOBAL_IsDistErasure, - heal::heal_commands::HEAL_UNKNOWN_SCAN, + heal::heal_commands::{HealStartSuccess, HEAL_UNKNOWN_SCAN}, utils::path::has_profix, }; use lazy_static::lazy_static; @@ -28,6 +28,7 @@ use uuid::Uuid; use super::{ background_heal_ops::HealTask, + data_scanner::HEAL_DELETE_DANGLING, heal_commands::{HealItemType, HealOpts, HealResultItem, HealScanMode, HealStopSuccess, HealingDisk, HealingTracker}, }; @@ -45,6 +46,10 @@ const HEAL_RUNNING_STATUS: &str = "running"; const HEAL_STOPPED_STATUS: &str = "stopped"; const HEAL_FINISHED_STATUS: &str = "finished"; +pub const RUESTFS_RESERVED_BUCKET: &str = "rustfs"; +pub const RUESTFS_RESERVED_BUCKET_PATH: &str = "/rustfs"; +pub const LOGIN_PATH_PREFIX: &str = "/login"; + const MAX_UNCONSUMED_HEAL_RESULT_ITEMS: usize = 1000; const HEAL_UNCONSUMED_TIMEOUT: std::time::Duration = Duration::from_secs(24 * 60 * 60); pub const NOP_HEAL: &str = ""; @@ -74,8 +79,8 @@ pub struct HealSequence { pub bucket: String, pub object: String, pub report_progress: bool, - pub start_time: u64, - pub end_time: Arc>, + pub start_time: SystemTime, + pub end_time: Arc>, pub client_token: String, pub client_address: String, pub force_started: bool, @@ -94,6 +99,30 @@ pub struct HealSequence { rx: Arc>>, } +pub fn new_bg_heal_sequence() -> HealSequence { + let hs = HealOpts { + remove: HEAL_DELETE_DANGLING, + ..Default::default() + }; + + HealSequence { + start_time: SystemTime::now(), + client_token: BG_HEALING_UUID.to_string(), + bucket: RUESTFS_RESERVED_BUCKET.to_string(), + setting: hs, + current_status: Arc::new(RwLock::new(HealSequenceStatus { + summary: HEAL_NOT_STARTED_STATUS.to_string(), + heal_setting: hs, + ..Default::default() + })), + report_progress: false, + scanned_items_map: HashMap::new(), + healed_items_map: HashMap::new(), + heal_failed_items_map: HashMap::new(), + ..Default::default() + } +} + impl Default for HealSequence { fn default() -> Self { let (h_tx, h_rx) = mpsc::channel(1); @@ -102,8 +131,8 @@ impl Default for HealSequence { bucket: Default::default(), object: Default::default(), report_progress: Default::default(), - start_time: Default::default(), - end_time: Default::default(), + start_time: SystemTime::now(), + end_time: Arc::new(RwLock::new(SystemTime::now())), client_token: Default::default(), client_address: Default::default(), force_started: Default::default(), @@ -289,9 +318,10 @@ impl HealSequence { } } -pub async fn heal_sequence_start(h: Arc) { +pub async fn heal_sequence_start(h: Arc>) { + let r = h.read().await; { - let mut current_status_w = h.current_status.write().await; + let mut current_status_w = r.current_status.write().await; (*current_status_w).summary = HEAL_RUNNING_STATUS.to_string(); (*current_status_w).start_time = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -301,22 +331,20 @@ pub async fn heal_sequence_start(h: Arc) { let h_clone = h.clone(); spawn(async move { - h_clone.traverse_and_heal().await; + h_clone.read().await.traverse_and_heal().await; }); let h_clone_1 = h.clone(); - let mut x = h.traverse_and_heal_done_rx.write().await; + let mut x = r.traverse_and_heal_done_rx.write().await; select! { - _ = h.is_done() => { - *(h.end_time.write().await) = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_secs(); - let mut current_status_w = h.current_status.write().await; + _ = r.is_done() => { + *(r.end_time.write().await) = SystemTime::now(); + let mut current_status_w = r.current_status.write().await; (*current_status_w).summary = HEAL_FINISHED_STATUS.to_string(); spawn(async move { - let mut rx_w = h_clone_1.traverse_and_heal_done_rx.write().await; + let binding = h_clone_1.read().await; + let mut rx_w = binding.traverse_and_heal_done_rx.write().await; rx_w.recv().await; }); } @@ -325,12 +353,12 @@ pub async fn heal_sequence_start(h: Arc) { Some(err) => { match err { Some(err) => { - let mut current_status_w = h.current_status.write().await; + let mut current_status_w = r.current_status.write().await; (current_status_w).summary = HEAL_STOPPED_STATUS.to_string(); (current_status_w).failure_detail = err.to_string(); }, None => { - let mut current_status_w = h.current_status.write().await; + let mut current_status_w = r.current_status.write().await; (current_status_w).summary = HEAL_FINISHED_STATUS.to_string(); } } @@ -429,13 +457,13 @@ impl AllHealState { Endpoints::from(endpoints) } - async fn set_disk_healing_status(&mut self, ep: Endpoint, healing: bool) { + pub async fn set_disk_healing_status(&mut self, ep: Endpoint, healing: bool) { let _ = self.mu.write().await; self.heal_local_disks.insert(ep, healing); } - async fn push_heal_local_disks(&mut self, heal_local_disks: &[Endpoint]) { + pub async fn push_heal_local_disks(&mut self, heal_local_disks: &[Endpoint]) { let _ = self.mu.write().await; heal_local_disks.iter().for_each(|heal_local_disk| { @@ -450,9 +478,7 @@ impl AllHealState { let mut keys_to_reomve = Vec::new(); for (k, v) in self.heal_seq_map.iter() { let r = v.read().await; - if r.has_ended().await - && (UNIX_EPOCH + Duration::from_secs(*(r.end_time.read().await)) + KEEP_HEAL_SEQ_STATE_DURATION) < now - { + if r.has_ended().await && now.duration_since(*(r.end_time.read().await)).unwrap() > KEEP_HEAL_SEQ_STATE_DURATION { keys_to_reomve.push(k.clone()) } } @@ -523,15 +549,16 @@ impl AllHealState { // `keepHealSeqStateDuration`. This function also launches a // background routine to clean up heal results after the // aforementioned duration. - pub async fn launch_new_heal_sequence(&mut self, heal_sequence: &HealSequence) -> Result> { - let path = Path::new(&heal_sequence.bucket).join(heal_sequence.object.clone()); + pub async fn launch_new_heal_sequence(&mut self, heal_sequence: Arc>) -> Result> { + let r = heal_sequence.read().await; + let path = Path::new(&r.bucket).join(r.object.clone()); let path_s = path.to_str().unwrap(); - if heal_sequence.force_started { + if r.force_started { self.stop_heal_sequence(path_s).await?; } else { if let Some(hs) = self.get_heal_sequence(path_s).await { if !hs.read().await.has_ended().await { - return Err(Error::from_string(format!("Heal is already running on the given path (use force-start option to stop and start afresh). The heal was started by IP {} at {}, token is {}", heal_sequence.client_address, heal_sequence.start_time, heal_sequence.client_token))); + return Err(Error::from_string(format!("Heal is already running on the given path (use force-start option to stop and start afresh). The heal was started by IP {} at {:?}, token is {}", r.client_address, r.start_time, r.client_token))); } } } @@ -547,17 +574,27 @@ impl AllHealState { } } - self.heal_seq_map - .insert(path_s.to_string(), Arc::new(RwLock::new(heal_sequence.clone()))); + self.heal_seq_map.insert(path_s.to_string(), heal_sequence.clone()); - let client_token = heal_sequence.client_token.clone(); + let client_token = r.client_token.clone(); if *GLOBAL_IsDistErasure.read().await { // TODO: proxy } - if heal_sequence.client_token == BG_HEALING_UUID { + if r.client_token == BG_HEALING_UUID { // For background heal do nothing, do not spawn an unnecessary goroutine. + } else { + let heal_sequence_clone = heal_sequence.clone(); + tokio::spawn(async { + heal_sequence_start(heal_sequence_clone).await; + }); } - todo!() + + let b = serde_json::to_vec(&HealStartSuccess { + client_token, + client_address: r.client_address.clone(), + start_time: r.start_time, + })?; + Ok(b) } } diff --git a/ecstore/src/sets.rs b/ecstore/src/sets.rs index 2fb852f47..7b88d9e4c 100644 --- a/ecstore/src/sets.rs +++ b/ecstore/src/sets.rs @@ -483,7 +483,7 @@ impl StorageAPI for Sets { .complete_multipart_upload(bucket, object, upload_id, uploaded_parts, opts) .await } - async fn get_disks(&self, pool_idx: usize, set_idx: usize) -> Result>> { + async fn get_disks(&self, _pool_idx: usize, _set_idx: usize) -> Result>> { unimplemented!() } @@ -535,8 +535,7 @@ impl StorageAPI for Sets { } let format_op_id = Uuid::new_v4().to_string(); - let (new_format_sets, current_disks_info) = - new_heal_format_sets(&ref_format, self.set_count, self.set_drive_count, &formats, &errs); + let (new_format_sets, _) = new_heal_format_sets(&ref_format, self.set_count, self.set_drive_count, &formats, &errs); if !dry_run { let mut tmp_new_formats = vec![None; self.set_count * self.set_drive_count]; for (i, set) in new_format_sets.iter().enumerate() { @@ -578,7 +577,7 @@ impl StorageAPI for Sets { } Ok((res, None)) } - async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + async fn heal_bucket(&self, _bucket: &str, _opts: &HealOpts) -> Result { unimplemented!() } async fn heal_object( @@ -592,18 +591,18 @@ impl StorageAPI for Sets { .heal_object(bucket, object, version_id, opts) .await } - async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()> { + async fn heal_objects(&self, _bucket: &str, _prefix: &str, _opts: &HealOpts, _func: HealObjectFn) -> Result<()> { unimplemented!() } - async fn get_pool_and_set(&self, id: &str) -> Result<(Option, Option, Option)> { + async fn get_pool_and_set(&self, _id: &str) -> Result<(Option, Option, Option)> { unimplemented!() } - async fn check_abandoned_parts(&self, bucket: &str, object: &str, opts: &HealOpts) -> Result<()> { + async fn check_abandoned_parts(&self, _bucket: &str, _object: &str, _opts: &HealOpts) -> Result<()> { unimplemented!() } } -async fn close_storage_disks(disks: &[Option]) { +async fn _close_storage_disks(disks: &[Option]) { let mut futures = Vec::with_capacity(disks.len()); for disk in disks.iter() { if let Some(disk) = disk { @@ -652,7 +651,7 @@ fn formats_to_drives_info(endpoints: &Endpoints, formats: &[Option], e let mut before_drives = Vec::with_capacity(endpoints.as_ref().len()); for (index, format) in formats.iter().enumerate() { let drive = endpoints.get_string(index); - let mut state = if format.is_some() { + let state = if format.is_some() { DRIVE_STATE_OK } else { if let Some(Some(err)) = errs.get(index) { @@ -689,7 +688,7 @@ fn new_heal_format_sets( let mut new_formats = vec![vec![None; set_drive_count]; set_count]; let mut current_disks_info = vec![vec![DiskInfo::default(); set_drive_count]; set_count]; for (i, set) in ref_format.erasure.sets.iter().enumerate() { - for (j, value) in set.iter().enumerate() { + for j in 0..set.len() { if let Some(Some(err)) = errs.get(i * set_drive_count + j) { match err.downcast_ref::() { Some(DiskError::UnformattedDisk) => { diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index 3d0ddcaca..f6bb937df 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -1,6 +1,5 @@ #![allow(clippy::map_entry)] -use crate::bucket::metadata; use crate::bucket::metadata_sys::{self, init_bucket_metadata_sys, set_bucket_metadata}; use crate::bucket::utils::{check_valid_bucket_name, check_valid_bucket_name_strict, is_meta_bucketname}; use crate::config::{self, storageclass, GLOBAL_ConfigSys}; @@ -44,7 +43,6 @@ use http::HeaderMap; use lazy_static::lazy_static; use rand::Rng; use s3s::dto::{BucketVersioningStatus, ObjectLockConfiguration, ObjectLockEnabled, VersioningConfiguration}; -use tokio::time::interval; use std::cmp::Ordering; use std::slice::Iter; use std::time::SystemTime; @@ -54,12 +52,13 @@ use std::{ time::Duration, }; use time::OffsetDateTime; -use tokio::{fs, select}; use tokio::sync::mpsc::Sender; use tokio::sync::{broadcast, mpsc, RwLock, Semaphore}; +use tokio::time::interval; +use tokio::{fs, select}; use crate::heal::data_usage_cache::{DataUsageCache, DataUsageCacheInfo}; -use tracing::{debug, info, warn}; +use tracing::{debug, info}; use uuid::Uuid; const MAX_UPLOADS_LIST: usize = 10000; @@ -510,7 +509,7 @@ impl ECStore { self.pools.iter().for_each(|pool| { total_results += pool.disk_set.len(); }); - let mut results = Arc::new(RwLock::new(vec![DataUsageCache::default(); total_results])); + let results = Arc::new(RwLock::new(vec![DataUsageCache::default(); total_results])); let (cancel, _) = broadcast::channel(100); let first_err = Arc::new(RwLock::new(None)); let mut futures = Vec::new(); @@ -535,13 +534,16 @@ impl ECStore { } } }); - if let Err(err) = set.ns_scanner(&all_buckets_clone, want_cycle.try_into().unwrap(), tx, heal_scan_mode).await { + if let Err(err) = set + .ns_scanner(&all_buckets_clone, want_cycle.try_into().unwrap(), tx, heal_scan_mode) + .await + { let mut f_w = first_err_clone.write().await; if f_w.is_none() { *f_w = Some(err); } let _ = cancel_clone.send(true); - return ; + return; } let _ = task.await; }); @@ -583,7 +585,7 @@ impl ECStore { } _ = ctx_closer.recv() => { - + } } let _ = task.await; @@ -688,7 +690,13 @@ impl ECStore { } } -async fn update_scan(all_merged: Arc>, results: Arc>>, last_update: Option, all_buckets: Vec, updates: Sender) -> Option { +async fn update_scan( + all_merged: Arc>, + results: Arc>>, + last_update: Option, + all_buckets: Vec, + updates: Sender, +) -> Option { let mut w = all_merged.write().await; *w = DataUsageCache { info: DataUsageCacheInfo { @@ -1527,7 +1535,7 @@ impl StorageAPI for ECStore { Ok((r, None)) } - async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + async fn heal_bucket(&self, _bucket: &str, _opts: &HealOpts) -> Result { unimplemented!() } async fn heal_object( diff --git a/rustfs/src/grpc.rs b/rustfs/src/grpc.rs index c17f67e67..55884c9d2 100644 --- a/rustfs/src/grpc.rs +++ b/rustfs/src/grpc.rs @@ -6,6 +6,7 @@ use ecstore::{ UpdateMetadataOpts, WalkDirOptions, }, erasure::Writer, + heal::data_usage_cache::DataUsageCache, peer::{LocalPeerS3Client, PeerS3Client}, store::{all_local_disk_path, find_local_disk}, store_api::{BucketOptions, DeleteBucketOptions, FileInfo, MakeBucketOptions}, @@ -22,12 +23,12 @@ use protos::{ DiskInfoRequest, DiskInfoResponse, GenerallyLockRequest, GenerallyLockResponse, GetBucketInfoRequest, GetBucketInfoResponse, ListBucketRequest, ListBucketResponse, ListDirRequest, ListDirResponse, ListVolumesRequest, ListVolumesResponse, MakeBucketRequest, MakeBucketResponse, MakeVolumeRequest, MakeVolumeResponse, MakeVolumesRequest, - MakeVolumesResponse, PingRequest, PingResponse, ReadAllRequest, ReadAllResponse, ReadAtRequest, ReadAtResponse, - ReadMultipleRequest, ReadMultipleResponse, ReadVersionRequest, ReadVersionResponse, ReadXlRequest, ReadXlResponse, - RenameDataRequest, RenameDataResponse, RenameFileRequst, RenameFileResponse, RenamePartRequst, RenamePartResponse, - StatVolumeRequest, StatVolumeResponse, UpdateMetadataRequest, UpdateMetadataResponse, VerifyFileRequest, - VerifyFileResponse, WalkDirRequest, WalkDirResponse, WriteAllRequest, WriteAllResponse, WriteMetadataRequest, - WriteMetadataResponse, WriteRequest, WriteResponse, + MakeVolumesResponse, NsScannerRequest, NsScannerResponse, PingRequest, PingResponse, ReadAllRequest, ReadAllResponse, + ReadAtRequest, ReadAtResponse, ReadMultipleRequest, ReadMultipleResponse, ReadVersionRequest, ReadVersionResponse, + ReadXlRequest, ReadXlResponse, RenameDataRequest, RenameDataResponse, RenameFileRequst, RenameFileResponse, + RenamePartRequst, RenamePartResponse, StatVolumeRequest, StatVolumeResponse, UpdateMetadataRequest, + UpdateMetadataResponse, VerifyFileRequest, VerifyFileResponse, WalkDirRequest, WalkDirResponse, WriteAllRequest, + WriteAllResponse, WriteMetadataRequest, WriteMetadataResponse, WriteRequest, WriteResponse, }, }; use tokio::sync::mpsc; @@ -1270,6 +1271,96 @@ impl Node for NodeService { } } + type NsScannerStream = ResponseStream; + async fn ns_scanner(&self, request: Request>) -> Result, Status> { + info!("ns_scanner"); + + let mut in_stream = request.into_inner(); + let (tx, rx) = mpsc::channel(10); + + tokio::spawn(async move { + match in_stream.next().await { + Some(Ok(request)) => { + if let Some(disk) = find_local_disk(&request.disk).await { + let cache = match serde_json::from_str::(&request.cache) { + Ok(cache) => cache, + Err(_) => { + tx.send(Ok(NsScannerResponse { + success: false, + update: "".to_string(), + data_usage_cache: "".to_string(), + error_info: Some("can not decode DataUsageCache".to_string()), + })) + .await + .expect("working rx"); + return; + } + }; + let (updates_tx, mut updates_rx) = mpsc::channel(100); + let tx_clone = tx.clone(); + let task = tokio::spawn(async move { + loop { + match updates_rx.recv().await { + Some(update) => { + let update = serde_json::to_string(&update).expect("encode failed"); + tx_clone + .send(Ok(NsScannerResponse { + success: true, + update, + data_usage_cache: "".to_string(), + error_info: Some("can not decode DataUsageCache".to_string()), + })) + .await + .expect("working rx"); + } + None => return, + } + } + }); + let data_usage_cache = disk.ns_scanner(&cache, updates_tx, request.scan_mode as usize).await; + let _ = task.await; + match data_usage_cache { + Ok(data_usage_cache) => { + let data_usage_cache = serde_json::to_string(&data_usage_cache).expect("encode failed"); + tx.send(Ok(NsScannerResponse { + success: true, + update: "".to_string(), + data_usage_cache, + error_info: Some("can not decode DataUsageCache".to_string()), + })) + .await + .expect("working rx"); + } + Err(_) => { + tx.send(Ok(NsScannerResponse { + success: false, + update: "".to_string(), + data_usage_cache: "".to_string(), + error_info: Some("scanner failed".to_string()), + })) + .await + .expect("working rx"); + } + } + } else { + tx.send(Ok(NsScannerResponse { + success: false, + update: "".to_string(), + data_usage_cache: "".to_string(), + error_info: Some("can not find disk".to_string()), + })) + .await + .expect("working rx"); + } + } + _ => todo!(), + } + }); + + let out_stream = ReceiverStream::new(rx); + Ok(tonic::Response::new(Box::pin(out_stream))) + } + async fn lock(&self, request: Request) -> Result, Status> { let request = request.into_inner(); match &serde_json::from_str::(&request.args) { diff --git a/rustfs/src/main.rs b/rustfs/src/main.rs index 975d4c9b4..361982c34 100644 --- a/rustfs/src/main.rs +++ b/rustfs/src/main.rs @@ -6,12 +6,10 @@ mod storage; use clap::Parser; use common::error::{Error, Result}; use ecstore::{ - bucket::metadata_sys::init_bucket_metadata_sys, endpoints::EndpointServerPools, heal::data_scanner::init_data_scanner, set_global_endpoints, store::{init_local_disks, ECStore}, - store_api::{BucketOptions, StorageAPI}, update_erasure_type, }; use grpc::make_server; From 6291087ecba6ef9a16605295cbbb20c208a1312c Mon Sep 17 00:00:00 2001 From: junxiang Mu <1948535941@qq.com> Date: Sun, 17 Nov 2024 18:34:29 +0800 Subject: [PATCH 07/11] auto heal(2) Signed-off-by: junxiang Mu <1948535941@qq.com> --- .../generated/flatbuffers_generated/models.rs | 207 +- .../src/generated/proto_gen/node_service.rs | 1926 +++++++++++++---- ecstore/src/config/mod.rs | 2 + ecstore/src/disk/endpoint.rs | 3 +- ecstore/src/disk/local.rs | 27 +- ecstore/src/disk/mod.rs | 12 +- ecstore/src/disk/remote.rs | 6 +- ecstore/src/endpoints.rs | 8 + ecstore/src/heal/background_heal_ops.rs | 167 +- ecstore/src/heal/heal_commands.rs | 7 +- ecstore/src/heal/heal_ops.rs | 12 +- ecstore/src/store.rs | 10 +- 12 files changed, 1855 insertions(+), 532 deletions(-) diff --git a/common/protos/src/generated/flatbuffers_generated/models.rs b/common/protos/src/generated/flatbuffers_generated/models.rs index e4949fdcf..aa1f6ae2f 100644 --- a/common/protos/src/generated/flatbuffers_generated/models.rs +++ b/common/protos/src/generated/flatbuffers_generated/models.rs @@ -1,9 +1,10 @@ // automatically generated by the FlatBuffers compiler, do not modify + // @generated -use core::cmp::Ordering; use core::mem; +use core::cmp::Ordering; extern crate flatbuffers; use self::flatbuffers::{EndianScalar, Follow}; @@ -11,114 +12,112 @@ use self::flatbuffers::{EndianScalar, Follow}; #[allow(unused_imports, dead_code)] pub mod models { - use core::cmp::Ordering; - use core::mem; + use core::mem; + use core::cmp::Ordering; - extern crate flatbuffers; - use self::flatbuffers::{EndianScalar, Follow}; + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; - pub enum PingBodyOffset {} - #[derive(Copy, Clone, PartialEq)] +pub enum PingBodyOffset {} +#[derive(Copy, Clone, PartialEq)] - pub struct PingBody<'a> { - pub _tab: flatbuffers::Table<'a>, +pub struct PingBody<'a> { + pub _tab: flatbuffers::Table<'a>, +} + +impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { + type Inner = PingBody<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { _tab: flatbuffers::Table::new(buf, loc) } + } +} + +impl<'a> PingBody<'a> { + pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; + + pub const fn get_fully_qualified_name() -> &'static str { + "models.PingBody" + } + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + PingBody { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args PingBodyArgs<'args> + ) -> flatbuffers::WIPOffset> { + let mut builder = PingBodyBuilder::new(_fbb); + if let Some(x) = args.payload { builder.add_payload(x); } + builder.finish() + } + + + #[inline] + pub fn payload(&self) -> Option> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { self._tab.get::>>(PingBody::VT_PAYLOAD, None)} + } +} + +impl flatbuffers::Verifiable for PingBody<'_> { + #[inline] + fn run_verifier( + v: &mut flatbuffers::Verifier, pos: usize + ) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>("payload", Self::VT_PAYLOAD, false)? + .finish(); + Ok(()) + } +} +pub struct PingBodyArgs<'a> { + pub payload: Option>>, +} +impl<'a> Default for PingBodyArgs<'a> { + #[inline] + fn default() -> Self { + PingBodyArgs { + payload: None, } + } +} - impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { - type Inner = PingBody<'a>; - #[inline] - unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { - _tab: flatbuffers::Table::new(buf, loc), - } - } +pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, +} +impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { + #[inline] + pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { + self.fbb_.push_slot_always::>(PingBody::VT_PAYLOAD, payload); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + PingBodyBuilder { + fbb_: _fbb, + start_: start, } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } +} - impl<'a> PingBody<'a> { - pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; +impl core::fmt::Debug for PingBody<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("PingBody"); + ds.field("payload", &self.payload()); + ds.finish() + } +} +} // pub mod models - pub const fn get_fully_qualified_name() -> &'static str { - "models.PingBody" - } - - #[inline] - pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - PingBody { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, - args: &'args PingBodyArgs<'args>, - ) -> flatbuffers::WIPOffset> { - let mut builder = PingBodyBuilder::new(_fbb); - if let Some(x) = args.payload { - builder.add_payload(x); - } - builder.finish() - } - - #[inline] - pub fn payload(&self) -> Option> { - // Safety: - // Created from valid Table for this object - // which contains a valid value in this slot - unsafe { - self._tab - .get::>>(PingBody::VT_PAYLOAD, None) - } - } - } - - impl flatbuffers::Verifiable for PingBody<'_> { - #[inline] - fn run_verifier(v: &mut flatbuffers::Verifier, pos: usize) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>>("payload", Self::VT_PAYLOAD, false)? - .finish(); - Ok(()) - } - } - pub struct PingBodyArgs<'a> { - pub payload: Option>>, - } - impl<'a> Default for PingBodyArgs<'a> { - #[inline] - fn default() -> Self { - PingBodyArgs { payload: None } - } - } - - pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - start_: flatbuffers::WIPOffset, - } - impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { - #[inline] - pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { - self.fbb_ - .push_slot_always::>(PingBody::VT_PAYLOAD, payload); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { - let start = _fbb.start_table(); - PingBodyBuilder { - fbb_: _fbb, - start_: start, - } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } - } - - impl core::fmt::Debug for PingBody<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut ds = f.debug_struct("PingBody"); - ds.field("payload", &self.payload()); - ds.finish() - } - } -} // pub mod models diff --git a/common/protos/src/generated/proto_gen/node_service.rs b/common/protos/src/generated/proto_gen/node_service.rs index 7c7d31a57..26ba50955 100644 --- a/common/protos/src/generated/proto_gen/node_service.rs +++ b/common/protos/src/generated/proto_gen/node_service.rs @@ -600,9 +600,15 @@ pub struct GenerallyLockResponse { } /// Generated client implementations. pub mod node_service_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] - use tonic::codegen::http::Uri; + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; + use tonic::codegen::http::Uri; #[derive(Debug, Clone)] pub struct NodeServiceClient { inner: tonic::client::Grpc, @@ -633,16 +639,22 @@ pub mod node_service_client { let inner = tonic::client::Grpc::with_origin(inner, origin); Self { inner } } - pub fn with_interceptor(inner: T, interceptor: F) -> NodeServiceClient> + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> NodeServiceClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, - Response = http::Response<>::ResponseBody>, + Response = http::Response< + >::ResponseBody, + >, >, - >>::Error: - Into + std::marker::Send + std::marker::Sync, + , + >>::Error: Into + std::marker::Send + std::marker::Sync, { NodeServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -685,9 +697,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Ping"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Ping", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Ping")); @@ -696,13 +714,22 @@ pub mod node_service_client { pub async fn list_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListBucket")); @@ -711,13 +738,22 @@ pub mod node_service_client { pub async fn make_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeBucket")); @@ -726,13 +762,22 @@ pub mod node_service_client { pub async fn get_bucket_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/GetBucketInfo"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/GetBucketInfo", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "GetBucketInfo")); @@ -741,13 +786,22 @@ pub mod node_service_client { pub async fn delete_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteBucket"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteBucket", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteBucket")); @@ -756,13 +810,22 @@ pub mod node_service_client { pub async fn read_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAll"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadAll", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAll")); @@ -771,13 +834,22 @@ pub mod node_service_client { pub async fn write_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteAll"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteAll", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteAll")); @@ -790,9 +862,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Delete"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Delete", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Delete")); @@ -801,13 +879,22 @@ pub mod node_service_client { pub async fn verify_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/VerifyFile"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/VerifyFile", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "VerifyFile")); @@ -816,13 +903,22 @@ pub mod node_service_client { pub async fn check_parts( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/CheckParts"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/CheckParts", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "CheckParts")); @@ -831,13 +927,22 @@ pub mod node_service_client { pub async fn rename_part( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenamePart"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenamePart", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenamePart")); @@ -846,13 +951,22 @@ pub mod node_service_client { pub async fn rename_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameFile"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenameFile", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameFile")); @@ -865,9 +979,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Write"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Write", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Write")); @@ -876,13 +996,22 @@ pub mod node_service_client { pub async fn write_stream( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result>, tonic::Status> { + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteStream"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteStream", + ); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteStream")); @@ -892,13 +1021,22 @@ pub mod node_service_client { pub async fn read_at( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result>, tonic::Status> { + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAt"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadAt", + ); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAt")); @@ -907,13 +1045,22 @@ pub mod node_service_client { pub async fn list_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListDir"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListDir", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListDir")); @@ -922,13 +1069,22 @@ pub mod node_service_client { pub async fn walk_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WalkDir"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WalkDir", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WalkDir")); @@ -937,13 +1093,22 @@ pub mod node_service_client { pub async fn rename_data( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameData"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RenameData", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameData")); @@ -952,13 +1117,22 @@ pub mod node_service_client { pub async fn make_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolumes"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeVolumes", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolumes")); @@ -967,13 +1141,22 @@ pub mod node_service_client { pub async fn make_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/MakeVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolume")); @@ -982,13 +1165,22 @@ pub mod node_service_client { pub async fn list_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListVolumes"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ListVolumes", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListVolumes")); @@ -997,13 +1189,22 @@ pub mod node_service_client { pub async fn stat_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/StatVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/StatVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "StatVolume")); @@ -1012,13 +1213,22 @@ pub mod node_service_client { pub async fn delete_paths( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeletePaths"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeletePaths", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeletePaths")); @@ -1027,13 +1237,22 @@ pub mod node_service_client { pub async fn update_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UpdateMetadata"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/UpdateMetadata", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UpdateMetadata")); @@ -1042,13 +1261,22 @@ pub mod node_service_client { pub async fn write_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteMetadata"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/WriteMetadata", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteMetadata")); @@ -1057,13 +1285,22 @@ pub mod node_service_client { pub async fn read_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadVersion"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadVersion", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadVersion")); @@ -1076,9 +1313,15 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadXL"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadXL", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadXL")); @@ -1087,13 +1330,22 @@ pub mod node_service_client { pub async fn delete_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersion"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVersion", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersion")); @@ -1102,13 +1354,22 @@ pub mod node_service_client { pub async fn delete_versions( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersions"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVersions", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersions")); @@ -1117,13 +1378,22 @@ pub mod node_service_client { pub async fn read_multiple( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadMultiple"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ReadMultiple", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadMultiple")); @@ -1132,13 +1402,22 @@ pub mod node_service_client { pub async fn delete_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVolume"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DeleteVolume", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVolume")); @@ -1147,13 +1426,22 @@ pub mod node_service_client { pub async fn disk_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DiskInfo"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/DiskInfo", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DiskInfo")); @@ -1162,13 +1450,22 @@ pub mod node_service_client { pub async fn ns_scanner( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result>, tonic::Status> { + ) -> std::result::Result< + tonic::Response>, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/NsScanner"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/NsScanner", + ); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "NsScanner")); @@ -1177,13 +1474,22 @@ pub mod node_service_client { pub async fn lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Lock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Lock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Lock")); @@ -1192,13 +1498,22 @@ pub mod node_service_client { pub async fn un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/UnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UnLock")); @@ -1207,13 +1522,22 @@ pub mod node_service_client { pub async fn r_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RLock")); @@ -1222,13 +1546,22 @@ pub mod node_service_client { pub async fn r_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RUnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/RUnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RUnLock")); @@ -1237,13 +1570,22 @@ pub mod node_service_client { pub async fn force_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ForceUnLock"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/ForceUnLock", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ForceUnLock")); @@ -1252,13 +1594,22 @@ pub mod node_service_client { pub async fn refresh( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { self.inner .ready() .await - .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Refresh"); + let path = http::uri::PathAndQuery::from_static( + "/node_service.NodeService/Refresh", + ); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Refresh")); @@ -1268,7 +1619,13 @@ pub mod node_service_client { } /// Generated server implementations. pub mod node_service_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] + #![allow( + unused_variables, + dead_code, + missing_docs, + clippy::wildcard_imports, + clippy::let_unit_value, + )] use tonic::codegen::*; /// Generated trait containing gRPC methods that should be implemented for use with NodeServiceServer. #[async_trait] @@ -1281,19 +1638,31 @@ pub mod node_service_server { async fn list_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn get_bucket_info( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_bucket( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_all( &self, request: tonic::Request, @@ -1301,7 +1670,10 @@ pub mod node_service_server { async fn write_all( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete( &self, request: tonic::Request, @@ -1309,33 +1681,52 @@ pub mod node_service_server { async fn verify_file( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn check_parts( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn rename_part( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn rename_file( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn write( &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the WriteStream method. - type WriteStreamStream: tonic::codegen::tokio_stream::Stream> + type WriteStreamStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + 'static; async fn write_stream( &self, request: tonic::Request>, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Server streaming response type for the ReadAt method. - type ReadAtStream: tonic::codegen::tokio_stream::Stream> + type ReadAtStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + 'static; /// rpc Append(AppendRequest) returns (AppendResponse) {}; @@ -1354,39 +1745,66 @@ pub mod node_service_server { async fn rename_data( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_volumes( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn make_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn list_volumes( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn stat_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_paths( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn update_metadata( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn write_metadata( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_version( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_xl( &self, request: tonic::Request, @@ -1394,25 +1812,42 @@ pub mod node_service_server { async fn delete_version( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_versions( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn read_multiple( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn delete_volume( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn disk_info( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Server streaming response type for the NsScanner method. - type NsScannerStream: tonic::codegen::tokio_stream::Stream> + type NsScannerStream: tonic::codegen::tokio_stream::Stream< + Item = std::result::Result, + > + std::marker::Send + 'static; async fn ns_scanner( @@ -1422,27 +1857,45 @@ pub mod node_service_server { async fn lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn r_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn r_un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn force_un_lock( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; async fn refresh( &self, request: tonic::Request, - ) -> std::result::Result, tonic::Status>; + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; } #[derive(Debug)] pub struct NodeServiceServer { @@ -1465,7 +1918,10 @@ pub mod node_service_server { max_encoding_message_size: None, } } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService where F: tonic::service::Interceptor, { @@ -1509,7 +1965,10 @@ pub mod node_service_server { type Response = http::Response; type Error = std::convert::Infallible; type Future = BoxFuture; - fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: http::Request) -> Self::Future { @@ -1517,12 +1976,21 @@ pub mod node_service_server { "/node_service.NodeService/Ping" => { #[allow(non_camel_case_types)] struct PingSvc(pub Arc); - impl tonic::server::UnaryService for PingSvc { + impl tonic::server::UnaryService + for PingSvc { type Response = super::PingResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::ping(&inner, request).await }; + let fut = async move { + ::ping(&inner, request).await + }; Box::pin(fut) } } @@ -1535,8 +2003,14 @@ pub mod node_service_server { let method = PingSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1545,12 +2019,23 @@ pub mod node_service_server { "/node_service.NodeService/ListBucket" => { #[allow(non_camel_case_types)] struct ListBucketSvc(pub Arc); - impl tonic::server::UnaryService for ListBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListBucketSvc { type Response = super::ListBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_bucket(&inner, request).await }; + let fut = async move { + ::list_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1563,8 +2048,14 @@ pub mod node_service_server { let method = ListBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1573,12 +2064,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeBucket" => { #[allow(non_camel_case_types)] struct MakeBucketSvc(pub Arc); - impl tonic::server::UnaryService for MakeBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeBucketSvc { type Response = super::MakeBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_bucket(&inner, request).await }; + let fut = async move { + ::make_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1591,8 +2093,14 @@ pub mod node_service_server { let method = MakeBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1601,12 +2109,23 @@ pub mod node_service_server { "/node_service.NodeService/GetBucketInfo" => { #[allow(non_camel_case_types)] struct GetBucketInfoSvc(pub Arc); - impl tonic::server::UnaryService for GetBucketInfoSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for GetBucketInfoSvc { type Response = super::GetBucketInfoResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::get_bucket_info(&inner, request).await }; + let fut = async move { + ::get_bucket_info(&inner, request).await + }; Box::pin(fut) } } @@ -1619,8 +2138,14 @@ pub mod node_service_server { let method = GetBucketInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1629,12 +2154,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteBucket" => { #[allow(non_camel_case_types)] struct DeleteBucketSvc(pub Arc); - impl tonic::server::UnaryService for DeleteBucketSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteBucketSvc { type Response = super::DeleteBucketResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_bucket(&inner, request).await }; + let fut = async move { + ::delete_bucket(&inner, request).await + }; Box::pin(fut) } } @@ -1647,8 +2183,14 @@ pub mod node_service_server { let method = DeleteBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1657,12 +2199,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadAll" => { #[allow(non_camel_case_types)] struct ReadAllSvc(pub Arc); - impl tonic::server::UnaryService for ReadAllSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadAllSvc { type Response = super::ReadAllResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_all(&inner, request).await }; + let fut = async move { + ::read_all(&inner, request).await + }; Box::pin(fut) } } @@ -1675,8 +2228,14 @@ pub mod node_service_server { let method = ReadAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1685,12 +2244,23 @@ pub mod node_service_server { "/node_service.NodeService/WriteAll" => { #[allow(non_camel_case_types)] struct WriteAllSvc(pub Arc); - impl tonic::server::UnaryService for WriteAllSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WriteAllSvc { type Response = super::WriteAllResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_all(&inner, request).await }; + let fut = async move { + ::write_all(&inner, request).await + }; Box::pin(fut) } } @@ -1703,8 +2273,14 @@ pub mod node_service_server { let method = WriteAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1713,12 +2289,23 @@ pub mod node_service_server { "/node_service.NodeService/Delete" => { #[allow(non_camel_case_types)] struct DeleteSvc(pub Arc); - impl tonic::server::UnaryService for DeleteSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteSvc { type Response = super::DeleteResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete(&inner, request).await }; + let fut = async move { + ::delete(&inner, request).await + }; Box::pin(fut) } } @@ -1731,8 +2318,14 @@ pub mod node_service_server { let method = DeleteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1741,12 +2334,23 @@ pub mod node_service_server { "/node_service.NodeService/VerifyFile" => { #[allow(non_camel_case_types)] struct VerifyFileSvc(pub Arc); - impl tonic::server::UnaryService for VerifyFileSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for VerifyFileSvc { type Response = super::VerifyFileResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::verify_file(&inner, request).await }; + let fut = async move { + ::verify_file(&inner, request).await + }; Box::pin(fut) } } @@ -1759,8 +2363,14 @@ pub mod node_service_server { let method = VerifyFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1769,12 +2379,23 @@ pub mod node_service_server { "/node_service.NodeService/CheckParts" => { #[allow(non_camel_case_types)] struct CheckPartsSvc(pub Arc); - impl tonic::server::UnaryService for CheckPartsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for CheckPartsSvc { type Response = super::CheckPartsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::check_parts(&inner, request).await }; + let fut = async move { + ::check_parts(&inner, request).await + }; Box::pin(fut) } } @@ -1787,8 +2408,14 @@ pub mod node_service_server { let method = CheckPartsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1797,12 +2424,23 @@ pub mod node_service_server { "/node_service.NodeService/RenamePart" => { #[allow(non_camel_case_types)] struct RenamePartSvc(pub Arc); - impl tonic::server::UnaryService for RenamePartSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenamePartSvc { type Response = super::RenamePartResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_part(&inner, request).await }; + let fut = async move { + ::rename_part(&inner, request).await + }; Box::pin(fut) } } @@ -1815,8 +2453,14 @@ pub mod node_service_server { let method = RenamePartSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1825,12 +2469,23 @@ pub mod node_service_server { "/node_service.NodeService/RenameFile" => { #[allow(non_camel_case_types)] struct RenameFileSvc(pub Arc); - impl tonic::server::UnaryService for RenameFileSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenameFileSvc { type Response = super::RenameFileResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_file(&inner, request).await }; + let fut = async move { + ::rename_file(&inner, request).await + }; Box::pin(fut) } } @@ -1843,8 +2498,14 @@ pub mod node_service_server { let method = RenameFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1853,12 +2514,21 @@ pub mod node_service_server { "/node_service.NodeService/Write" => { #[allow(non_camel_case_types)] struct WriteSvc(pub Arc); - impl tonic::server::UnaryService for WriteSvc { + impl tonic::server::UnaryService + for WriteSvc { type Response = super::WriteResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write(&inner, request).await }; + let fut = async move { + ::write(&inner, request).await + }; Box::pin(fut) } } @@ -1871,8 +2541,14 @@ pub mod node_service_server { let method = WriteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1881,13 +2557,26 @@ pub mod node_service_server { "/node_service.NodeService/WriteStream" => { #[allow(non_camel_case_types)] struct WriteStreamSvc(pub Arc); - impl tonic::server::StreamingService for WriteStreamSvc { + impl< + T: NodeService, + > tonic::server::StreamingService + for WriteStreamSvc { type Response = super::WriteResponse; type ResponseStream = T::WriteStreamStream; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request>) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_stream(&inner, request).await }; + let fut = async move { + ::write_stream(&inner, request).await + }; Box::pin(fut) } } @@ -1900,8 +2589,14 @@ pub mod node_service_server { let method = WriteStreamSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -1910,13 +2605,26 @@ pub mod node_service_server { "/node_service.NodeService/ReadAt" => { #[allow(non_camel_case_types)] struct ReadAtSvc(pub Arc); - impl tonic::server::StreamingService for ReadAtSvc { + impl< + T: NodeService, + > tonic::server::StreamingService + for ReadAtSvc { type Response = super::ReadAtResponse; type ResponseStream = T::ReadAtStream; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request>) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_at(&inner, request).await }; + let fut = async move { + ::read_at(&inner, request).await + }; Box::pin(fut) } } @@ -1929,8 +2637,14 @@ pub mod node_service_server { let method = ReadAtSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -1939,12 +2653,23 @@ pub mod node_service_server { "/node_service.NodeService/ListDir" => { #[allow(non_camel_case_types)] struct ListDirSvc(pub Arc); - impl tonic::server::UnaryService for ListDirSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListDirSvc { type Response = super::ListDirResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_dir(&inner, request).await }; + let fut = async move { + ::list_dir(&inner, request).await + }; Box::pin(fut) } } @@ -1957,8 +2682,14 @@ pub mod node_service_server { let method = ListDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1967,12 +2698,23 @@ pub mod node_service_server { "/node_service.NodeService/WalkDir" => { #[allow(non_camel_case_types)] struct WalkDirSvc(pub Arc); - impl tonic::server::UnaryService for WalkDirSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WalkDirSvc { type Response = super::WalkDirResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::walk_dir(&inner, request).await }; + let fut = async move { + ::walk_dir(&inner, request).await + }; Box::pin(fut) } } @@ -1985,8 +2727,14 @@ pub mod node_service_server { let method = WalkDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -1995,12 +2743,23 @@ pub mod node_service_server { "/node_service.NodeService/RenameData" => { #[allow(non_camel_case_types)] struct RenameDataSvc(pub Arc); - impl tonic::server::UnaryService for RenameDataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RenameDataSvc { type Response = super::RenameDataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::rename_data(&inner, request).await }; + let fut = async move { + ::rename_data(&inner, request).await + }; Box::pin(fut) } } @@ -2013,8 +2772,14 @@ pub mod node_service_server { let method = RenameDataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2023,12 +2788,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolumes" => { #[allow(non_camel_case_types)] struct MakeVolumesSvc(pub Arc); - impl tonic::server::UnaryService for MakeVolumesSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeVolumesSvc { type Response = super::MakeVolumesResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_volumes(&inner, request).await }; + let fut = async move { + ::make_volumes(&inner, request).await + }; Box::pin(fut) } } @@ -2041,8 +2817,14 @@ pub mod node_service_server { let method = MakeVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2051,12 +2833,23 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolume" => { #[allow(non_camel_case_types)] struct MakeVolumeSvc(pub Arc); - impl tonic::server::UnaryService for MakeVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for MakeVolumeSvc { type Response = super::MakeVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::make_volume(&inner, request).await }; + let fut = async move { + ::make_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2069,8 +2862,14 @@ pub mod node_service_server { let method = MakeVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2079,12 +2878,23 @@ pub mod node_service_server { "/node_service.NodeService/ListVolumes" => { #[allow(non_camel_case_types)] struct ListVolumesSvc(pub Arc); - impl tonic::server::UnaryService for ListVolumesSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ListVolumesSvc { type Response = super::ListVolumesResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::list_volumes(&inner, request).await }; + let fut = async move { + ::list_volumes(&inner, request).await + }; Box::pin(fut) } } @@ -2097,8 +2907,14 @@ pub mod node_service_server { let method = ListVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2107,12 +2923,23 @@ pub mod node_service_server { "/node_service.NodeService/StatVolume" => { #[allow(non_camel_case_types)] struct StatVolumeSvc(pub Arc); - impl tonic::server::UnaryService for StatVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for StatVolumeSvc { type Response = super::StatVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::stat_volume(&inner, request).await }; + let fut = async move { + ::stat_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2125,8 +2952,14 @@ pub mod node_service_server { let method = StatVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2135,12 +2968,23 @@ pub mod node_service_server { "/node_service.NodeService/DeletePaths" => { #[allow(non_camel_case_types)] struct DeletePathsSvc(pub Arc); - impl tonic::server::UnaryService for DeletePathsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeletePathsSvc { type Response = super::DeletePathsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_paths(&inner, request).await }; + let fut = async move { + ::delete_paths(&inner, request).await + }; Box::pin(fut) } } @@ -2153,8 +2997,14 @@ pub mod node_service_server { let method = DeletePathsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2163,12 +3013,23 @@ pub mod node_service_server { "/node_service.NodeService/UpdateMetadata" => { #[allow(non_camel_case_types)] struct UpdateMetadataSvc(pub Arc); - impl tonic::server::UnaryService for UpdateMetadataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for UpdateMetadataSvc { type Response = super::UpdateMetadataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::update_metadata(&inner, request).await }; + let fut = async move { + ::update_metadata(&inner, request).await + }; Box::pin(fut) } } @@ -2181,8 +3042,14 @@ pub mod node_service_server { let method = UpdateMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2191,12 +3058,23 @@ pub mod node_service_server { "/node_service.NodeService/WriteMetadata" => { #[allow(non_camel_case_types)] struct WriteMetadataSvc(pub Arc); - impl tonic::server::UnaryService for WriteMetadataSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for WriteMetadataSvc { type Response = super::WriteMetadataResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::write_metadata(&inner, request).await }; + let fut = async move { + ::write_metadata(&inner, request).await + }; Box::pin(fut) } } @@ -2209,8 +3087,14 @@ pub mod node_service_server { let method = WriteMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2219,12 +3103,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadVersion" => { #[allow(non_camel_case_types)] struct ReadVersionSvc(pub Arc); - impl tonic::server::UnaryService for ReadVersionSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadVersionSvc { type Response = super::ReadVersionResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_version(&inner, request).await }; + let fut = async move { + ::read_version(&inner, request).await + }; Box::pin(fut) } } @@ -2237,8 +3132,14 @@ pub mod node_service_server { let method = ReadVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2247,12 +3148,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadXL" => { #[allow(non_camel_case_types)] struct ReadXLSvc(pub Arc); - impl tonic::server::UnaryService for ReadXLSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadXLSvc { type Response = super::ReadXlResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_xl(&inner, request).await }; + let fut = async move { + ::read_xl(&inner, request).await + }; Box::pin(fut) } } @@ -2265,8 +3177,14 @@ pub mod node_service_server { let method = ReadXLSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2275,12 +3193,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersion" => { #[allow(non_camel_case_types)] struct DeleteVersionSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVersionSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVersionSvc { type Response = super::DeleteVersionResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_version(&inner, request).await }; + let fut = async move { + ::delete_version(&inner, request).await + }; Box::pin(fut) } } @@ -2293,8 +3222,14 @@ pub mod node_service_server { let method = DeleteVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2303,12 +3238,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersions" => { #[allow(non_camel_case_types)] struct DeleteVersionsSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVersionsSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVersionsSvc { type Response = super::DeleteVersionsResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_versions(&inner, request).await }; + let fut = async move { + ::delete_versions(&inner, request).await + }; Box::pin(fut) } } @@ -2321,8 +3267,14 @@ pub mod node_service_server { let method = DeleteVersionsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2331,12 +3283,23 @@ pub mod node_service_server { "/node_service.NodeService/ReadMultiple" => { #[allow(non_camel_case_types)] struct ReadMultipleSvc(pub Arc); - impl tonic::server::UnaryService for ReadMultipleSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ReadMultipleSvc { type Response = super::ReadMultipleResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::read_multiple(&inner, request).await }; + let fut = async move { + ::read_multiple(&inner, request).await + }; Box::pin(fut) } } @@ -2349,8 +3312,14 @@ pub mod node_service_server { let method = ReadMultipleSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2359,12 +3328,23 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVolume" => { #[allow(non_camel_case_types)] struct DeleteVolumeSvc(pub Arc); - impl tonic::server::UnaryService for DeleteVolumeSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DeleteVolumeSvc { type Response = super::DeleteVolumeResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::delete_volume(&inner, request).await }; + let fut = async move { + ::delete_volume(&inner, request).await + }; Box::pin(fut) } } @@ -2377,8 +3357,14 @@ pub mod node_service_server { let method = DeleteVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2387,12 +3373,23 @@ pub mod node_service_server { "/node_service.NodeService/DiskInfo" => { #[allow(non_camel_case_types)] struct DiskInfoSvc(pub Arc); - impl tonic::server::UnaryService for DiskInfoSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for DiskInfoSvc { type Response = super::DiskInfoResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::disk_info(&inner, request).await }; + let fut = async move { + ::disk_info(&inner, request).await + }; Box::pin(fut) } } @@ -2405,8 +3402,14 @@ pub mod node_service_server { let method = DiskInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2415,13 +3418,26 @@ pub mod node_service_server { "/node_service.NodeService/NsScanner" => { #[allow(non_camel_case_types)] struct NsScannerSvc(pub Arc); - impl tonic::server::StreamingService for NsScannerSvc { + impl< + T: NodeService, + > tonic::server::StreamingService + for NsScannerSvc { type Response = super::NsScannerResponse; type ResponseStream = T::NsScannerStream; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request>) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + tonic::Streaming, + >, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::ns_scanner(&inner, request).await }; + let fut = async move { + ::ns_scanner(&inner, request).await + }; Box::pin(fut) } } @@ -2434,8 +3450,14 @@ pub mod node_service_server { let method = NsScannerSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -2444,12 +3466,23 @@ pub mod node_service_server { "/node_service.NodeService/Lock" => { #[allow(non_camel_case_types)] struct LockSvc(pub Arc); - impl tonic::server::UnaryService for LockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for LockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::lock(&inner, request).await }; + let fut = async move { + ::lock(&inner, request).await + }; Box::pin(fut) } } @@ -2462,8 +3495,14 @@ pub mod node_service_server { let method = LockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2472,12 +3511,23 @@ pub mod node_service_server { "/node_service.NodeService/UnLock" => { #[allow(non_camel_case_types)] struct UnLockSvc(pub Arc); - impl tonic::server::UnaryService for UnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for UnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::un_lock(&inner, request).await }; + let fut = async move { + ::un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2490,8 +3540,14 @@ pub mod node_service_server { let method = UnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2500,12 +3556,23 @@ pub mod node_service_server { "/node_service.NodeService/RLock" => { #[allow(non_camel_case_types)] struct RLockSvc(pub Arc); - impl tonic::server::UnaryService for RLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::r_lock(&inner, request).await }; + let fut = async move { + ::r_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2518,8 +3585,14 @@ pub mod node_service_server { let method = RLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2528,12 +3601,23 @@ pub mod node_service_server { "/node_service.NodeService/RUnLock" => { #[allow(non_camel_case_types)] struct RUnLockSvc(pub Arc); - impl tonic::server::UnaryService for RUnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::r_un_lock(&inner, request).await }; + let fut = async move { + ::r_un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2546,8 +3630,14 @@ pub mod node_service_server { let method = RUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2556,12 +3646,23 @@ pub mod node_service_server { "/node_service.NodeService/ForceUnLock" => { #[allow(non_camel_case_types)] struct ForceUnLockSvc(pub Arc); - impl tonic::server::UnaryService for ForceUnLockSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for ForceUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::force_un_lock(&inner, request).await }; + let fut = async move { + ::force_un_lock(&inner, request).await + }; Box::pin(fut) } } @@ -2574,8 +3675,14 @@ pub mod node_service_server { let method = ForceUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2584,12 +3691,23 @@ pub mod node_service_server { "/node_service.NodeService/Refresh" => { #[allow(non_camel_case_types)] struct RefreshSvc(pub Arc); - impl tonic::server::UnaryService for RefreshSvc { + impl< + T: NodeService, + > tonic::server::UnaryService + for RefreshSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture, tonic::Status>; - fn call(&mut self, request: tonic::Request) -> Self::Future { + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { ::refresh(&inner, request).await }; + let fut = async move { + ::refresh(&inner, request).await + }; Box::pin(fut) } } @@ -2602,20 +3720,36 @@ pub mod node_service_server { let method = RefreshSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config(accept_compression_encodings, send_compression_encodings) - .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } - _ => Box::pin(async move { - let mut response = http::Response::new(empty_body()); - let headers = response.headers_mut(); - headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into()); - headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE); - Ok(response) - }), + _ => { + Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers + .insert( + tonic::Status::GRPC_STATUS, + (tonic::Code::Unimplemented as i32).into(), + ); + headers + .insert( + http::header::CONTENT_TYPE, + tonic::metadata::GRPC_CONTENT_TYPE, + ); + Ok(response) + }) + } } } } diff --git a/ecstore/src/config/mod.rs b/ecstore/src/config/mod.rs index 030d15a10..14d0f21e9 100644 --- a/ecstore/src/config/mod.rs +++ b/ecstore/src/config/mod.rs @@ -18,6 +18,8 @@ lazy_static! { pub static ref GLOBAL_ConfigSys: ConfigSys = ConfigSys::new(); } +pub static RUSTFS_CONFIG_PREFIX: &str = "config"; + pub struct ConfigSys {} impl ConfigSys { diff --git a/ecstore/src/disk/endpoint.rs b/ecstore/src/disk/endpoint.rs index 6a6ba743f..eb4b233d9 100644 --- a/ecstore/src/disk/endpoint.rs +++ b/ecstore/src/disk/endpoint.rs @@ -2,6 +2,7 @@ use crate::error::{Error, Result}; use crate::utils::net; use path_absolutize::Absolutize; use path_clean::PathClean; +use std::fs; use std::{fmt::Display, path::Path}; use url::{ParseError, Url}; @@ -29,7 +30,7 @@ pub struct Endpoint { impl Display for Endpoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.url.scheme() == "file" { - write!(f, "{}", self.url.path()) + write!(f, "{}", fs::canonicalize(self.url.path()).map_err(|_| std::fmt::Error)?.to_string_lossy().to_string()) } else { write!(f, "{}", self.url) } diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index e7c45195d..919e88ec8 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -6,7 +6,7 @@ use super::{endpoint::Endpoint, error::DiskError, format::FormatV3}; use super::{ os, CheckPartsResp, DeleteOptions, DiskAPI, DiskInfo, DiskInfoOptions, DiskLocation, DiskMetrics, FileInfoVersions, FileReader, FileWriter, Info, MetaCacheEntry, ReadMultipleReq, ReadMultipleResp, ReadOptions, RenameDataResp, - UpdateMetadataOpts, VolumeInfo, WalkDirOptions, + UpdateMetadataOpts, VolumeInfo, WalkDirOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET, }; use crate::bitrot::bitrot_verify; use crate::bucket::metadata_sys::GLOBAL_BucketMetadataSys; @@ -23,7 +23,8 @@ use crate::heal::data_scanner::{has_active_rules, scan_data_folder, ScannerItem, use crate::heal::data_scanner_metric::{ScannerMetric, ScannerMetrics}; use crate::heal::data_usage_cache::{DataUsageCache, DataUsageEntry}; use crate::heal::error::{ERR_IGNORE_FILE_CONTRIB, ERR_SKIP_FILE}; -use crate::heal::heal_commands::HealScanMode; +use crate::heal::heal_commands::{HealScanMode, HealingTracker}; +use crate::heal::heal_ops::HEALING_TRACKER_FILENAME; use crate::new_object_layer_fn; use crate::set_disk::{ conv_part_err_to_int, CHECK_PART_FILE_CORRUPT, CHECK_PART_FILE_NOT_FOUND, CHECK_PART_SUCCESS, CHECK_PART_UNKNOWN, @@ -32,7 +33,7 @@ use crate::set_disk::{ use crate::store_api::{BitrotAlgorithm, StorageAPI}; 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, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR}; +use crate::utils::path::{clean, has_suffix, path_join, GLOBAL_DIR_SUFFIX_WITH_SLASH, SLASH_SEPARATOR}; use crate::{ file_meta::FileMeta, store_api::{FileInfo, RawFileInfo}, @@ -2013,6 +2014,26 @@ impl DiskAPI for LocalDisk { data_usage_info.info.last_update = Some(SystemTime::now()); Ok(data_usage_info) } + + async fn healing(&self) -> Option { + let healing_file = path_join(&[ + self.path(), + PathBuf::from(RUSTFS_META_BUCKET), + PathBuf::from(BUCKET_META_PREFIX), + PathBuf::from(HEALING_TRACKER_FILENAME), + ]); + let b = match fs::read(healing_file).await { + Ok(b) => b, + Err(_) => return None, + }; + if b.is_empty() { + return None; + } + match HealingTracker::unmarshal_msg(&b) { + Ok(h) => Some(h), + Err(_) => Some(HealingTracker::default()) + } + } } async fn get_disk_info(drive_path: PathBuf) -> Result<(Info, bool)> { diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index d903a6f9a..a19bec9b7 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -19,7 +19,7 @@ use crate::{ file_meta::{merge_file_meta_versions, FileMeta, FileMetaShallowVersion}, heal::{ data_usage_cache::{DataUsageCache, DataUsageEntry}, - heal_commands::HealScanMode, + heal_commands::{HealScanMode, HealingTracker}, }, store_api::{FileInfo, RawFileInfo}, }; @@ -349,11 +349,18 @@ impl DiskAPI for Disk { updates: Sender, scan_mode: HealScanMode, ) -> Result { - match &*self { + match self { Disk::Local(local_disk) => local_disk.ns_scanner(cache, updates, scan_mode).await, Disk::Remote(remote_disk) => remote_disk.ns_scanner(cache, updates, scan_mode).await, } } + + async fn healing(&self) -> Option { + match self { + Disk::Local(local_disk) => local_disk.healing().await, + Disk::Remote(remote_disk) => remote_disk.healing().await, + } + } } pub async fn new_disk(ep: &endpoint::Endpoint, opt: &DiskOption) -> Result { @@ -458,6 +465,7 @@ pub trait DiskAPI: Debug + Send + Sync + 'static { updates: Sender, scan_mode: HealScanMode, ) -> Result; + async fn healing(&self) -> Option; } #[derive(Debug, Default, Serialize, Deserialize)] diff --git a/ecstore/src/disk/remote.rs b/ecstore/src/disk/remote.rs index e23508f76..83099693c 100644 --- a/ecstore/src/disk/remote.rs +++ b/ecstore/src/disk/remote.rs @@ -26,7 +26,7 @@ use crate::{ error::{Error, Result}, heal::{ data_usage_cache::{DataUsageCache, DataUsageEntry}, - heal_commands::HealScanMode, + heal_commands::{HealScanMode, HealingTracker}, }, store_api::{FileInfo, RawFileInfo}, }; @@ -775,4 +775,8 @@ impl DiskAPI for RemoteDisk { } } } + + async fn healing(&self) -> Option { + None + } } diff --git a/ecstore/src/endpoints.rs b/ecstore/src/endpoints.rs index 0329f88f5..a8b9d4dee 100644 --- a/ecstore/src/endpoints.rs +++ b/ecstore/src/endpoints.rs @@ -110,6 +110,10 @@ impl Endpoints { self.0 } + pub fn into_ref(&self) -> &Vec { + &self.0 + } + // GetString - returns endpoint string of i-th endpoint (0-based), // and empty string for invalid indexes. pub fn get_string(&self, i: usize) -> String { @@ -119,6 +123,10 @@ impl Endpoints { self.0[i].to_string() } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } } #[derive(Debug)] diff --git a/ecstore/src/heal/background_heal_ops.rs b/ecstore/src/heal/background_heal_ops.rs index 1ac61387e..5c5e7fb46 100644 --- a/ecstore/src/heal/background_heal_ops.rs +++ b/ecstore/src/heal/background_heal_ops.rs @@ -1,18 +1,17 @@ -use std::{env, sync::Arc}; +use std::{cmp::Ordering, env, path::PathBuf, sync::Arc, time::Duration}; -use tokio::sync::{ - mpsc::{self, Receiver, Sender}, - RwLock, +use tokio::{ + sync::{ + mpsc::{self, Receiver, Sender}, + RwLock, + }, + time::interval, }; +use tracing::info; +use uuid::Uuid; use crate::{ - endpoints::Endpoints, - error::{Error, Result}, - global::{GLOBAL_BackgroundHealRoutine, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP}, - heal::heal_ops::NOP_HEAL, - new_object_layer_fn, - store_api::StorageAPI, - utils::path::SLASH_SEPARATOR, + config::RUSTFS_CONFIG_PREFIX, disk::{endpoint::Endpoint, error::DiskError, DiskAPI, DiskInfoOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, error::{Error, Result}, global::{GLOBAL_BackgroundHealRoutine, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP}, heal::{data_usage::{DATA_USAGE_CACHE_NAME, DATA_USAGE_ROOT}, data_usage_cache::DataUsageCache, heal_commands::{init_healing_tracker, load_healing_tracker}, heal_ops::NOP_HEAL}, new_object_layer_fn, store::get_disk_via_endpoint, store_api::{BucketInfo, BucketOptions, StorageAPI}, utils::path::{path_join, SLASH_SEPARATOR} }; use super::{ @@ -20,11 +19,17 @@ use super::{ heal_ops::{new_bg_heal_sequence, HealSequence}, }; +pub static DEFAULT_MONITOR_NEW_DISK_INTERVAL: Duration = Duration::from_secs(10); + pub async fn init_auto_heal() { init_background_healing().await; if let Ok(v) = env::var("_RUSTFS_AUTO_DRIVE_HEALING") { if v == "on" { - // GLOBAL_BackgroundHealState.write().await.push_heal_local_disks(heal_local_disks).await; + GLOBAL_BackgroundHealState + .write() + .await + .push_heal_local_disks(&get_local_disks_to_heal().await) + .await; } } } @@ -44,8 +49,142 @@ async fn init_background_healing() { .await; } -async fn get_local_disks_to_heal() -> Endpoints { - for (_, disk) in GLOBAL_LOCAL_DISK_MAP.read().await.iter() {} +async fn get_local_disks_to_heal() -> Vec { + let mut disks_to_heal = Vec::new(); + for (_, disk) in GLOBAL_LOCAL_DISK_MAP.read().await.iter() { + if let Some(disk) = disk { + if let Err(err) = disk.disk_info(&DiskInfoOptions::default()).await { + if let Some(DiskError::UnformattedDisk) = err.downcast_ref() { + disks_to_heal.push(disk.endpoint()); + } + } + let h = disk.healing().await; + if let Some(h) = h { + if !h.finished { + disks_to_heal.push(disk.endpoint()); + } + } + } + } + + // todo + // if disks_to_heal.len() == GLOBAL_Endpoints.read().await.n { + + // } + disks_to_heal +} + +async fn monitor_local_disks_and_heal() { + let mut interval = interval(DEFAULT_MONITOR_NEW_DISK_INTERVAL); + + loop { + interval.tick().await; + let heal_disks = GLOBAL_BackgroundHealState.read().await.get_heal_local_disk_endpoints().await; + if heal_disks.is_empty() { + interval.reset(); + continue; + } + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = lock.as_ref().expect("errServerNotInitialized"); + if let (_, Some(err)) = store.heal_format(false).await.expect("heal format failed") { + if let Some(DiskError::NoHealRequired) = err.downcast_ref() { + } else { + info!("heal format err: {}", err.to_string()); + interval.reset(); + continue; + } + } + + for disk in heal_disks.into_ref().iter() { + let disk_clone = disk.clone(); + tokio::spawn(async move { + GLOBAL_BackgroundHealState.write().await.set_disk_healing_status(disk_clone.clone(), true).await; + + }); + } + } +} + +async fn heal_fresh_disk(endpoint: &Endpoint) -> Result<()> { + let (pool_idx, set_idx) = (endpoint.pool_idx.unwrap(), endpoint.disk_idx.unwrap()); + let disk = match get_disk_via_endpoint(endpoint).await { + Some(disk) => disk, + None => return Err(Error::from_string(format!("Unexpected error disk must be initialized by now after formatting: {}", endpoint.to_string()))), + }; + + if let Err(err) = disk.disk_info(&DiskInfoOptions::default()).await { + match err.downcast_ref() { + Some(DiskError::DriveIsRoot) => { + return Ok(()); + }, + Some(DiskError::UnformattedDisk) => { + }, + _ => { + return Err(err); + } + } + } + + let mut tracker = match load_healing_tracker(&Some(disk.clone())).await { + Ok(tracker) => tracker, + Err(err) => { + match err.downcast_ref() { + Some(DiskError::FileNotFound) => { + return Ok(()); + } + _ => { + info!("Unable to load healing tracker on '{}': {}, re-initializing..", disk.to_string(), err.to_string()); + }, + } + init_healing_tracker(disk.clone(), &Uuid::new_v4().to_string()).await? + } + }; + + info!("Healing drive '{}' - 'mc admin heal alias/ --verbose' to check the current status.", endpoint.to_string()); + + 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")), + }; + let mut buckets = store.list_bucket(&BucketOptions::default()).await?; + buckets.push(BucketInfo { + name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(RUSTFS_CONFIG_PREFIX)]).to_string_lossy().to_string(), + ..Default::default() + }); + buckets.push(BucketInfo { + name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(BUCKET_META_PREFIX)]).to_string_lossy().to_string(), + ..Default::default() + }); + + buckets.sort_by(|a, b| { + let a_has_prefix = a.name.starts_with(RUSTFS_META_BUCKET); + let b_has_prefix = b.name.starts_with(RUSTFS_META_BUCKET); + + match (a_has_prefix, b_has_prefix) { + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + _ => b.created.cmp(&a.created), + } + }); + + let mut cache = match DataUsageCache::load(&store.pools[pool_idx].disk_set[set_idx], DATA_USAGE_CACHE_NAME).await { + Ok(cache) => { + let data_usage_info = cache.dui(DATA_USAGE_ROOT, &Vec::new()); + tracker.objects_total_count = data_usage_info.objects_total_count; + tracker.objects_total_size = data_usage_info.objects_total_size; + cache + }, + Err(_) => DataUsageCache::default() + }; + + let location = disk.get_disk_location(); + tracker.set_queue_buckets(&buckets).await; + tracker.save().await?; + + // store.pools[pool_idx].disk_set[set_idx]. todo!() } diff --git a/ecstore/src/heal/heal_commands.rs b/ecstore/src/heal/heal_commands.rs index 8417c8b67..6195f922a 100644 --- a/ecstore/src/heal/heal_commands.rs +++ b/ecstore/src/heal/heal_commands.rs @@ -161,8 +161,7 @@ pub struct HealingTracker { impl HealingTracker { pub fn marshal_msg(&self) -> Result> { - serde_json::to_string(self) - .map(|s| s.as_bytes().to_vec()) + serde_json::to_vec(self) .map_err(|err| Error::from_string(err.to_string())) } @@ -336,7 +335,7 @@ impl HealingTracker { self.queue_buckets.retain(|x| x != bucket); } - async fn set_queue_buckets(&mut self, buckets: &[BucketInfo]) { + pub async fn set_queue_buckets(&mut self, buckets: &[BucketInfo]) { let _ = self.mu.write().await; buckets.iter().for_each(|bucket| { @@ -417,7 +416,7 @@ impl Clone for HealingTracker { } } -async fn load_healing_tracker(disk: &Option) -> Result { +pub async fn load_healing_tracker(disk: &Option) -> Result { if let Some(disk) = disk { let disk_id = disk.get_disk_id().await?; if let Some(disk_id) = disk_id { diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 36f35dc54..47b5f6c17 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -406,7 +406,7 @@ impl AllHealState { hstate } - async fn pop_heal_local_disks(&mut self, heal_local_disks: &[Endpoint]) { + pub async fn pop_heal_local_disks(&mut self, heal_local_disks: &[Endpoint]) { let _ = self.mu.write().await; self.heal_local_disks.retain(|k, _| { @@ -433,7 +433,7 @@ impl AllHealState { self.heal_status.insert(tracker.id.clone(), tracker.clone()); } - async fn get_local_healing_disks(&self) -> HashMap { + pub async fn get_local_healing_disks(&self) -> HashMap { let _ = self.mu.read().await; let mut dst = HashMap::new(); @@ -444,7 +444,7 @@ impl AllHealState { dst } - async fn get_heal_local_disk_endpoints(&self) -> Endpoints { + pub async fn get_heal_local_disk_endpoints(&self) -> Endpoints { let _ = self.mu.read().await; let mut endpoints = Vec::new(); @@ -471,7 +471,7 @@ impl AllHealState { }); } - async fn periodic_heal_seqs_clean(&mut self) { + pub async fn periodic_heal_seqs_clean(&mut self) { let _ = self.mu.write().await; let now = SystemTime::now(); @@ -500,13 +500,13 @@ impl AllHealState { (None, false) } - async fn get_heal_sequence(&self, path: &str) -> Option>> { + pub async fn get_heal_sequence(&self, path: &str) -> Option>> { let _ = self.mu.read().await; self.heal_seq_map.get(path).cloned() } - async fn stop_heal_sequence(&mut self, path: &str) -> Result> { + pub async fn stop_heal_sequence(&mut self, path: &str) -> Result> { let mut hsp = HealStopSuccess::default(); if let Some(he) = self.get_heal_sequence(path).await { let he = he.read().await; diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index f6bb937df..8452bbe9a 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -3,7 +3,7 @@ use crate::bucket::metadata_sys::{self, init_bucket_metadata_sys, set_bucket_metadata}; use crate::bucket::utils::{check_valid_bucket_name, check_valid_bucket_name_strict, is_meta_bucketname}; use crate::config::{self, storageclass, GLOBAL_ConfigSys}; -use crate::disk::endpoint::EndpointType; +use crate::disk::endpoint::{Endpoint, EndpointType}; use crate::disk::{DiskAPI, DiskInfo, DiskInfoOptions, MetaCacheEntry}; use crate::global::{ is_dist_erasure, is_erasure_sd, set_global_deployment_id, set_object_layer, DISK_ASSUME_UNKNOWN_SIZE, DISK_FILL_FRACTION, @@ -735,6 +735,14 @@ pub async fn find_local_disk(disk_path: &String) -> Option { None } +pub async fn get_disk_via_endpoint(endpoint: &Endpoint) -> Option { + let global_set_drives = GLOBAL_LOCAL_DISK_SET_DRIVES.read().await; + if global_set_drives.is_empty() { + return GLOBAL_LOCAL_DISK_MAP.read().await[&endpoint.to_string()].clone(); + } + global_set_drives[endpoint.pool_idx.unwrap()][endpoint.set_idx.unwrap()][endpoint.disk_idx.unwrap()].clone() +} + pub async fn all_local_disk_path() -> Vec { let disk_map = GLOBAL_LOCAL_DISK_MAP.read().await; disk_map.keys().cloned().collect() From e94d462652cdce3da01d3eb726e7c79fe0ef8158 Mon Sep 17 00:00:00 2001 From: mujunxiang <1948535941@qq.com> Date: Tue, 19 Nov 2024 17:15:37 +0800 Subject: [PATCH 08/11] auto heal(3) Signed-off-by: mujunxiang <1948535941@qq.com> --- Cargo.lock | 11 + Cargo.toml | 3 +- common/common/Cargo.toml | 4 +- common/lock/src/lrwmutex.rs | 12 +- common/lock/src/namespace_lock.rs | 2 +- .../generated/flatbuffers_generated/models.rs | 207 +- .../src/generated/proto_gen/node_service.rs | 1991 ++++------------- common/protos/src/node.proto | 11 + common/workers/Cargo.toml | 11 + common/workers/src/lib.rs | 1 + common/workers/src/workers.rs | 87 + e2e_test/src/reliant/lock.rs | 25 +- ecstore/Cargo.toml | 1 + ecstore/src/bitrot.rs | 34 +- ecstore/src/bucket/utils.rs | 6 +- ecstore/src/bucket/versioning/mod.rs | 6 +- ecstore/src/cache_value/cache.rs | 8 +- ecstore/src/cache_value/metacache_set.rs | 20 +- ecstore/src/config/common.rs | 37 +- ecstore/src/config/heal.rs | 4 +- ecstore/src/config/mod.rs | 19 + ecstore/src/config/storageclass.rs | 6 +- ecstore/src/disk/endpoint.rs | 8 +- ecstore/src/disk/error.rs | 39 +- ecstore/src/disk/local.rs | 31 +- ecstore/src/disk/mod.rs | 5 +- ecstore/src/disk/os.rs | 2 +- ecstore/src/endpoints.rs | 2 +- ecstore/src/erasure.rs | 2 +- ecstore/src/global.rs | 2 +- ecstore/src/heal/background_heal_ops.rs | 203 +- ecstore/src/heal/data_scanner.rs | 79 +- ecstore/src/heal/data_scanner_metric.rs | 15 +- ecstore/src/heal/data_usage.rs | 2 +- ecstore/src/heal/data_usage_cache.rs | 60 +- ecstore/src/heal/error.rs | 3 + ecstore/src/heal/heal_commands.rs | 112 +- ecstore/src/heal/heal_ops.rs | 294 ++- ecstore/src/options.rs | 2 +- ecstore/src/peer.rs | 249 ++- ecstore/src/quorum.rs | 10 + ecstore/src/sets.rs | 64 +- ecstore/src/store.rs | 192 +- ecstore/src/store_api.rs | 20 +- ecstore/src/utils/bool_flag.rs | 12 +- ecstore/src/utils/ellipses.rs | 4 + ecstore/src/utils/wildcard.rs | 6 + rustfs/src/grpc.rs | 44 +- rustfs/src/storage/acess.rs | 2 +- rustfs/src/storage/ecfs.rs | 27 +- 50 files changed, 1822 insertions(+), 2175 deletions(-) create mode 100644 common/workers/Cargo.toml create mode 100644 common/workers/src/lib.rs create mode 100644 common/workers/src/workers.rs diff --git a/Cargo.lock b/Cargo.lock index 5a24b8a1d..678e996f3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" name = "common" version = "0.0.1" dependencies = [ + "async-trait", "lazy_static", + "scopeguard", "tokio", "tonic", "tracing-error", @@ -655,6 +657,7 @@ dependencies = [ "url", "uuid", "winapi", + "workers", "xxhash-rust", ] @@ -3206,6 +3209,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "workers" +version = "0.0.1" +dependencies = [ + "common", + "tokio", +] + [[package]] name = "write16" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index b5ac976ca..a930c0634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "common/protos", "api/admin", "reader", - "router", + "router", "common/workers", ] [workspace.package] @@ -85,3 +85,4 @@ uuid = { version = "1.11.0", features = [ log = "0.4.22" axum = "0.7.7" md-5 = "0.10.6" +workers = { path = "./common/workers" } diff --git a/common/common/Cargo.toml b/common/common/Cargo.toml index 0675b06b3..9031424e8 100644 --- a/common/common/Cargo.toml +++ b/common/common/Cargo.toml @@ -4,7 +4,9 @@ version.workspace = true edition.workspace = true [dependencies] +async-trait.workspace = true lazy_static.workspace = true +scopeguard = "1.2.0" tokio.workspace = true tonic.workspace = true -tracing-error.workspace = true \ No newline at end of file +tracing-error.workspace = true diff --git a/common/lock/src/lrwmutex.rs b/common/lock/src/lrwmutex.rs index 1ff4ebb98..fa65f1a7c 100644 --- a/common/lock/src/lrwmutex.rs +++ b/common/lock/src/lrwmutex.rs @@ -135,14 +135,14 @@ mod test { let id = "foo"; let source = "dandan"; let timeout = Duration::from_secs(5); - assert_eq!(true, l_rw_lock.get_lock(id, source, &timeout).await); + assert!(l_rw_lock.get_lock(id, source, &timeout).await); l_rw_lock.un_lock().await; l_rw_lock.lock().await; - assert_eq!(false, l_rw_lock.get_r_lock(id, source, &timeout).await); + assert!(!(l_rw_lock.get_r_lock(id, source, &timeout).await)); l_rw_lock.un_lock().await; - assert_eq!(true, l_rw_lock.get_r_lock(id, source, &timeout).await); + assert!(l_rw_lock.get_r_lock(id, source, &timeout).await); Ok(()) } @@ -156,7 +156,7 @@ mod test { let one_fn = async { let one = Arc::clone(&l_rw_lock); let timeout = Duration::from_secs(1); - assert_eq!(true, one.get_lock(id, source, &timeout).await); + assert!(one.get_lock(id, source, &timeout).await); sleep(Duration::from_secs(5)).await; l_rw_lock.un_lock().await; }; @@ -164,9 +164,9 @@ mod test { let two_fn = async { let two = Arc::clone(&l_rw_lock); let timeout = Duration::from_secs(2); - assert_eq!(false, two.get_r_lock(id, source, &timeout).await); + assert!(!(two.get_r_lock(id, source, &timeout).await)); sleep(Duration::from_secs(5)).await; - assert_eq!(true, two.get_r_lock(id, source, &timeout).await); + assert!(two.get_r_lock(id, source, &timeout).await); two.un_r_lock().await; }; diff --git a/common/lock/src/namespace_lock.rs b/common/lock/src/namespace_lock.rs index 268458e73..2392ae0aa 100644 --- a/common/lock/src/namespace_lock.rs +++ b/common/lock/src/namespace_lock.rs @@ -287,7 +287,7 @@ mod test { }) .await?; - assert_eq!(result, true); + assert!(result); Ok(()) } } diff --git a/common/protos/src/generated/flatbuffers_generated/models.rs b/common/protos/src/generated/flatbuffers_generated/models.rs index aa1f6ae2f..e4949fdcf 100644 --- a/common/protos/src/generated/flatbuffers_generated/models.rs +++ b/common/protos/src/generated/flatbuffers_generated/models.rs @@ -1,10 +1,9 @@ // automatically generated by the FlatBuffers compiler, do not modify - // @generated -use core::mem; use core::cmp::Ordering; +use core::mem; extern crate flatbuffers; use self::flatbuffers::{EndianScalar, Follow}; @@ -12,112 +11,114 @@ use self::flatbuffers::{EndianScalar, Follow}; #[allow(unused_imports, dead_code)] pub mod models { - use core::mem; - use core::cmp::Ordering; + use core::cmp::Ordering; + use core::mem; - extern crate flatbuffers; - use self::flatbuffers::{EndianScalar, Follow}; + extern crate flatbuffers; + use self::flatbuffers::{EndianScalar, Follow}; -pub enum PingBodyOffset {} -#[derive(Copy, Clone, PartialEq)] + pub enum PingBodyOffset {} + #[derive(Copy, Clone, PartialEq)] -pub struct PingBody<'a> { - pub _tab: flatbuffers::Table<'a>, -} - -impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { - type Inner = PingBody<'a>; - #[inline] - unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { - Self { _tab: flatbuffers::Table::new(buf, loc) } - } -} - -impl<'a> PingBody<'a> { - pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; - - pub const fn get_fully_qualified_name() -> &'static str { - "models.PingBody" - } - - #[inline] - pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { - PingBody { _tab: table } - } - #[allow(unused_mut)] - pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( - _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, - args: &'args PingBodyArgs<'args> - ) -> flatbuffers::WIPOffset> { - let mut builder = PingBodyBuilder::new(_fbb); - if let Some(x) = args.payload { builder.add_payload(x); } - builder.finish() - } - - - #[inline] - pub fn payload(&self) -> Option> { - // Safety: - // Created from valid Table for this object - // which contains a valid value in this slot - unsafe { self._tab.get::>>(PingBody::VT_PAYLOAD, None)} - } -} - -impl flatbuffers::Verifiable for PingBody<'_> { - #[inline] - fn run_verifier( - v: &mut flatbuffers::Verifier, pos: usize - ) -> Result<(), flatbuffers::InvalidFlatbuffer> { - use self::flatbuffers::Verifiable; - v.visit_table(pos)? - .visit_field::>>("payload", Self::VT_PAYLOAD, false)? - .finish(); - Ok(()) - } -} -pub struct PingBodyArgs<'a> { - pub payload: Option>>, -} -impl<'a> Default for PingBodyArgs<'a> { - #[inline] - fn default() -> Self { - PingBodyArgs { - payload: None, + pub struct PingBody<'a> { + pub _tab: flatbuffers::Table<'a>, } - } -} -pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { - fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, - start_: flatbuffers::WIPOffset, -} -impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { - #[inline] - pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { - self.fbb_.push_slot_always::>(PingBody::VT_PAYLOAD, payload); - } - #[inline] - pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { - let start = _fbb.start_table(); - PingBodyBuilder { - fbb_: _fbb, - start_: start, + impl<'a> flatbuffers::Follow<'a> for PingBody<'a> { + type Inner = PingBody<'a>; + #[inline] + unsafe fn follow(buf: &'a [u8], loc: usize) -> Self::Inner { + Self { + _tab: flatbuffers::Table::new(buf, loc), + } + } } - } - #[inline] - pub fn finish(self) -> flatbuffers::WIPOffset> { - let o = self.fbb_.end_table(self.start_); - flatbuffers::WIPOffset::new(o.value()) - } -} -impl core::fmt::Debug for PingBody<'_> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut ds = f.debug_struct("PingBody"); - ds.field("payload", &self.payload()); - ds.finish() - } -} -} // pub mod models + impl<'a> PingBody<'a> { + pub const VT_PAYLOAD: flatbuffers::VOffsetT = 4; + pub const fn get_fully_qualified_name() -> &'static str { + "models.PingBody" + } + + #[inline] + pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self { + PingBody { _tab: table } + } + #[allow(unused_mut)] + pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr, A: flatbuffers::Allocator + 'bldr>( + _fbb: &'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr, A>, + args: &'args PingBodyArgs<'args>, + ) -> flatbuffers::WIPOffset> { + let mut builder = PingBodyBuilder::new(_fbb); + if let Some(x) = args.payload { + builder.add_payload(x); + } + builder.finish() + } + + #[inline] + pub fn payload(&self) -> Option> { + // Safety: + // Created from valid Table for this object + // which contains a valid value in this slot + unsafe { + self._tab + .get::>>(PingBody::VT_PAYLOAD, None) + } + } + } + + impl flatbuffers::Verifiable for PingBody<'_> { + #[inline] + fn run_verifier(v: &mut flatbuffers::Verifier, pos: usize) -> Result<(), flatbuffers::InvalidFlatbuffer> { + use self::flatbuffers::Verifiable; + v.visit_table(pos)? + .visit_field::>>("payload", Self::VT_PAYLOAD, false)? + .finish(); + Ok(()) + } + } + pub struct PingBodyArgs<'a> { + pub payload: Option>>, + } + impl<'a> Default for PingBodyArgs<'a> { + #[inline] + fn default() -> Self { + PingBodyArgs { payload: None } + } + } + + pub struct PingBodyBuilder<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> { + fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a, A>, + start_: flatbuffers::WIPOffset, + } + impl<'a: 'b, 'b, A: flatbuffers::Allocator + 'a> PingBodyBuilder<'a, 'b, A> { + #[inline] + pub fn add_payload(&mut self, payload: flatbuffers::WIPOffset>) { + self.fbb_ + .push_slot_always::>(PingBody::VT_PAYLOAD, payload); + } + #[inline] + pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a, A>) -> PingBodyBuilder<'a, 'b, A> { + let start = _fbb.start_table(); + PingBodyBuilder { + fbb_: _fbb, + start_: start, + } + } + #[inline] + pub fn finish(self) -> flatbuffers::WIPOffset> { + let o = self.fbb_.end_table(self.start_); + flatbuffers::WIPOffset::new(o.value()) + } + } + + impl core::fmt::Debug for PingBody<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let mut ds = f.debug_struct("PingBody"); + ds.field("payload", &self.payload()); + ds.finish() + } + } +} // pub mod models diff --git a/common/protos/src/generated/proto_gen/node_service.rs b/common/protos/src/generated/proto_gen/node_service.rs index 26ba50955..1ec3f589b 100644 --- a/common/protos/src/generated/proto_gen/node_service.rs +++ b/common/protos/src/generated/proto_gen/node_service.rs @@ -15,6 +15,20 @@ pub struct PingResponse { pub body: ::prost::alloc::vec::Vec, } #[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealBucketRequest { + #[prost(string, tag = "1")] + pub bucket: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub options: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealBucketResponse { + #[prost(bool, tag = "1")] + pub success: bool, + #[prost(string, optional, tag = "2")] + pub error_info: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(Clone, PartialEq, ::prost::Message)] pub struct ListBucketRequest { #[prost(string, tag = "1")] pub options: ::prost::alloc::string::String, @@ -600,15 +614,9 @@ pub struct GenerallyLockResponse { } /// Generated client implementations. pub mod node_service_client { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] - use tonic::codegen::*; + #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] use tonic::codegen::http::Uri; + use tonic::codegen::*; #[derive(Debug, Clone)] pub struct NodeServiceClient { inner: tonic::client::Grpc, @@ -639,22 +647,16 @@ pub mod node_service_client { let inner = tonic::client::Grpc::with_origin(inner, origin); Self { inner } } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> NodeServiceClient> + pub fn with_interceptor(inner: T, interceptor: F) -> NodeServiceClient> where F: tonic::service::Interceptor, T::ResponseBody: Default, T: tonic::codegen::Service< http::Request, - Response = http::Response< - >::ResponseBody, - >, + Response = http::Response<>::ResponseBody>, >, - , - >>::Error: Into + std::marker::Send + std::marker::Sync, + >>::Error: + Into + std::marker::Send + std::marker::Sync, { NodeServiceClient::new(InterceptedService::new(inner, interceptor)) } @@ -697,39 +699,39 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Ping", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Ping"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Ping")); self.inner.unary(req, path, codec).await } - pub async fn list_bucket( + pub async fn heal_bucket( &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/HealBucket"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("node_service.NodeService", "HealBucket")); + self.inner.unary(req, path, codec).await + } + pub async fn list_bucket( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListBucket")); @@ -738,22 +740,13 @@ pub mod node_service_client { pub async fn make_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeBucket")); @@ -762,22 +755,13 @@ pub mod node_service_client { pub async fn get_bucket_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/GetBucketInfo", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/GetBucketInfo"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "GetBucketInfo")); @@ -786,22 +770,13 @@ pub mod node_service_client { pub async fn delete_bucket( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteBucket", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteBucket"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteBucket")); @@ -810,22 +785,13 @@ pub mod node_service_client { pub async fn read_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadAll", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAll"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAll")); @@ -834,22 +800,13 @@ pub mod node_service_client { pub async fn write_all( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteAll", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteAll"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteAll")); @@ -862,15 +819,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Delete", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Delete"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Delete")); @@ -879,22 +830,13 @@ pub mod node_service_client { pub async fn verify_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/VerifyFile", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/VerifyFile"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "VerifyFile")); @@ -903,22 +845,13 @@ pub mod node_service_client { pub async fn check_parts( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/CheckParts", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/CheckParts"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "CheckParts")); @@ -927,22 +860,13 @@ pub mod node_service_client { pub async fn rename_part( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenamePart", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenamePart"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenamePart")); @@ -951,22 +875,13 @@ pub mod node_service_client { pub async fn rename_file( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenameFile", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameFile"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameFile")); @@ -979,15 +894,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Write", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Write"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Write")); @@ -996,22 +905,13 @@ pub mod node_service_client { pub async fn write_stream( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteStream", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteStream"); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteStream")); @@ -1021,22 +921,13 @@ pub mod node_service_client { pub async fn read_at( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadAt", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadAt"); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadAt")); @@ -1045,22 +936,13 @@ pub mod node_service_client { pub async fn list_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListDir", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListDir"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListDir")); @@ -1069,22 +951,13 @@ pub mod node_service_client { pub async fn walk_dir( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WalkDir", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WalkDir"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WalkDir")); @@ -1093,22 +966,13 @@ pub mod node_service_client { pub async fn rename_data( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RenameData", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RenameData"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RenameData")); @@ -1117,22 +981,13 @@ pub mod node_service_client { pub async fn make_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeVolumes", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolumes"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolumes")); @@ -1141,22 +996,13 @@ pub mod node_service_client { pub async fn make_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/MakeVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/MakeVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "MakeVolume")); @@ -1165,22 +1011,13 @@ pub mod node_service_client { pub async fn list_volumes( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ListVolumes", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ListVolumes"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ListVolumes")); @@ -1189,22 +1026,13 @@ pub mod node_service_client { pub async fn stat_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/StatVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/StatVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "StatVolume")); @@ -1213,22 +1041,13 @@ pub mod node_service_client { pub async fn delete_paths( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeletePaths", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeletePaths"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeletePaths")); @@ -1237,22 +1056,13 @@ pub mod node_service_client { pub async fn update_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/UpdateMetadata", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UpdateMetadata"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UpdateMetadata")); @@ -1261,22 +1071,13 @@ pub mod node_service_client { pub async fn write_metadata( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/WriteMetadata", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/WriteMetadata"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "WriteMetadata")); @@ -1285,22 +1086,13 @@ pub mod node_service_client { pub async fn read_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadVersion", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadVersion"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadVersion")); @@ -1313,15 +1105,9 @@ pub mod node_service_client { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadXL", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadXL"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadXL")); @@ -1330,22 +1116,13 @@ pub mod node_service_client { pub async fn delete_version( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVersion", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersion"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersion")); @@ -1354,22 +1131,13 @@ pub mod node_service_client { pub async fn delete_versions( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVersions", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVersions"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVersions")); @@ -1378,22 +1146,13 @@ pub mod node_service_client { pub async fn read_multiple( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ReadMultiple", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ReadMultiple"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ReadMultiple")); @@ -1402,22 +1161,13 @@ pub mod node_service_client { pub async fn delete_volume( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DeleteVolume", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DeleteVolume"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DeleteVolume")); @@ -1426,22 +1176,13 @@ pub mod node_service_client { pub async fn disk_info( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/DiskInfo", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/DiskInfo"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "DiskInfo")); @@ -1450,22 +1191,13 @@ pub mod node_service_client { pub async fn ns_scanner( &mut self, request: impl tonic::IntoStreamingRequest, - ) -> std::result::Result< - tonic::Response>, - tonic::Status, - > { + ) -> std::result::Result>, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/NsScanner", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/NsScanner"); let mut req = request.into_streaming_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "NsScanner")); @@ -1474,22 +1206,13 @@ pub mod node_service_client { pub async fn lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Lock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Lock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Lock")); @@ -1498,22 +1221,13 @@ pub mod node_service_client { pub async fn un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/UnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/UnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "UnLock")); @@ -1522,22 +1236,13 @@ pub mod node_service_client { pub async fn r_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RLock")); @@ -1546,22 +1251,13 @@ pub mod node_service_client { pub async fn r_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/RUnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/RUnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "RUnLock")); @@ -1570,22 +1266,13 @@ pub mod node_service_client { pub async fn force_un_lock( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/ForceUnLock", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/ForceUnLock"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "ForceUnLock")); @@ -1594,22 +1281,13 @@ pub mod node_service_client { pub async fn refresh( &mut self, request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { + ) -> std::result::Result, tonic::Status> { self.inner .ready() .await - .map_err(|e| { - tonic::Status::unknown( - format!("Service was not ready: {}", e.into()), - ) - })?; + .map_err(|e| tonic::Status::unknown(format!("Service was not ready: {}", e.into())))?; let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/node_service.NodeService/Refresh", - ); + let path = http::uri::PathAndQuery::from_static("/node_service.NodeService/Refresh"); let mut req = request.into_request(); req.extensions_mut() .insert(GrpcMethod::new("node_service.NodeService", "Refresh")); @@ -1619,13 +1297,7 @@ pub mod node_service_client { } /// Generated server implementations. pub mod node_service_server { - #![allow( - unused_variables, - dead_code, - missing_docs, - clippy::wildcard_imports, - clippy::let_unit_value, - )] + #![allow(unused_variables, dead_code, missing_docs, clippy::wildcard_imports, clippy::let_unit_value)] use tonic::codegen::*; /// Generated trait containing gRPC methods that should be implemented for use with NodeServiceServer. #[async_trait] @@ -1635,34 +1307,26 @@ pub mod node_service_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + async fn heal_bucket( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; async fn list_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn get_bucket_info( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_bucket( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_all( &self, request: tonic::Request, @@ -1670,10 +1334,7 @@ pub mod node_service_server { async fn write_all( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete( &self, request: tonic::Request, @@ -1681,52 +1342,33 @@ pub mod node_service_server { async fn verify_file( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn check_parts( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn rename_part( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn rename_file( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn write( &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the WriteStream method. - type WriteStreamStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + type WriteStreamStream: tonic::codegen::tokio_stream::Stream> + std::marker::Send + 'static; async fn write_stream( &self, request: tonic::Request>, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the ReadAt method. - type ReadAtStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + type ReadAtStream: tonic::codegen::tokio_stream::Stream> + std::marker::Send + 'static; /// rpc Append(AppendRequest) returns (AppendResponse) {}; @@ -1745,66 +1387,39 @@ pub mod node_service_server { async fn rename_data( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_volumes( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn make_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn list_volumes( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn stat_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_paths( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn update_metadata( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn write_metadata( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_version( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_xl( &self, request: tonic::Request, @@ -1812,42 +1427,25 @@ pub mod node_service_server { async fn delete_version( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_versions( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn read_multiple( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn delete_volume( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn disk_info( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; /// Server streaming response type for the NsScanner method. - type NsScannerStream: tonic::codegen::tokio_stream::Stream< - Item = std::result::Result, - > + type NsScannerStream: tonic::codegen::tokio_stream::Stream> + std::marker::Send + 'static; async fn ns_scanner( @@ -1857,45 +1455,27 @@ pub mod node_service_server { async fn lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn r_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn r_un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn force_un_lock( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; async fn refresh( &self, request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + ) -> std::result::Result, tonic::Status>; } #[derive(Debug)] pub struct NodeServiceServer { @@ -1918,10 +1498,7 @@ pub mod node_service_server { max_encoding_message_size: None, } } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> InterceptedService + pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService where F: tonic::service::Interceptor, { @@ -1965,10 +1542,7 @@ pub mod node_service_server { type Response = http::Response; type Error = std::convert::Infallible; type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { + fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll> { Poll::Ready(Ok(())) } fn call(&mut self, req: http::Request) -> Self::Future { @@ -1976,21 +1550,12 @@ pub mod node_service_server { "/node_service.NodeService/Ping" => { #[allow(non_camel_case_types)] struct PingSvc(pub Arc); - impl tonic::server::UnaryService - for PingSvc { + impl tonic::server::UnaryService for PingSvc { type Response = super::PingResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::ping(&inner, request).await - }; + let fut = async move { ::ping(&inner, request).await }; Box::pin(fut) } } @@ -2003,14 +1568,36 @@ pub mod node_service_server { let method = PingSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/node_service.NodeService/HealBucket" => { + #[allow(non_camel_case_types)] + struct HealBucketSvc(pub Arc); + impl tonic::server::UnaryService for HealBucketSvc { + type Response = super::HealBucketResponse; + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { ::heal_bucket(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = HealBucketSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2019,23 +1606,12 @@ pub mod node_service_server { "/node_service.NodeService/ListBucket" => { #[allow(non_camel_case_types)] struct ListBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListBucketSvc { + impl tonic::server::UnaryService for ListBucketSvc { type Response = super::ListBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_bucket(&inner, request).await - }; + let fut = async move { ::list_bucket(&inner, request).await }; Box::pin(fut) } } @@ -2048,14 +1624,8 @@ pub mod node_service_server { let method = ListBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2064,23 +1634,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeBucket" => { #[allow(non_camel_case_types)] struct MakeBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeBucketSvc { + impl tonic::server::UnaryService for MakeBucketSvc { type Response = super::MakeBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_bucket(&inner, request).await - }; + let fut = async move { ::make_bucket(&inner, request).await }; Box::pin(fut) } } @@ -2093,14 +1652,8 @@ pub mod node_service_server { let method = MakeBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2109,23 +1662,12 @@ pub mod node_service_server { "/node_service.NodeService/GetBucketInfo" => { #[allow(non_camel_case_types)] struct GetBucketInfoSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for GetBucketInfoSvc { + impl tonic::server::UnaryService for GetBucketInfoSvc { type Response = super::GetBucketInfoResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::get_bucket_info(&inner, request).await - }; + let fut = async move { ::get_bucket_info(&inner, request).await }; Box::pin(fut) } } @@ -2138,14 +1680,8 @@ pub mod node_service_server { let method = GetBucketInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2154,23 +1690,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteBucket" => { #[allow(non_camel_case_types)] struct DeleteBucketSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteBucketSvc { + impl tonic::server::UnaryService for DeleteBucketSvc { type Response = super::DeleteBucketResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_bucket(&inner, request).await - }; + let fut = async move { ::delete_bucket(&inner, request).await }; Box::pin(fut) } } @@ -2183,14 +1708,8 @@ pub mod node_service_server { let method = DeleteBucketSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2199,23 +1718,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadAll" => { #[allow(non_camel_case_types)] struct ReadAllSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadAllSvc { + impl tonic::server::UnaryService for ReadAllSvc { type Response = super::ReadAllResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_all(&inner, request).await - }; + let fut = async move { ::read_all(&inner, request).await }; Box::pin(fut) } } @@ -2228,14 +1736,8 @@ pub mod node_service_server { let method = ReadAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2244,23 +1746,12 @@ pub mod node_service_server { "/node_service.NodeService/WriteAll" => { #[allow(non_camel_case_types)] struct WriteAllSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WriteAllSvc { + impl tonic::server::UnaryService for WriteAllSvc { type Response = super::WriteAllResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_all(&inner, request).await - }; + let fut = async move { ::write_all(&inner, request).await }; Box::pin(fut) } } @@ -2273,14 +1764,8 @@ pub mod node_service_server { let method = WriteAllSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2289,23 +1774,12 @@ pub mod node_service_server { "/node_service.NodeService/Delete" => { #[allow(non_camel_case_types)] struct DeleteSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteSvc { + impl tonic::server::UnaryService for DeleteSvc { type Response = super::DeleteResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete(&inner, request).await - }; + let fut = async move { ::delete(&inner, request).await }; Box::pin(fut) } } @@ -2318,14 +1792,8 @@ pub mod node_service_server { let method = DeleteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2334,23 +1802,12 @@ pub mod node_service_server { "/node_service.NodeService/VerifyFile" => { #[allow(non_camel_case_types)] struct VerifyFileSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for VerifyFileSvc { + impl tonic::server::UnaryService for VerifyFileSvc { type Response = super::VerifyFileResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::verify_file(&inner, request).await - }; + let fut = async move { ::verify_file(&inner, request).await }; Box::pin(fut) } } @@ -2363,14 +1820,8 @@ pub mod node_service_server { let method = VerifyFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2379,23 +1830,12 @@ pub mod node_service_server { "/node_service.NodeService/CheckParts" => { #[allow(non_camel_case_types)] struct CheckPartsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for CheckPartsSvc { + impl tonic::server::UnaryService for CheckPartsSvc { type Response = super::CheckPartsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::check_parts(&inner, request).await - }; + let fut = async move { ::check_parts(&inner, request).await }; Box::pin(fut) } } @@ -2408,14 +1848,8 @@ pub mod node_service_server { let method = CheckPartsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2424,23 +1858,12 @@ pub mod node_service_server { "/node_service.NodeService/RenamePart" => { #[allow(non_camel_case_types)] struct RenamePartSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenamePartSvc { + impl tonic::server::UnaryService for RenamePartSvc { type Response = super::RenamePartResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_part(&inner, request).await - }; + let fut = async move { ::rename_part(&inner, request).await }; Box::pin(fut) } } @@ -2453,14 +1876,8 @@ pub mod node_service_server { let method = RenamePartSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2469,23 +1886,12 @@ pub mod node_service_server { "/node_service.NodeService/RenameFile" => { #[allow(non_camel_case_types)] struct RenameFileSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenameFileSvc { + impl tonic::server::UnaryService for RenameFileSvc { type Response = super::RenameFileResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_file(&inner, request).await - }; + let fut = async move { ::rename_file(&inner, request).await }; Box::pin(fut) } } @@ -2498,14 +1904,8 @@ pub mod node_service_server { let method = RenameFileSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2514,21 +1914,12 @@ pub mod node_service_server { "/node_service.NodeService/Write" => { #[allow(non_camel_case_types)] struct WriteSvc(pub Arc); - impl tonic::server::UnaryService - for WriteSvc { + impl tonic::server::UnaryService for WriteSvc { type Response = super::WriteResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write(&inner, request).await - }; + let fut = async move { ::write(&inner, request).await }; Box::pin(fut) } } @@ -2541,14 +1932,8 @@ pub mod node_service_server { let method = WriteSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2557,26 +1942,13 @@ pub mod node_service_server { "/node_service.NodeService/WriteStream" => { #[allow(non_camel_case_types)] struct WriteStreamSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::StreamingService - for WriteStreamSvc { + impl tonic::server::StreamingService for WriteStreamSvc { type Response = super::WriteResponse; type ResponseStream = T::WriteStreamStream; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - tonic::Streaming, - >, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_stream(&inner, request).await - }; + let fut = async move { ::write_stream(&inner, request).await }; Box::pin(fut) } } @@ -2589,14 +1961,8 @@ pub mod node_service_server { let method = WriteStreamSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -2605,26 +1971,13 @@ pub mod node_service_server { "/node_service.NodeService/ReadAt" => { #[allow(non_camel_case_types)] struct ReadAtSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::StreamingService - for ReadAtSvc { + impl tonic::server::StreamingService for ReadAtSvc { type Response = super::ReadAtResponse; type ResponseStream = T::ReadAtStream; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - tonic::Streaming, - >, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_at(&inner, request).await - }; + let fut = async move { ::read_at(&inner, request).await }; Box::pin(fut) } } @@ -2637,14 +1990,8 @@ pub mod node_service_server { let method = ReadAtSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -2653,23 +2000,12 @@ pub mod node_service_server { "/node_service.NodeService/ListDir" => { #[allow(non_camel_case_types)] struct ListDirSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListDirSvc { + impl tonic::server::UnaryService for ListDirSvc { type Response = super::ListDirResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_dir(&inner, request).await - }; + let fut = async move { ::list_dir(&inner, request).await }; Box::pin(fut) } } @@ -2682,14 +2018,8 @@ pub mod node_service_server { let method = ListDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2698,23 +2028,12 @@ pub mod node_service_server { "/node_service.NodeService/WalkDir" => { #[allow(non_camel_case_types)] struct WalkDirSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WalkDirSvc { + impl tonic::server::UnaryService for WalkDirSvc { type Response = super::WalkDirResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::walk_dir(&inner, request).await - }; + let fut = async move { ::walk_dir(&inner, request).await }; Box::pin(fut) } } @@ -2727,14 +2046,8 @@ pub mod node_service_server { let method = WalkDirSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2743,23 +2056,12 @@ pub mod node_service_server { "/node_service.NodeService/RenameData" => { #[allow(non_camel_case_types)] struct RenameDataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RenameDataSvc { + impl tonic::server::UnaryService for RenameDataSvc { type Response = super::RenameDataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::rename_data(&inner, request).await - }; + let fut = async move { ::rename_data(&inner, request).await }; Box::pin(fut) } } @@ -2772,14 +2074,8 @@ pub mod node_service_server { let method = RenameDataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2788,23 +2084,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolumes" => { #[allow(non_camel_case_types)] struct MakeVolumesSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeVolumesSvc { + impl tonic::server::UnaryService for MakeVolumesSvc { type Response = super::MakeVolumesResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_volumes(&inner, request).await - }; + let fut = async move { ::make_volumes(&inner, request).await }; Box::pin(fut) } } @@ -2817,14 +2102,8 @@ pub mod node_service_server { let method = MakeVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2833,23 +2112,12 @@ pub mod node_service_server { "/node_service.NodeService/MakeVolume" => { #[allow(non_camel_case_types)] struct MakeVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for MakeVolumeSvc { + impl tonic::server::UnaryService for MakeVolumeSvc { type Response = super::MakeVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::make_volume(&inner, request).await - }; + let fut = async move { ::make_volume(&inner, request).await }; Box::pin(fut) } } @@ -2862,14 +2130,8 @@ pub mod node_service_server { let method = MakeVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2878,23 +2140,12 @@ pub mod node_service_server { "/node_service.NodeService/ListVolumes" => { #[allow(non_camel_case_types)] struct ListVolumesSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ListVolumesSvc { + impl tonic::server::UnaryService for ListVolumesSvc { type Response = super::ListVolumesResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::list_volumes(&inner, request).await - }; + let fut = async move { ::list_volumes(&inner, request).await }; Box::pin(fut) } } @@ -2907,14 +2158,8 @@ pub mod node_service_server { let method = ListVolumesSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2923,23 +2168,12 @@ pub mod node_service_server { "/node_service.NodeService/StatVolume" => { #[allow(non_camel_case_types)] struct StatVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for StatVolumeSvc { + impl tonic::server::UnaryService for StatVolumeSvc { type Response = super::StatVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::stat_volume(&inner, request).await - }; + let fut = async move { ::stat_volume(&inner, request).await }; Box::pin(fut) } } @@ -2952,14 +2186,8 @@ pub mod node_service_server { let method = StatVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -2968,23 +2196,12 @@ pub mod node_service_server { "/node_service.NodeService/DeletePaths" => { #[allow(non_camel_case_types)] struct DeletePathsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeletePathsSvc { + impl tonic::server::UnaryService for DeletePathsSvc { type Response = super::DeletePathsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_paths(&inner, request).await - }; + let fut = async move { ::delete_paths(&inner, request).await }; Box::pin(fut) } } @@ -2997,14 +2214,8 @@ pub mod node_service_server { let method = DeletePathsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3013,23 +2224,12 @@ pub mod node_service_server { "/node_service.NodeService/UpdateMetadata" => { #[allow(non_camel_case_types)] struct UpdateMetadataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for UpdateMetadataSvc { + impl tonic::server::UnaryService for UpdateMetadataSvc { type Response = super::UpdateMetadataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::update_metadata(&inner, request).await - }; + let fut = async move { ::update_metadata(&inner, request).await }; Box::pin(fut) } } @@ -3042,14 +2242,8 @@ pub mod node_service_server { let method = UpdateMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3058,23 +2252,12 @@ pub mod node_service_server { "/node_service.NodeService/WriteMetadata" => { #[allow(non_camel_case_types)] struct WriteMetadataSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for WriteMetadataSvc { + impl tonic::server::UnaryService for WriteMetadataSvc { type Response = super::WriteMetadataResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::write_metadata(&inner, request).await - }; + let fut = async move { ::write_metadata(&inner, request).await }; Box::pin(fut) } } @@ -3087,14 +2270,8 @@ pub mod node_service_server { let method = WriteMetadataSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3103,23 +2280,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadVersion" => { #[allow(non_camel_case_types)] struct ReadVersionSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadVersionSvc { + impl tonic::server::UnaryService for ReadVersionSvc { type Response = super::ReadVersionResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_version(&inner, request).await - }; + let fut = async move { ::read_version(&inner, request).await }; Box::pin(fut) } } @@ -3132,14 +2298,8 @@ pub mod node_service_server { let method = ReadVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3148,23 +2308,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadXL" => { #[allow(non_camel_case_types)] struct ReadXLSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadXLSvc { + impl tonic::server::UnaryService for ReadXLSvc { type Response = super::ReadXlResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_xl(&inner, request).await - }; + let fut = async move { ::read_xl(&inner, request).await }; Box::pin(fut) } } @@ -3177,14 +2326,8 @@ pub mod node_service_server { let method = ReadXLSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3193,23 +2336,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersion" => { #[allow(non_camel_case_types)] struct DeleteVersionSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVersionSvc { + impl tonic::server::UnaryService for DeleteVersionSvc { type Response = super::DeleteVersionResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_version(&inner, request).await - }; + let fut = async move { ::delete_version(&inner, request).await }; Box::pin(fut) } } @@ -3222,14 +2354,8 @@ pub mod node_service_server { let method = DeleteVersionSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3238,23 +2364,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVersions" => { #[allow(non_camel_case_types)] struct DeleteVersionsSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVersionsSvc { + impl tonic::server::UnaryService for DeleteVersionsSvc { type Response = super::DeleteVersionsResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_versions(&inner, request).await - }; + let fut = async move { ::delete_versions(&inner, request).await }; Box::pin(fut) } } @@ -3267,14 +2382,8 @@ pub mod node_service_server { let method = DeleteVersionsSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3283,23 +2392,12 @@ pub mod node_service_server { "/node_service.NodeService/ReadMultiple" => { #[allow(non_camel_case_types)] struct ReadMultipleSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ReadMultipleSvc { + impl tonic::server::UnaryService for ReadMultipleSvc { type Response = super::ReadMultipleResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::read_multiple(&inner, request).await - }; + let fut = async move { ::read_multiple(&inner, request).await }; Box::pin(fut) } } @@ -3312,14 +2410,8 @@ pub mod node_service_server { let method = ReadMultipleSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3328,23 +2420,12 @@ pub mod node_service_server { "/node_service.NodeService/DeleteVolume" => { #[allow(non_camel_case_types)] struct DeleteVolumeSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DeleteVolumeSvc { + impl tonic::server::UnaryService for DeleteVolumeSvc { type Response = super::DeleteVolumeResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::delete_volume(&inner, request).await - }; + let fut = async move { ::delete_volume(&inner, request).await }; Box::pin(fut) } } @@ -3357,14 +2438,8 @@ pub mod node_service_server { let method = DeleteVolumeSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3373,23 +2448,12 @@ pub mod node_service_server { "/node_service.NodeService/DiskInfo" => { #[allow(non_camel_case_types)] struct DiskInfoSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for DiskInfoSvc { + impl tonic::server::UnaryService for DiskInfoSvc { type Response = super::DiskInfoResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::disk_info(&inner, request).await - }; + let fut = async move { ::disk_info(&inner, request).await }; Box::pin(fut) } } @@ -3402,14 +2466,8 @@ pub mod node_service_server { let method = DiskInfoSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3418,26 +2476,13 @@ pub mod node_service_server { "/node_service.NodeService/NsScanner" => { #[allow(non_camel_case_types)] struct NsScannerSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::StreamingService - for NsScannerSvc { + impl tonic::server::StreamingService for NsScannerSvc { type Response = super::NsScannerResponse; type ResponseStream = T::NsScannerStream; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request< - tonic::Streaming, - >, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request>) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::ns_scanner(&inner, request).await - }; + let fut = async move { ::ns_scanner(&inner, request).await }; Box::pin(fut) } } @@ -3450,14 +2495,8 @@ pub mod node_service_server { let method = NsScannerSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.streaming(method, req).await; Ok(res) }; @@ -3466,23 +2505,12 @@ pub mod node_service_server { "/node_service.NodeService/Lock" => { #[allow(non_camel_case_types)] struct LockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for LockSvc { + impl tonic::server::UnaryService for LockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::lock(&inner, request).await - }; + let fut = async move { ::lock(&inner, request).await }; Box::pin(fut) } } @@ -3495,14 +2523,8 @@ pub mod node_service_server { let method = LockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3511,23 +2533,12 @@ pub mod node_service_server { "/node_service.NodeService/UnLock" => { #[allow(non_camel_case_types)] struct UnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for UnLockSvc { + impl tonic::server::UnaryService for UnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::un_lock(&inner, request).await - }; + let fut = async move { ::un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3540,14 +2551,8 @@ pub mod node_service_server { let method = UnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3556,23 +2561,12 @@ pub mod node_service_server { "/node_service.NodeService/RLock" => { #[allow(non_camel_case_types)] struct RLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RLockSvc { + impl tonic::server::UnaryService for RLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::r_lock(&inner, request).await - }; + let fut = async move { ::r_lock(&inner, request).await }; Box::pin(fut) } } @@ -3585,14 +2579,8 @@ pub mod node_service_server { let method = RLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3601,23 +2589,12 @@ pub mod node_service_server { "/node_service.NodeService/RUnLock" => { #[allow(non_camel_case_types)] struct RUnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RUnLockSvc { + impl tonic::server::UnaryService for RUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::r_un_lock(&inner, request).await - }; + let fut = async move { ::r_un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3630,14 +2607,8 @@ pub mod node_service_server { let method = RUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3646,23 +2617,12 @@ pub mod node_service_server { "/node_service.NodeService/ForceUnLock" => { #[allow(non_camel_case_types)] struct ForceUnLockSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for ForceUnLockSvc { + impl tonic::server::UnaryService for ForceUnLockSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::force_un_lock(&inner, request).await - }; + let fut = async move { ::force_un_lock(&inner, request).await }; Box::pin(fut) } } @@ -3675,14 +2635,8 @@ pub mod node_service_server { let method = ForceUnLockSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; @@ -3691,23 +2645,12 @@ pub mod node_service_server { "/node_service.NodeService/Refresh" => { #[allow(non_camel_case_types)] struct RefreshSvc(pub Arc); - impl< - T: NodeService, - > tonic::server::UnaryService - for RefreshSvc { + impl tonic::server::UnaryService for RefreshSvc { type Response = super::GenerallyLockResponse; - type Future = BoxFuture< - tonic::Response, - tonic::Status, - >; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { + type Future = BoxFuture, tonic::Status>; + fn call(&mut self, request: tonic::Request) -> Self::Future { let inner = Arc::clone(&self.0); - let fut = async move { - ::refresh(&inner, request).await - }; + let fut = async move { ::refresh(&inner, request).await }; Box::pin(fut) } } @@ -3720,36 +2663,20 @@ pub mod node_service_server { let method = RefreshSvc(inner); let codec = tonic::codec::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); + .apply_compression_config(accept_compression_encodings, send_compression_encodings) + .apply_max_message_size_config(max_decoding_message_size, max_encoding_message_size); let res = grpc.unary(method, req).await; Ok(res) }; Box::pin(fut) } - _ => { - Box::pin(async move { - let mut response = http::Response::new(empty_body()); - let headers = response.headers_mut(); - headers - .insert( - tonic::Status::GRPC_STATUS, - (tonic::Code::Unimplemented as i32).into(), - ); - headers - .insert( - http::header::CONTENT_TYPE, - tonic::metadata::GRPC_CONTENT_TYPE, - ); - Ok(response) - }) - } + _ => Box::pin(async move { + let mut response = http::Response::new(empty_body()); + let headers = response.headers_mut(); + headers.insert(tonic::Status::GRPC_STATUS, (tonic::Code::Unimplemented as i32).into()); + headers.insert(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE); + Ok(response) + }), } } } diff --git a/common/protos/src/node.proto b/common/protos/src/node.proto index 79e234ee6..f80fb10f3 100644 --- a/common/protos/src/node.proto +++ b/common/protos/src/node.proto @@ -12,6 +12,16 @@ message PingResponse { bytes body = 2; } +message HealBucketRequest { + string bucket = 1; + string options = 2; +} + +message HealBucketResponse { + bool success = 1; + optional string error_info = 2; +} + message ListBucketRequest { string options = 1; } @@ -410,6 +420,7 @@ message GenerallyLockResponse { service NodeService { /* -------------------------------meta service-------------------------- */ rpc Ping(PingRequest) returns (PingResponse) {}; + rpc HealBucket(HealBucketRequest) returns (HealBucketResponse) {}; rpc ListBucket(ListBucketRequest) returns (ListBucketResponse) {}; rpc MakeBucket(MakeBucketRequest) returns (MakeBucketResponse) {}; rpc GetBucketInfo(GetBucketInfoRequest) returns (GetBucketInfoResponse) {}; diff --git a/common/workers/Cargo.toml b/common/workers/Cargo.toml new file mode 100644 index 000000000..dfb70d140 --- /dev/null +++ b/common/workers/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "workers" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[dependencies] +common.workspace = true +tokio.workspace = true \ No newline at end of file diff --git a/common/workers/src/lib.rs b/common/workers/src/lib.rs new file mode 100644 index 000000000..3719b10aa --- /dev/null +++ b/common/workers/src/lib.rs @@ -0,0 +1 @@ +pub mod workers; diff --git a/common/workers/src/workers.rs b/common/workers/src/workers.rs new file mode 100644 index 000000000..5c03447f8 --- /dev/null +++ b/common/workers/src/workers.rs @@ -0,0 +1,87 @@ +use std::sync::Arc; +use tokio::sync::{Mutex, Notify}; + +pub struct Workers { + available: Mutex, // 可用的工作槽 + notify: Notify, // 用于通知等待的任务 + limit: usize, // 最大并发工作数 +} + +impl Workers { + // 创建 Workers 对象,允许最多 n 个作业并发执行 + pub fn new(n: usize) -> Result, &'static str> { + if n == 0 { + return Err("n must be > 0"); + } + + Ok(Arc::new(Workers { + available: Mutex::new(n), + notify: Notify::new(), + limit: n, + })) + } + + // 让一个作业获得执行的机会 + pub async fn take(&self) { + let mut available = self.available.lock().await; + while *available == 0 { + // 等待直到有可用槽 + self.notify.notified().await; + available = self.available.lock().await; + } + *available -= 1; // 减少可用槽 + } + + // 让一个作业释放其机会 + pub async fn give(&self) { + let mut available = self.available.lock().await; + *available += 1; // 增加可用槽 + self.notify.notify_one(); // 通知一个等待的任务 + } + + // 等待所有并发作业完成 + pub async fn wait(&self) { + loop { + { + let available = self.available.lock().await; + if *available == self.limit { + break; + } + } + // 等待直到所有槽都被释放 + self.notify.notified().await; + } + } + + pub async fn available(&self) -> usize { + *self.available.lock().await + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::time::Duration; + use tokio::time::sleep; + + #[tokio::test] + async fn test_workers() { + let workers = Arc::new(Workers::new(5).unwrap()); + + for _ in 0..4 { + let workers = workers.clone(); + tokio::spawn(async move { + workers.take().await; + sleep(Duration::from_secs(3)).await; + workers.give().await; + }); + } + + // Sleep: wait for spawn task started + sleep(Duration::from_secs(1)).await; + workers.wait().await; + if workers.available().await != workers.limit { + assert!(false); + } + } +} diff --git a/e2e_test/src/reliant/lock.rs b/e2e_test/src/reliant/lock.rs index fd5db5174..ea84b2787 100644 --- a/e2e_test/src/reliant/lock.rs +++ b/e2e_test/src/reliant/lock.rs @@ -33,13 +33,13 @@ async fn test_lock_unlock_rpc() -> Result<(), Box> { let response = client.lock(request).await?.into_inner(); println!("request ended"); if let Some(error_info) = response.error_info { - assert!(false, "can not get lock: {}", error_info); + panic!("can not get lock: {}", error_info); } let request = Request::new(GenerallyLockRequest { args }); let response = client.un_lock(request).await?.into_inner(); if let Some(error_info) = response.error_info { - assert!(false, "can not get un_lock: {}", error_info); + panic!("can not get un_lock: {}", error_info); } Ok(()) @@ -58,17 +58,16 @@ async fn test_lock_unlock_ns_lock() -> Result<(), Box> { vec![locker], ) .await; - assert_eq!( - ns.0.write() - .await - .get_lock(&Options { - timeout: Duration::from_secs(5), - retry_interval: Duration::from_secs(1), - }) - .await - .unwrap(), - true - ); + assert!(ns + .0 + .write() + .await + .get_lock(&Options { + timeout: Duration::from_secs(5), + retry_interval: Duration::from_secs(1), + }) + .await + .unwrap()); ns.0.write().await.un_lock().await.unwrap(); Ok(()) diff --git a/ecstore/Cargo.toml b/ecstore/Cargo.toml index 79370b32f..79023158b 100644 --- a/ecstore/Cargo.toml +++ b/ecstore/Cargo.toml @@ -60,6 +60,7 @@ s3s-policy.workspace = true rand.workspace = true pin-project-lite.workspace = true md-5.workspace = true +workers.workspace = true [target.'cfg(not(windows))'.dependencies] diff --git a/ecstore/src/bitrot.rs b/ecstore/src/bitrot.rs index 98c7a6896..198c6a226 100644 --- a/ecstore/src/bitrot.rs +++ b/ecstore/src/bitrot.rs @@ -103,7 +103,7 @@ impl Hasher { } impl BitrotAlgorithm { - pub fn new(&self) -> Hasher { + pub fn new_hasher(&self) -> Hasher { match self { BitrotAlgorithm::SHA256 => Hasher::SHA256(Sha256::new()), BitrotAlgorithm::HighwayHash256 | BitrotAlgorithm::HighwayHash256S => { @@ -186,10 +186,8 @@ pub fn new_bitrot_reader( } pub async fn close_bitrot_writers(writers: &mut [Option]) -> Result<()> { - for w in writers.into_iter() { - if let Some(w) = w { - let _ = w.close().await?; - } + for w in writers.iter_mut().flatten() { + w.close().await?; } Ok(()) @@ -207,7 +205,7 @@ pub fn bitrot_shard_file_size(size: usize, shard_size: usize, algo: BitrotAlgori if algo != BitrotAlgorithm::HighwayHash256S { return size; } - size.div_ceil(shard_size) * algo.new().size() + size + size.div_ceil(shard_size) * algo.new_hasher().size() + size } pub fn bitrot_verify( @@ -219,7 +217,7 @@ pub fn bitrot_verify( mut shard_size: usize, ) -> Result<()> { if algo != BitrotAlgorithm::HighwayHash256S { - let mut h = algo.new(); + let mut h = algo.new_hasher(); h.update(r.get_ref()); if h.finalize() != want { return Err(Error::new(DiskError::FileCorrupt)); @@ -227,7 +225,7 @@ pub fn bitrot_verify( return Ok(()); } - let mut h = algo.new(); + let mut h = algo.new_hasher(); let mut hash_buf = vec![0; h.size()]; let mut left = want_size; @@ -271,7 +269,7 @@ impl WholeBitrotWriter { volume: volume.to_string(), file_path: file_path.to_string(), _shard_size: shard_size, - hash: algo.new(), + hash: algo.new_hasher(), } } } @@ -353,7 +351,7 @@ impl StreamingBitrotWriter { algo: BitrotAlgorithm, shard_size: usize, ) -> Result { - let hasher = algo.new(); + let hasher = algo.new_hasher(); let (tx, mut rx) = mpsc::channel::>>(10); let total_file_size = length.div_ceil(shard_size) * hasher.size() + length; @@ -362,7 +360,7 @@ impl StreamingBitrotWriter { let task = spawn(async move { loop { if let Some(Some(buf)) = rx.recv().await { - let _ = writer.write(&buf).await.unwrap(); + writer.write(&buf).await.unwrap(); continue; } @@ -389,7 +387,7 @@ impl Writer for StreamingBitrotWriter { return Ok(()); } self.hasher.reset(); - self.hasher.update(&buf); + self.hasher.update(buf); let hash_bytes = self.hasher.clone().finalize(); let _ = self.tx.send(Some(hash_bytes)).await?; let _ = self.tx.send(Some(buf.to_vec())).await?; @@ -430,7 +428,7 @@ impl StreamingBitrotReader { till_offset: usize, shard_size: usize, ) -> Self { - let hasher = algo.new(); + let hasher = algo.new_hasher(); Self { disk, _data: data.to_vec(), @@ -489,7 +487,7 @@ pub struct BitrotFileWriter { impl BitrotFileWriter { pub fn new(inner: FileWriter, algo: BitrotAlgorithm, _shard_size: usize) -> Self { - let hasher = algo.new(); + let hasher = algo.new_hasher(); Self { inner, hasher, @@ -513,7 +511,7 @@ impl Writer for BitrotFileWriter { return Ok(()); } self.hasher.reset(); - self.hasher.update(&buf); + self.hasher.update(buf); let hash_bytes = self.hasher.clone().finalize(); let _ = self.inner.write(&hash_bytes).await?; let _ = self.inner.write(buf).await?; @@ -544,7 +542,7 @@ struct BitrotFileReader { impl BitrotFileReader { pub fn new(inner: FileReader, algo: BitrotAlgorithm, _till_offset: usize, shard_size: usize) -> Self { - let hasher = algo.new(); + let hasher = algo.new_hasher(); Self { inner, // till_offset: ceil(till_offset, shard_size) * hasher.size() + till_offset, @@ -648,7 +646,7 @@ mod test { } let checksum = decode_to_vec(checksums.get(algo).unwrap()).unwrap(); - let mut h = algo.new(); + let mut h = algo.new_hasher(); let mut msg = Vec::with_capacity(h.size() * h.block_size()); let mut sum = Vec::with_capacity(h.size()); @@ -656,7 +654,7 @@ mod test { h.update(&msg); sum = h.finalize(); msg.extend(sum.clone()); - h = algo.new(); + h = algo.new_hasher(); } if checksum != sum { diff --git a/ecstore/src/bucket/utils.rs b/ecstore/src/bucket/utils.rs index f7dc8dfe2..613f1b3ba 100644 --- a/ecstore/src/bucket/utils.rs +++ b/ecstore/src/bucket/utils.rs @@ -39,10 +39,8 @@ pub fn check_bucket_name_common(bucket_name: &str, strict: bool) -> Result<(), E if !VALID_BUCKET_NAME_STRICT.is_match(bucket_name_trimmed) { return Err(Error::msg("Bucket name contains invalid characters")); } - } else { - if !VALID_BUCKET_NAME.is_match(bucket_name_trimmed) { - return Err(Error::msg("Bucket name contains invalid characters")); - } + } else if !VALID_BUCKET_NAME.is_match(bucket_name_trimmed) { + return Err(Error::msg("Bucket name contains invalid characters")); } Ok(()) } diff --git a/ecstore/src/bucket/versioning/mod.rs b/ecstore/src/bucket/versioning/mod.rs index 5efe2f80d..6ad2e4014 100644 --- a/ecstore/src/bucket/versioning/mod.rs +++ b/ecstore/src/bucket/versioning/mod.rs @@ -40,10 +40,8 @@ impl VersioningApi for VersioningConfiguration { } if let Some(status) = self.status.as_ref() { - if status.as_str() == BucketVersioningStatus::ENABLED { - if prefix.is_empty() { - return false; - } + if status.as_str() == BucketVersioningStatus::ENABLED && prefix.is_empty() { + return false; // TODO: ExcludeFolders } diff --git a/ecstore/src/cache_value/cache.rs b/ecstore/src/cache_value/cache.rs index fa4367197..cdd6b6c19 100644 --- a/ecstore/src/cache_value/cache.rs +++ b/ecstore/src/cache_value/cache.rs @@ -54,8 +54,10 @@ impl Cache { .duration_since(UNIX_EPOCH) .expect("Time went backwards") .as_secs(); - if v.is_some() && now - self.last_update_ms.load(Ordering::SeqCst) < self.ttl.as_secs() { - return Ok(v.unwrap()); + if now - self.last_update_ms.load(Ordering::SeqCst) < self.ttl.as_secs() { + if let Some(v) = v { + return Ok(v); + } } if self.opts.no_wait && v.is_some() && now - self.last_update_ms.load(Ordering::SeqCst) < self.ttl.as_secs() * 2 { @@ -110,7 +112,7 @@ impl Cache { return Ok(()); } - return Err(err); + Err(err) } } } diff --git a/ecstore/src/cache_value/metacache_set.rs b/ecstore/src/cache_value/metacache_set.rs index aad3617b6..928849cf6 100644 --- a/ecstore/src/cache_value/metacache_set.rs +++ b/ecstore/src/cache_value/metacache_set.rs @@ -45,12 +45,12 @@ impl Clone for ListPathRawOptions { fallback_disks: self.fallback_disks.clone(), bucket: self.bucket.clone(), path: self.path.clone(), - recursice: self.recursice.clone(), + recursice: self.recursice, filter_prefix: self.filter_prefix.clone(), forward_to: self.forward_to.clone(), - min_disks: self.min_disks.clone(), - report_not_found: self.report_not_found.clone(), - per_disk_limit: self.per_disk_limit.clone(), + min_disks: self.min_disks, + report_not_found: self.report_not_found, + per_disk_limit: self.per_disk_limit, ..Default::default() } } @@ -80,7 +80,7 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - .walk_dir(WalkDirOptions { bucket: opts_clone.bucket.clone(), base_dir: opts_clone.path.clone(), - recursive: opts_clone.recursice.clone(), + recursive: opts_clone.recursice, report_notfound: opts_clone.report_not_found, filter_prefix: opts_clone.filter_prefix.clone(), forward_to: opts_clone.forward_to.clone(), @@ -210,13 +210,11 @@ pub async fn list_path_raw(mut rx: B_Receiver, opts: ListPathRawOptions) - } // Break if all at EOF or error. - if at_eof + has_err == readers.len() { - if has_err > 0 { - if let Some(finished_fn) = opts.finished.as_ref() { - finished_fn(&errs).await; - } - break; + if at_eof + has_err == readers.len() && has_err > 0 { + if let Some(finished_fn) = opts.finished.as_ref() { + finished_fn(&errs).await; } + break; } if agree == readers.len() { diff --git a/ecstore/src/config/common.rs b/ecstore/src/config/common.rs index e5b9e3d70..d5d44b44d 100644 --- a/ecstore/src/config/common.rs +++ b/ecstore/src/config/common.rs @@ -15,7 +15,7 @@ use s3s::dto::StreamingBlob; use s3s::Body; use tracing::error; -const CONFIG_PREFIX: &str = "config"; +pub const CONFIG_PREFIX: &str = "config"; const CONFIG_FILE: &str = "config.json"; pub const STORAGE_CLASS_SUB_SYS: &str = "storage_class"; @@ -161,32 +161,29 @@ async fn apply_dynamic_config(cfg: &mut Config, api: &ECStore) -> Result<()> { Ok(()) } -async fn apply_dynamic_config_for_sub_sys(cfg: &mut Config, api: &ECStore, subsys: &String) -> Result<()> { +async fn apply_dynamic_config_for_sub_sys(cfg: &mut Config, api: &ECStore, subsys: &str) -> Result<()> { let set_drive_counts = api.set_drive_counts(); - match subsys.as_str() { - STORAGE_CLASS_SUB_SYS => { - let kvs = match cfg.get_value(STORAGE_CLASS_SUB_SYS, DEFAULT_KV_KEY) { - Some(res) => res, - None => KVS::new(), - }; + if subsys == STORAGE_CLASS_SUB_SYS { + let kvs = match cfg.get_value(STORAGE_CLASS_SUB_SYS, DEFAULT_KV_KEY) { + Some(res) => res, + None => KVS::new(), + }; - for (i, count) in set_drive_counts.iter().enumerate() { - match storageclass::lookup_config(&kvs, *count) { - Ok(res) => { - if i == 0 && GLOBAL_StorageClass.get().is_none() { - if let Err(r) = GLOBAL_StorageClass.set(res) { - error!("GLOBAL_StorageClass.set failed {:?}", r); - } + for (i, count) in set_drive_counts.iter().enumerate() { + match storageclass::lookup_config(&kvs, *count) { + Ok(res) => { + if i == 0 && GLOBAL_StorageClass.get().is_none() { + if let Err(r) = GLOBAL_StorageClass.set(res) { + error!("GLOBAL_StorageClass.set failed {:?}", r); } } - Err(err) => { - error!("init storageclass err:{:?}", &err); - break; - } + } + Err(err) => { + error!("init storageclass err:{:?}", &err); + break; } } } - _ => {} } Ok(()) diff --git a/ecstore/src/config/heal.rs b/ecstore/src/config/heal.rs index 20e910a6f..913997164 100644 --- a/ecstore/src/config/heal.rs +++ b/ecstore/src/config/heal.rs @@ -37,9 +37,9 @@ fn parse_bitrot_config(s: &str) -> Result { match parse_bool(s) { Ok(enabled) => { if enabled { - return Ok(Duration::from_secs_f64(0.0)); + Ok(Duration::from_secs_f64(0.0)) } else { - return Ok(Duration::from_secs_f64(-1.0)); + Ok(Duration::from_secs_f64(-1.0)) } } Err(_) => { diff --git a/ecstore/src/config/mod.rs b/ecstore/src/config/mod.rs index 14d0f21e9..a169d6988 100644 --- a/ecstore/src/config/mod.rs +++ b/ecstore/src/config/mod.rs @@ -1,5 +1,6 @@ pub mod common; pub mod error; +#[allow(dead_code)] pub mod heal; pub mod storageclass; @@ -22,6 +23,12 @@ pub static RUSTFS_CONFIG_PREFIX: &str = "config"; pub struct ConfigSys {} +impl Default for ConfigSys { + fn default() -> Self { + Self::new() + } +} + impl ConfigSys { pub fn new() -> Self { Self {} @@ -47,6 +54,12 @@ pub struct KV { #[derive(Debug, Deserialize, Serialize, Clone)] pub struct KVS(Vec); +impl Default for KVS { + fn default() -> Self { + Self::new() + } +} + impl KVS { pub fn new() -> Self { KVS(Vec::new()) @@ -72,6 +85,12 @@ impl KVS { #[derive(Debug, Clone)] pub struct Config(HashMap>); +impl Default for Config { + fn default() -> Self { + Self::new() + } +} + impl Config { pub fn new() -> Self { let mut cfg = Config(HashMap::new()); diff --git a/ecstore/src/config/storageclass.rs b/ecstore/src/config/storageclass.rs index 6e8917250..46bc0737b 100644 --- a/ecstore/src/config/storageclass.rs +++ b/ecstore/src/config/storageclass.rs @@ -228,7 +228,7 @@ pub fn parse_storage_class(env: &str) -> Result { // only two elements allowed in the string - "scheme" and "number of parity drives" if s.len() != 2 { - return Err(Error::msg(&format!( + return Err(Error::msg(format!( "Invalid storage class format: {}. Expected 'Scheme:Number of parity drives'.", env ))); @@ -236,13 +236,13 @@ pub fn parse_storage_class(env: &str) -> Result { // only allowed scheme is "EC" if s[0] != SCHEME_PREFIX { - return Err(Error::msg(&format!("Unsupported scheme {}. Supported scheme is EC.", s[0]))); + return Err(Error::msg(format!("Unsupported scheme {}. Supported scheme is EC.", s[0]))); } // Number of parity drives should be integer let parity_drives: usize = match s[1].parse() { Ok(num) => num, - Err(_) => return Err(Error::msg(&format!("Failed to parse parity value: {}.", s[1]))), + Err(_) => return Err(Error::msg(format!("Failed to parse parity value: {}.", s[1]))), }; Ok(StorageClass { parity: parity_drives }) diff --git a/ecstore/src/disk/endpoint.rs b/ecstore/src/disk/endpoint.rs index eb4b233d9..321b06149 100644 --- a/ecstore/src/disk/endpoint.rs +++ b/ecstore/src/disk/endpoint.rs @@ -30,7 +30,13 @@ pub struct Endpoint { impl Display for Endpoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.url.scheme() == "file" { - write!(f, "{}", fs::canonicalize(self.url.path()).map_err(|_| std::fmt::Error)?.to_string_lossy().to_string()) + write!( + f, + "{}", + fs::canonicalize(self.url.path()) + .map_err(|_| std::fmt::Error)? + .to_string_lossy() + ) } else { write!(f, "{}", self.url) } diff --git a/ecstore/src/disk/error.rs b/ecstore/src/disk/error.rs index f114210cc..0bce48455 100644 --- a/ecstore/src/disk/error.rs +++ b/ecstore/src/disk/error.rs @@ -265,14 +265,7 @@ 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::() { - match e { - DiskError::FileNotFound => true, - _ => false, - } - } else { - false - } + matches!(err.downcast_ref::(), Some(DiskError::FileNotFound)) } pub fn is_sys_err_no_space(e: &io::Error) -> bool { @@ -426,18 +419,32 @@ pub fn convert_access_error(e: io::Error, per_err: DiskError) -> Error { } pub fn is_all_not_found(errs: &[Option]) -> bool { - for err in errs.iter() { - if let Some(err) = err { - if let Some(err) = err.downcast_ref::() { - match err { - DiskError::FileNotFound | DiskError::VolumeNotFound | &DiskError::FileVersionNotFound => { - continue; - } - _ => return false, + for err in errs.iter().flatten() { + if let Some(err) = err.downcast_ref::() { + match err { + DiskError::FileNotFound | DiskError::VolumeNotFound | &DiskError::FileVersionNotFound => { + continue; } + _ => return false, } } } !errs.is_empty() } + +pub fn is_all_buckets_not_found(errs: &[Option]) -> bool { + if errs.is_empty() { + return false; + } + let mut not_found_count = 0; + for err in errs.iter().flatten() { + match err.downcast_ref() { + Some(DiskError::VolumeNotFound) | Some(DiskError::DiskNotFound) => { + not_found_count += 1; + } + _ => {} + } + } + errs.len() == not_found_count +} diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index 919e88ec8..9f1a68656 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -929,7 +929,7 @@ impl DiskAPI for LocalDisk { } async fn check_parts(&self, volume: &str, path: &str, fi: &FileInfo) -> Result { - let volume_dir = self.get_bucket_path(&volume)?; + let volume_dir = self.get_bucket_path(volume)?; check_path_length(volume_dir.join(path).to_string_lossy().as_ref())?; let mut resp = CheckPartsResp { results: vec![0; fi.parts.len()], @@ -955,22 +955,16 @@ impl DiskAPI for LocalDisk { resp.results[i] = CHECK_PART_SUCCESS; } Err(err) => { - match os_err_to_file_err(err).downcast_ref() { - Some(DiskError::FileNotFound) => { - if !skip_access_checks(volume) { - if let Err(err) = access(&volume_dir).await { - match err.kind() { - ErrorKind::NotFound => { - resp.results[i] = CHECK_PART_VOLUME_NOT_FOUND; - continue; - } - _ => {} - } + if let Some(DiskError::FileNotFound) = os_err_to_file_err(err).downcast_ref() { + if !skip_access_checks(volume) { + if let Err(err) = access(&volume_dir).await { + if err.kind() == ErrorKind::NotFound { + resp.results[i] = CHECK_PART_VOLUME_NOT_FOUND; + continue; } } - resp.results[i] = CHECK_PART_FILE_NOT_FOUND; } - _ => {} + resp.results[i] = CHECK_PART_FILE_NOT_FOUND; } continue; } @@ -1966,7 +1960,7 @@ impl DiskAPI for LocalDisk { for info in obj_infos.iter() { let done = ScannerMetrics::time(ScannerMetric::ApplyVersion); let sz: usize; - (obj_deleted, sz) = item.apply_actions(&info, &size_s).await; + (obj_deleted, sz) = item.apply_actions(info, &size_s).await; done().await; if obj_deleted { @@ -2031,7 +2025,7 @@ impl DiskAPI for LocalDisk { } match HealingTracker::unmarshal_msg(&b) { Ok(h) => Some(h), - Err(_) => Some(HealingTracker::default()) + Err(_) => Some(HealingTracker::default()), } } } @@ -2046,10 +2040,7 @@ async fn get_disk_info(drive_path: PathBuf) -> Result<(Info, bool)> { if root_disk_threshold > 0 { disk_info.total <= root_disk_threshold } else { - match is_root_disk(&drive_path, SLASH_SEPARATOR) { - Ok(result) => result, - Err(_) => false, - } + is_root_disk(&drive_path, SLASH_SEPARATOR).unwrap_or_default() } } else { false diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index a19bec9b7..92afc3b81 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -39,7 +39,6 @@ use std::{ io::{Cursor, SeekFrom}, path::PathBuf, sync::Arc, - usize, }; use time::OffsetDateTime; use tokio::{ @@ -683,7 +682,7 @@ impl MetaCacheEntry { let mut fm = FileMeta::new(); fm.unmarshal_msg(&self.metadata)?; - Ok(fm.into_file_info_versions(bucket, self.name.as_str(), false)?) + fm.into_file_info_versions(bucket, self.name.as_str(), false) } pub fn matches(&self, other: &MetaCacheEntry, strict: bool) -> Result<(Option, bool)> { @@ -842,7 +841,7 @@ impl MetaCacheEntries { selected = Some(MetaCacheEntry { name: selected.as_ref().unwrap().name.clone(), cached: Some(FileMeta { - meta_ver: selected.as_ref().unwrap().cached.as_ref().unwrap().meta_ver.clone(), + meta_ver: selected.as_ref().unwrap().cached.as_ref().unwrap().meta_ver, ..Default::default() }), _reusable: true, diff --git a/ecstore/src/disk/os.rs b/ecstore/src/disk/os.rs index 8375d608a..322d5f258 100644 --- a/ecstore/src/disk/os.rs +++ b/ecstore/src/disk/os.rs @@ -56,7 +56,7 @@ pub fn is_root_disk(disk_path: &str, root_disk: &str) -> Result { return Ok(false); } - Ok(same_disk(disk_path, root_disk)?) + same_disk(disk_path, root_disk) } pub async fn make_dir_all(path: impl AsRef, base_dir: impl AsRef) -> Result<()> { diff --git a/ecstore/src/endpoints.rs b/ecstore/src/endpoints.rs index a8b9d4dee..9539343b8 100644 --- a/ecstore/src/endpoints.rs +++ b/ecstore/src/endpoints.rs @@ -117,7 +117,7 @@ impl Endpoints { // GetString - returns endpoint string of i-th endpoint (0-based), // and empty string for invalid indexes. pub fn get_string(&self, i: usize) -> String { - if i < 0 || i >= self.0.len() { + if i >= self.0.len() { return "".to_string(); } diff --git a/ecstore/src/erasure.rs b/ecstore/src/erasure.rs index 5d2bba9e0..ee1687833 100644 --- a/ecstore/src/erasure.rs +++ b/ecstore/src/erasure.rs @@ -445,7 +445,7 @@ impl Erasure { self.encoder.as_ref().unwrap().reconstruct(&mut bufs)?; } - let shards = bufs.into_iter().filter_map(|x| x).collect::>(); + let shards = bufs.into_iter().flatten().collect::>(); if shards.len() != self.parity_shards + self.data_shards { return Err(Error::from_string("can not reconstruct data")); } diff --git a/ecstore/src/global.rs b/ecstore/src/global.rs index 39c35b15a..e2c46907a 100644 --- a/ecstore/src/global.rs +++ b/ecstore/src/global.rs @@ -37,7 +37,7 @@ pub async fn set_global_deployment_id(id: Uuid) { pub async fn get_global_deployment_id() -> Uuid { let id_ptr = globalDeploymentIDPtr.read().await; - id_ptr.clone() + *id_ptr } pub async fn set_global_endpoints(eps: Vec) { diff --git a/ecstore/src/heal/background_heal_ops.rs b/ecstore/src/heal/background_heal_ops.rs index 5c5e7fb46..089eb37cd 100644 --- a/ecstore/src/heal/background_heal_ops.rs +++ b/ecstore/src/heal/background_heal_ops.rs @@ -1,5 +1,5 @@ +use s3s::{S3Error, S3ErrorCode}; use std::{cmp::Ordering, env, path::PathBuf, sync::Arc, time::Duration}; - use tokio::{ sync::{ mpsc::{self, Receiver, Sender}, @@ -7,17 +7,30 @@ use tokio::{ }, time::interval, }; -use tracing::info; +use tracing::{error, info}; use uuid::Uuid; -use crate::{ - config::RUSTFS_CONFIG_PREFIX, disk::{endpoint::Endpoint, error::DiskError, DiskAPI, DiskInfoOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, error::{Error, Result}, global::{GLOBAL_BackgroundHealRoutine, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP}, heal::{data_usage::{DATA_USAGE_CACHE_NAME, DATA_USAGE_ROOT}, data_usage_cache::DataUsageCache, heal_commands::{init_healing_tracker, load_healing_tracker}, heal_ops::NOP_HEAL}, new_object_layer_fn, store::get_disk_via_endpoint, store_api::{BucketInfo, BucketOptions, StorageAPI}, utils::path::{path_join, SLASH_SEPARATOR} -}; - use super::{ heal_commands::{HealOpts, HealResultItem}, heal_ops::{new_bg_heal_sequence, HealSequence}, }; +use crate::heal::error::ERR_RETRY_HEALING; +use crate::{ + config::RUSTFS_CONFIG_PREFIX, + disk::{endpoint::Endpoint, error::DiskError, DiskAPI, DiskInfoOptions, BUCKET_META_PREFIX, RUSTFS_META_BUCKET}, + error::{Error, Result}, + global::{GLOBAL_BackgroundHealRoutine, GLOBAL_BackgroundHealState, GLOBAL_LOCAL_DISK_MAP}, + heal::{ + data_usage::{DATA_USAGE_CACHE_NAME, DATA_USAGE_ROOT}, + data_usage_cache::DataUsageCache, + heal_commands::{init_healing_tracker, load_healing_tracker}, + heal_ops::NOP_HEAL, + }, + new_object_layer_fn, + store::get_disk_via_endpoint, + store_api::{BucketInfo, BucketOptions, StorageAPI}, + utils::path::{path_join, SLASH_SEPARATOR}, +}; pub static DEFAULT_MONITOR_NEW_DISK_INTERVAL: Duration = Duration::from_secs(10); @@ -30,6 +43,9 @@ pub async fn init_auto_heal() { .await .push_heal_local_disks(&get_local_disks_to_heal().await) .await; + tokio::spawn(async { + monitor_local_disks_and_heal().await; + }); } } } @@ -99,10 +115,27 @@ async fn monitor_local_disks_and_heal() { for disk in heal_disks.into_ref().iter() { let disk_clone = disk.clone(); tokio::spawn(async move { - GLOBAL_BackgroundHealState.write().await.set_disk_healing_status(disk_clone.clone(), true).await; - + GLOBAL_BackgroundHealState + .write() + .await + .set_disk_healing_status(disk_clone.clone(), true) + .await; + if heal_fresh_disk(&disk_clone).await.is_err() { + GLOBAL_BackgroundHealState + .write() + .await + .set_disk_healing_status(disk_clone.clone(), false) + .await; + return; + } + GLOBAL_BackgroundHealState + .write() + .await + .pop_heal_local_disks(&[disk_clone]) + .await; }); } + interval.reset(); } } @@ -110,16 +143,20 @@ async fn heal_fresh_disk(endpoint: &Endpoint) -> Result<()> { let (pool_idx, set_idx) = (endpoint.pool_idx.unwrap(), endpoint.disk_idx.unwrap()); let disk = match get_disk_via_endpoint(endpoint).await { Some(disk) => disk, - None => return Err(Error::from_string(format!("Unexpected error disk must be initialized by now after formatting: {}", endpoint.to_string()))), + None => { + return Err(Error::from_string(format!( + "Unexpected error disk must be initialized by now after formatting: {}", + endpoint + ))) + } }; if let Err(err) = disk.disk_info(&DiskInfoOptions::default()).await { match err.downcast_ref() { Some(DiskError::DriveIsRoot) => { return Ok(()); - }, - Some(DiskError::UnformattedDisk) => { - }, + } + Some(DiskError::UnformattedDisk) => {} _ => { return Err(err); } @@ -134,14 +171,21 @@ async fn heal_fresh_disk(endpoint: &Endpoint) -> Result<()> { return Ok(()); } _ => { - info!("Unable to load healing tracker on '{}': {}, re-initializing..", disk.to_string(), err.to_string()); - }, + info!( + "Unable to load healing tracker on '{}': {}, re-initializing..", + disk.to_string(), + err.to_string() + ); + } } init_healing_tracker(disk.clone(), &Uuid::new_v4().to_string()).await? } }; - info!("Healing drive '{}' - 'mc admin heal alias/ --verbose' to check the current status.", endpoint.to_string()); + info!( + "Healing drive '{}' - 'mc admin heal alias/ --verbose' to check the current status.", + endpoint.to_string() + ); let layer = new_object_layer_fn(); let lock = layer.read().await; @@ -151,11 +195,15 @@ async fn heal_fresh_disk(endpoint: &Endpoint) -> Result<()> { }; let mut buckets = store.list_bucket(&BucketOptions::default()).await?; buckets.push(BucketInfo { - name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(RUSTFS_CONFIG_PREFIX)]).to_string_lossy().to_string(), + name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(RUSTFS_CONFIG_PREFIX)]) + .to_string_lossy() + .to_string(), ..Default::default() }); buckets.push(BucketInfo { - name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(BUCKET_META_PREFIX)]).to_string_lossy().to_string(), + name: path_join(&[PathBuf::from(RUSTFS_META_BUCKET), PathBuf::from(BUCKET_META_PREFIX)]) + .to_string_lossy() + .to_string(), ..Default::default() }); @@ -170,55 +218,123 @@ async fn heal_fresh_disk(endpoint: &Endpoint) -> Result<()> { } }); - let mut cache = match DataUsageCache::load(&store.pools[pool_idx].disk_set[set_idx], DATA_USAGE_CACHE_NAME).await { - Ok(cache) => { - let data_usage_info = cache.dui(DATA_USAGE_ROOT, &Vec::new()); - tracker.objects_total_count = data_usage_info.objects_total_count; - tracker.objects_total_size = data_usage_info.objects_total_size; - cache - }, - Err(_) => DataUsageCache::default() + if let Ok(cache) = DataUsageCache::load(&store.pools[pool_idx].disk_set[set_idx], DATA_USAGE_CACHE_NAME).await { + let data_usage_info = cache.dui(DATA_USAGE_ROOT, &Vec::new()); + tracker.objects_total_count = data_usage_info.objects_total_count; + tracker.objects_total_size = data_usage_info.objects_total_size; }; - let location = disk.get_disk_location(); tracker.set_queue_buckets(&buckets).await; tracker.save().await?; - // store.pools[pool_idx].disk_set[set_idx]. - todo!() + let tracker = Arc::new(RwLock::new(tracker)); + let qb = tracker.read().await.queue_buckets.clone(); + store.pools[pool_idx].disk_set[set_idx] + .clone() + .heal_erasure_set(&qb, tracker.clone()) + .await?; + let mut tracker_w = tracker.write().await; + if tracker_w.items_failed > 0 && tracker_w.retry_attempts < 4 { + tracker_w.retry_attempts += 1; + tracker_w.reset_healing().await; + if let Err(err) = tracker_w.update().await { + info!("update tracker failed: {}", err.to_string()); + } + return Err(Error::from_string(ERR_RETRY_HEALING)); + } + + if tracker_w.items_failed > 0 { + info!( + "Healing of drive '{}' is incomplete, retried {} times (healed: {}, skipped: {}, failed: {}).", + disk.to_string(), + tracker_w.retry_attempts, + tracker_w.items_healed, + tracker_w.item_skipped, + tracker_w.items_failed + ); + } else if tracker_w.retry_attempts > 0 { + info!( + "Healing of drive '{}' is incomplete, retried {} times (healed: {}, skipped: {}).", + disk.to_string(), + tracker_w.retry_attempts, + tracker_w.items_healed, + tracker_w.item_skipped + ); + } else { + info!( + "Healing of drive '{}' is finished (healed: {}, skipped: {}).", + disk.to_string(), + tracker_w.items_healed, + tracker_w.item_skipped + ); + } + + if tracker_w.heal_id.is_empty() { + if let Err(err) = tracker_w.delete().await { + error!("delete tracker failed: {}", err.to_string()); + } + } + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => return Err(Error::from(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()))), + }; + let disks = store.get_disks(pool_idx, set_idx).await?; + for disk in disks.into_iter() { + if disk.is_none() { + continue; + } + let mut tracker = match load_healing_tracker(&disk).await { + Ok(tracker) => tracker, + Err(err) => { + match err.downcast_ref() { + Some(DiskError::FileNotFound) => {} + _ => { + info!("Unable to load healing tracker on '{:?}': {}, re-initializing..", disk, err.to_string()); + } + } + continue; + } + }; + if tracker.heal_id == tracker_w.heal_id { + tracker.finished = true; + tracker.update().await?; + } + } + Ok(()) } -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct HealTask { pub bucket: String, pub object: String, pub version_id: String, pub opts: HealOpts, - pub resp_tx: Option>>, - pub resp_rx: Option>>, + pub resp_tx: Option>, + pub resp_rx: Option>, } impl HealTask { pub fn new(bucket: &str, object: &str, version_id: &str, opts: &HealOpts) -> Self { - let (tx, rx) = mpsc::channel(10); Self { bucket: bucket.to_string(), object: object.to_string(), version_id: version_id.to_string(), - opts: opts.clone(), - resp_tx: Some(tx.into()), - resp_rx: Some(rx.into()), + opts: *opts, + resp_tx: None, + resp_rx: None, } } } pub struct HealResult { pub result: HealResultItem, - _err: Option, + pub err: Option, } pub struct HealRoutine { - tasks_tx: Sender, + pub tasks_tx: Sender, tasks_rx: Receiver, workers: usize, } @@ -265,13 +381,10 @@ impl HealRoutine { let lock = layer.read().await; let store = lock.as_ref().expect("Not init"); if task.object.is_empty() { - match store - .heal_object(&task.bucket, &task.object, &task.version_id, &task.opts) - .await - { - Ok((res, err)) => { + match store.heal_bucket(&task.bucket, &task.opts).await { + Ok(res) => { d_res = res; - d_err = err; + d_err = None; } Err(err) => d_err = Some(err), } @@ -292,7 +405,7 @@ impl HealRoutine { let _ = resp_tx .send(HealResult { result: d_res, - _err: d_err, + err: d_err, }) .await; } else { @@ -325,5 +438,5 @@ async fn heal_disk_format(opts: HealOpts) -> Result<(HealResultItem, Option() { - Ok(buf) => buf, - Err(_) => { - error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); - return; - } - }; - } else if buf.len() > 8 { - cycle_info.next = match Cursor::new(buf[..8].to_vec()).read_u64::() { - Ok(buf) => buf, - Err(_) => { - error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); - return; - } - }; - let _ = cycle_info.unmarshal_msg(&buf.split_off(8)); + match buf.len().cmp(&8) { + std::cmp::Ordering::Less => {} + std::cmp::Ordering::Equal => { + cycle_info.next = match Cursor::new(buf).read_u64::() { + Ok(buf) => buf, + Err(_) => { + error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); + return; + } + }; + } + std::cmp::Ordering::Greater => { + cycle_info.next = match Cursor::new(buf[..8].to_vec()).read_u64::() { + Ok(buf) => buf, + Err(_) => { + error!("can not decode DATA_USAGE_BLOOM_NAME_PATH"); + return; + } + }; + let _ = cycle_info.unmarshal_msg(&buf.split_off(8)); + } } loop { @@ -377,11 +381,7 @@ pub struct ScannerItem { impl ScannerItem { pub fn transform_meda_dir(&mut self) { - let split = self - .prefix - .split(SLASH_SEPARATOR) - .map(|s| PathBuf::from(s)) - .collect::>(); + let split = self.prefix.split(SLASH_SEPARATOR).map(PathBuf::from).collect::>(); if split.len() > 1 { self.prefix = path_join(&split[0..split.len() - 1]).to_string_lossy().to_string(); } else { @@ -700,13 +700,14 @@ impl FolderScanner { // Scan existing... for folder in existing_folders.iter() { let h = hash_path(&folder.name); - if !into.compacted && self.old_cache.is_compacted(&h) { - if !h.mod_(self.old_cache.info.next_cycle, DATA_USAGE_UPDATE_DIR_CYCLES) { - self.new_cache - .copy_with_children(&self.old_cache, &h, &Some(folder.parent.clone())); - into.add_child(&h); - continue; - } + if !into.compacted + && self.old_cache.is_compacted(&h) + && !h.mod_(self.old_cache.info.next_cycle, DATA_USAGE_UPDATE_DIR_CYCLES) + { + self.new_cache + .copy_with_children(&self.old_cache, &h, &Some(folder.parent.clone())); + into.add_child(&h); + continue; } (self.update_current_path)(&folder.name).await; scan(folder, into, self).await; @@ -748,7 +749,7 @@ impl FolderScanner { (self.update_current_path)(k).await; if bucket != resolver.bucket { - let _ = bg_seq + bg_seq .clone() .write() .await @@ -841,7 +842,7 @@ impl FolderScanner { } } else { let mut w = found_objs_clone.write().await; - *w = *w || true; + *w = true; } return; } @@ -866,10 +867,13 @@ impl FolderScanner { { Ok(_) => { success_versions += 1; + let mut w = found_objs_clone.write().await; - *w = *w || true; + *w = true; + } + Err(_) => { + fail_versions += 1; } - Err(_) => fail_versions += 1, } } custom.insert("success_versions", success_versions.to_string()); @@ -901,14 +905,11 @@ impl FolderScanner { break; } if !was_compacted { - self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), &into); + self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), into); } if !into.compacted && self.new_cache.info.name != folder.name { - let mut flat = self - .new_cache - .size_recursive(&this_hash.key()) - .unwrap_or(DataUsageEntry::default()); + let mut flat = self.new_cache.size_recursive(&this_hash.key()).unwrap_or_default(); flat.compacted = true; let compact = if flat.objects < DATA_SCANNER_COMPACT_LEAST_OBJECT.try_into().unwrap() { true @@ -1079,3 +1080,5 @@ pub async fn scan_data_folder( close_disk().await; Ok(s.new_cache) } + +// pub fn eval_action_from_lifecycle(lc: &BucketLifecycleConfiguration, lr: &ObjectLockConfiguration, rcfg: &ReplicationConfiguration, obj: &ObjectInfo) diff --git a/ecstore/src/heal/data_scanner_metric.rs b/ecstore/src/heal/data_scanner_metric.rs index 8791726a4..d45b372df 100644 --- a/ecstore/src/heal/data_scanner_metric.rs +++ b/ecstore/src/heal/data_scanner_metric.rs @@ -101,10 +101,11 @@ impl LockedLastMinuteLatency { { let old = self.cached.clone(); self.cached = AccElem::default(); - let mut a = AccElem::default(); - a.size = old.size; - a.total = old.total; - a.n = old.n; + let a = AccElem { + size: old.size, + total: old.total, + n: old.n, + }; let _ = self.mu.write().await; self.latency.add_all(t - 1, &a); } @@ -130,6 +131,12 @@ pub struct ScannerMetrics { current_paths: HashMap, } +impl Default for ScannerMetrics { + fn default() -> Self { + Self::new() + } +} + impl ScannerMetrics { pub fn new() -> Self { Self { diff --git a/ecstore/src/heal/data_usage.rs b/ecstore/src/heal/data_usage.rs index 75dce2bff..067bcc641 100644 --- a/ecstore/src/heal/data_usage.rs +++ b/ecstore/src/heal/data_usage.rs @@ -122,7 +122,7 @@ pub async fn store_data_usage_in_backend(mut rx: Receiver) { Some(data_usage_info) => { if let Ok(data) = serde_json::to_vec(&data_usage_info) { if attempts > 10 { - let _ = save_config(store, &format!("{}{}", DATA_USAGE_OBJ_NAME_PATH.to_string(), ".bkp"), &data).await; + let _ = save_config(store, &format!("{}{}", *DATA_USAGE_OBJ_NAME_PATH, ".bkp"), &data).await; attempts += 1; } let _ = save_config(store, &DATA_USAGE_OBJ_NAME_PATH, &data).await; diff --git a/ecstore/src/heal/data_usage_cache.rs b/ecstore/src/heal/data_usage_cache.rs index 4731eedf4..371de38cf 100644 --- a/ecstore/src/heal/data_usage_cache.rs +++ b/ecstore/src/heal/data_usage_cache.rs @@ -17,7 +17,6 @@ use std::collections::{HashMap, HashSet}; use std::hash::{DefaultHasher, Hash, Hasher}; use std::path::Path; use std::time::{Duration, SystemTime}; -use std::u64; use tokio::sync::mpsc::Sender; use tokio::time::sleep; @@ -158,7 +157,7 @@ impl SizeHistogram { for (count, oh) in self.0.iter().zip(OBJECTS_HISTOGRAM_INTERVALS.iter()) { if ByteSize::kib(1).as_u64() == oh.start && oh.end == ByteSize::mib(1).as_u64() - 1 { res.insert(oh.name.to_string(), spl_count); - } else if ByteSize::kib(1).as_u64() <= oh.start && oh.end <= ByteSize::mib(1).as_u64() - 1 { + } else if ByteSize::kib(1).as_u64() <= oh.start && oh.end < ByteSize::mib(1).as_u64() { spl_count += count; res.insert(oh.name.to_string(), *count); } else { @@ -310,7 +309,7 @@ impl DataUsageEntry { s_rep.replica_size += o_rep.replica_size; s_rep.replica_count += o_rep.replica_count; for (arn, stat) in o_rep.targets.iter() { - let st = s_rep.targets.entry(arn.clone()).or_insert(ReplicationStats::default()); + let st = s_rep.targets.entry(arn.clone()).or_default(); *st = ReplicationStats { pending_size: stat.pending_size + st.pending_size, failed_size: stat.failed_size + st.failed_size, @@ -456,7 +455,7 @@ impl DataUsageCache { tokio::spawn(async move { let _ = save_config(&store_clone, &format!("{}{}", &name_clone, ".bkp"), &buf_clone).await; }); - save_config(&store, name, &buf).await + save_config(store, name, &buf).await } pub fn replace(&mut self, path: &str, parent: &str, e: DataUsageEntry) { @@ -465,7 +464,7 @@ impl DataUsageCache { if !parent.is_empty() { let phash = hash_path(parent); let p = { - let p = self.cache.entry(phash.key()).or_insert(DataUsageEntry::default()); + let p = self.cache.entry(phash.key()).or_default(); p.add_child(&hash); p.clone() }; @@ -476,10 +475,7 @@ impl DataUsageCache { pub fn replace_hashed(&mut self, hash: &DataUsageHash, parent: &Option, e: &DataUsageEntry) { self.cache.insert(hash.key(), e.clone()); if let Some(parent) = parent { - self.cache - .entry(parent.key()) - .or_insert(DataUsageEntry::default()) - .add_child(hash); + self.cache.entry(parent.key()).or_default().add_child(hash); } } @@ -488,11 +484,7 @@ impl DataUsageCache { } pub fn find_children_copy(&mut self, h: DataUsageHash) -> DataUsageHashMap { - self.cache - .entry(h.string()) - .or_insert(DataUsageEntry::default()) - .children - .clone() + self.cache.entry(h.string()).or_default().children.clone() } pub fn flatten(&self, root: &DataUsageEntry) -> DataUsageEntry { @@ -511,21 +503,18 @@ impl DataUsageCache { } pub fn copy_with_children(&mut self, src: &DataUsageCache, hash: &DataUsageHash, parent: &Option) { - match src.cache.get(&hash.string()) { - Some(e) => { - self.cache.insert(hash.key(), e.clone()); - for ch in e.children.iter() { - if *ch == hash.key() { - return; - } - self.copy_with_children(src, &DataUsageHash(ch.to_string()), &Some(hash.clone())); - } - if let Some(parent) = parent { - let p = self.cache.entry(parent.key()).or_insert(DataUsageEntry::default()); - p.add_child(hash); + if let Some(e) = src.cache.get(&hash.string()) { + self.cache.insert(hash.key(), e.clone()); + for ch in e.children.iter() { + if *ch == hash.key() { + return; } + self.copy_with_children(src, &DataUsageHash(ch.to_string()), &Some(hash.clone())); + } + if let Some(parent) = parent { + let p = self.cache.entry(parent.key()).or_default(); + p.add_child(hash); } - None => return, } } @@ -552,7 +541,7 @@ impl DataUsageCache { if flat.replication_stats.is_some() && flat.replication_stats.as_ref().unwrap().empty() { flat.replication_stats = None; } - return Some(flat); + Some(flat) } None => None, } @@ -623,7 +612,7 @@ impl DataUsageCache { } if e.children.len() > limit && compact_self { - let mut flat = self.size_recursive(&path.key()).unwrap_or(DataUsageEntry::default()); + let mut flat = self.size_recursive(&path.key()).unwrap_or_default(); flat.compacted = true; self.delete_recursive(path); self.replace_hashed(path, &None, &flat); @@ -639,7 +628,7 @@ impl DataUsageCache { add(self, path, &mut leaves); leaves.sort_by(|a, b| a.objects.cmp(&b.objects)); - while remove > 0 && leaves.len() > 0 { + while remove > 0 && !leaves.is_empty() { let e = leaves.first().unwrap(); let candidate = e.path.clone(); if candidate == *path && !compact_self { @@ -676,7 +665,7 @@ impl DataUsageCache { let mut n = root.children.len(); for ch in root.children.iter() { - n += self.total_children_rec(&ch); + n += self.total_children_rec(ch); } n } @@ -724,7 +713,7 @@ impl DataUsageCache { None => return DataUsageInfo::default(), }; let flat = self.flatten(&e); - let dui = DataUsageInfo { + DataUsageInfo { last_update: self.info.last_update, objects_total_count: flat.objects as u64, versions_total_count: flat.versions as u64, @@ -733,8 +722,7 @@ impl DataUsageCache { buckets_count: e.children.len() as u64, buckets_usage: self.buckets_usage_info(buckets), ..Default::default() - }; - dui + } } pub fn buckets_usage_info(&self, buckets: &[BucketInfo]) -> HashMap { @@ -807,9 +795,7 @@ fn add(data_usage_cache: &DataUsageCache, path: &DataUsageHash, leaves: &mut Vec return; } - let sz = data_usage_cache - .size_recursive(&path.key()) - .unwrap_or(DataUsageEntry::default()); + let sz = data_usage_cache.size_recursive(&path.key()).unwrap_or_default(); leaves.push(Inner { objects: sz.objects, path: path.clone(), diff --git a/ecstore/src/heal/error.rs b/ecstore/src/heal/error.rs index ff6c90f72..eb092ec90 100644 --- a/ecstore/src/heal/error.rs +++ b/ecstore/src/heal/error.rs @@ -1,2 +1,5 @@ pub const ERR_IGNORE_FILE_CONTRIB: &str = "ignore this file's contribution toward data-usage"; pub const ERR_SKIP_FILE: &str = "skip this file"; +pub const ERR_HEAL_STOP_SIGNALLED: &str = "heal stop signaled"; +pub const ERR_HEAL_IDLE_TIMEOUT: &str = "healing results were not consumed for too long"; +pub const ERR_RETRY_HEALING: &str = "some items failed to heal, we will retry healing this drive again"; diff --git a/ecstore/src/heal/heal_commands.rs b/ecstore/src/heal/heal_commands.rs index 6195f922a..6950cef1e 100644 --- a/ecstore/src/heal/heal_commands.rs +++ b/ecstore/src/heal/heal_commands.rs @@ -1,9 +1,8 @@ -use std::{ - path::Path, - time::{SystemTime, UNIX_EPOCH}, -}; +use std::{path::Path, time::SystemTime}; +use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; +use time::OffsetDateTime; use tokio::sync::RwLock; use crate::{ @@ -38,7 +37,11 @@ pub const DRIVE_STATE_ROOT_MOUNT: &str = "root-mount"; pub const DRIVE_STATE_UNKNOWN: &str = "unknown"; pub const DRIVE_STATE_UNFORMATTED: &str = "unformatted"; // only returned by disk -#[derive(Clone, Copy, Debug, Default)] +lazy_static! { + pub static ref TIME_SENTINEL: OffsetDateTime = OffsetDateTime::from_unix_timestamp(0).unwrap(); +} + +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize)] pub struct HealOpts { pub recursive: bool, pub dry_run: bool, @@ -102,8 +105,8 @@ pub struct HealingDisk { pub disk_index: Option, pub endpoint: String, pub path: String, - pub started: u64, - pub last_update: u64, + pub started: Option, + pub last_update: Option, pub retry_attempts: u64, pub objects_total_count: u64, pub objects_total_size: u64, @@ -132,8 +135,8 @@ pub struct HealingTracker { pub disk_index: Option, pub path: String, pub endpoint: String, - pub started: u64, - pub last_update: u64, + pub started: Option, + pub last_update: Option, pub objects_total_count: u64, pub objects_total_size: u64, pub items_healed: u64, @@ -161,8 +164,7 @@ pub struct HealingTracker { impl HealingTracker { pub fn marshal_msg(&self) -> Result> { - serde_json::to_vec(self) - .map_err(|err| Error::from_string(err.to_string())) + serde_json::to_vec(self).map_err(|err| Error::from_string(err.to_string())) } pub fn unmarshal_msg(data: &[u8]) -> Result { @@ -187,7 +189,7 @@ impl HealingTracker { self.object = String::new(); } - pub async fn get_last_update(&self) -> u64 { + pub async fn get_last_update(&self) -> Option { let _ = self.mu.read().await; self.last_update @@ -234,7 +236,7 @@ impl HealingTracker { pub async fn update(&mut self) -> Result<()> { if let Some(disk) = &self.disk { - if healing(&disk.path().to_string_lossy().to_string()).await?.is_none() { + if healing(disk.path().to_string_lossy().as_ref()).await?.is_none() { return Err(Error::from_string(format!("healingTracker: drive {} is not marked as healing", self.id))); } let _ = self.mu.write().await; @@ -262,14 +264,11 @@ impl HealingTracker { (self.pool_index, self.set_index, self.disk_index) = store.get_pool_and_set(&self.id).await?; } - self.last_update = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_secs(); + self.last_update = Some(SystemTime::now()); let htracker_bytes = self.marshal_msg()?; - GLOBAL_BackgroundHealState.write().await.update_heal_status(&self).await; + GLOBAL_BackgroundHealState.write().await.update_heal_status(self).await; if let Some(disk) = &self.disk { let file_path = Path::new(BUCKET_META_PREFIX).join(HEALING_TRACKER_FILENAME); @@ -280,7 +279,7 @@ impl HealingTracker { Ok(()) } - async fn delete(&self) -> Result<()> { + pub async fn delete(&self) -> Result<()> { if let Some(disk) = &self.disk { let file_path = Path::new(BUCKET_META_PREFIX).join(HEALING_TRACKER_FILENAME); return disk @@ -299,7 +298,7 @@ impl HealingTracker { Ok(()) } - async fn is_healed(&self, bucket: &str) -> bool { + pub async fn is_healed(&self, bucket: &str) -> bool { let _ = self.mu.read().await; for v in self.healed_buckets.iter() { if v == bucket { @@ -310,7 +309,7 @@ impl HealingTracker { false } - async fn resume(&mut self) { + pub async fn resume(&mut self) { let _ = self.mu.write().await; self.items_healed = self.resume_items_healed; @@ -321,7 +320,7 @@ impl HealingTracker { self.bytes_skipped = self.resume_bytes_skipped; } - async fn bucket_done(&mut self, bucket: &str) { + pub async fn bucket_done(&mut self, bucket: &str) { let _ = self.mu.write().await; self.resume_items_healed = self.items_healed; @@ -383,34 +382,34 @@ impl Clone for HealingTracker { Self { disk: self.disk.clone(), id: self.id.clone(), - pool_index: self.pool_index.clone(), - set_index: self.set_index.clone(), - disk_index: self.disk_index.clone(), + pool_index: self.pool_index, + set_index: self.set_index, + disk_index: self.disk_index, path: self.path.clone(), endpoint: self.endpoint.clone(), - started: self.started.clone(), - last_update: self.last_update.clone(), - objects_total_count: self.objects_total_count.clone(), - objects_total_size: self.objects_total_size.clone(), - items_healed: self.items_healed.clone(), - items_failed: self.items_failed.clone(), - item_skipped: self.item_skipped.clone(), - bytes_done: self.bytes_done.clone(), - bytes_failed: self.bytes_failed.clone(), - bytes_skipped: self.bytes_skipped.clone(), + started: self.started, + last_update: self.last_update, + objects_total_count: self.objects_total_count, + objects_total_size: self.objects_total_size, + items_healed: self.items_healed, + items_failed: self.items_failed, + item_skipped: self.item_skipped, + bytes_done: self.bytes_done, + bytes_failed: self.bytes_failed, + bytes_skipped: self.bytes_skipped, bucket: self.bucket.clone(), object: self.object.clone(), - resume_items_healed: self.resume_items_healed.clone(), - resume_items_failed: self.resume_items_failed.clone(), - resume_items_skipped: self.resume_items_skipped.clone(), - resume_bytes_done: self.resume_bytes_done.clone(), - resume_bytes_failed: self.resume_bytes_failed.clone(), - resume_bytes_skipped: self.resume_bytes_skipped.clone(), + resume_items_healed: self.resume_items_healed, + resume_items_failed: self.resume_items_failed, + resume_items_skipped: self.resume_items_skipped, + resume_bytes_done: self.resume_bytes_done, + resume_bytes_failed: self.resume_bytes_failed, + resume_bytes_skipped: self.resume_bytes_skipped, queue_buckets: self.queue_buckets.clone(), healed_buckets: self.healed_buckets.clone(), heal_id: self.heal_id.clone(), - retry_attempts: self.retry_attempts.clone(), - finished: self.finished.clone(), + retry_attempts: self.retry_attempts, + finished: self.finished, mu: RwLock::new(false), } } @@ -441,22 +440,19 @@ pub async fn load_healing_tracker(disk: &Option) -> Result Result { - let mut healing_tracker = HealingTracker::default(); - healing_tracker.id = disk.get_disk_id().await?.map_or("".to_string(), |id| id.to_string()); - healing_tracker.heal_id = heal_id.to_string(); - healing_tracker.path = disk.to_string(); - healing_tracker.endpoint = disk.endpoint().to_string(); - healing_tracker.started = SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Time went backwards") - .as_secs(); let disk_location = disk.get_disk_location(); - healing_tracker.pool_index = disk_location.pool_idx; - healing_tracker.set_index = disk_location.set_idx; - healing_tracker.disk_index = disk_location.disk_idx; - healing_tracker.disk = Some(disk); - - Ok(healing_tracker) + Ok(HealingTracker { + id: disk.get_disk_id().await?.map_or("".to_string(), |id| id.to_string()), + heal_id: heal_id.to_string(), + path: disk.to_string(), + endpoint: disk.endpoint().to_string(), + started: Some(OffsetDateTime::now_utc()), + pool_index: disk_location.pool_idx, + set_index: disk_location.set_idx, + disk_index: disk_location.disk_idx, + disk: Some(disk), + ..Default::default() + }) } pub async fn healing(derive_path: &str) -> Result> { diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 47b5f6c17..8cfcae7e0 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -1,12 +1,34 @@ +use super::{ + background_heal_ops::HealTask, + data_scanner::HEAL_DELETE_DANGLING, + error::ERR_SKIP_FILE, + heal_commands::{ + HealItemType, HealOpts, HealResultItem, HealScanMode, HealStopSuccess, HealingDisk, HealingTracker, + HEAL_ITEM_BUCKET_METADATA, + }, +}; +use crate::heal::heal_commands::{HEAL_ITEM_BUCKET, HEAL_ITEM_OBJECT}; +use crate::store_api::StorageAPI; +use crate::{ + config::common::CONFIG_PREFIX, + disk::RUSTFS_META_BUCKET, + global::GLOBAL_BackgroundHealRoutine, + heal::{ + error::ERR_HEAL_STOP_SIGNALLED, + heal_commands::{HealDriveInfo, DRIVE_STATE_OK}, + }, +}; use crate::{ disk::{endpoint::Endpoint, MetaCacheEntry}, endpoints::Endpoints, error::{Error, Result}, global::GLOBAL_IsDistErasure, heal::heal_commands::{HealStartSuccess, HEAL_UNKNOWN_SCAN}, + new_object_layer_fn, utils::path::has_profix, }; use lazy_static::lazy_static; +use s3s::{S3Error, S3ErrorCode}; use std::{ collections::HashMap, future::Future, @@ -24,19 +46,13 @@ use tokio::{ }, time::{interval, sleep}, }; +use tracing::info; use uuid::Uuid; -use super::{ - background_heal_ops::HealTask, - data_scanner::HEAL_DELETE_DANGLING, - heal_commands::{HealItemType, HealOpts, HealResultItem, HealScanMode, HealStopSuccess, HealingDisk, HealingTracker}, -}; - type HealStatusSummary = String; type ItemsMap = HashMap; -pub type HealObjectFn = Arc Result<()> + Send + Sync>; pub type HealEntryFn = - Box Pin> + Send>> + Send>; + Arc Pin> + Send>> + Send + Sync + 'static>; pub const BG_HEALING_UUID: &str = "0000-0000-0000-0000"; pub const HEALING_TRACKER_FILENAME: &str = ".healing.bin"; @@ -174,19 +190,19 @@ impl HealSequence { } impl HealSequence { - fn get_scanned_items_count(&self) -> usize { + fn _get_scanned_items_count(&self) -> usize { self.scanned_items_map.values().sum() } - fn get_scanned_items_map(&self) -> ItemsMap { + fn _get_scanned_items_map(&self) -> ItemsMap { self.scanned_items_map.clone() } - fn get_healed_items_map(&self) -> ItemsMap { + fn _get_healed_items_map(&self) -> ItemsMap { self.healed_items_map.clone() } - fn get_heal_failed_items_map(&self) -> ItemsMap { + fn _get_heal_failed_items_map(&self) -> ItemsMap { self.heal_failed_items_map.clone() } @@ -223,11 +239,11 @@ impl HealSequence { } async fn has_ended(&self) -> bool { - if self.client_token == BG_HEALING_UUID.to_string() { + if self.client_token == *BG_HEALING_UUID { return false; } - !(*(self.end_time.read().await) == self.start_time) + *(self.end_time.read().await) != self.start_time } async fn stop(&self) { @@ -238,6 +254,7 @@ impl HealSequence { async fn push_heal_result_item(&self, r: &HealResultItem) -> Result<()> { let mut r = r.clone(); let mut interval_timer = interval(HEAL_UNCONSUMED_TIMEOUT); + #[allow(unused_assignments)] let mut items_len = 0; loop { { @@ -282,31 +299,108 @@ impl HealSequence { task.opts.scan_mode = HEAL_UNKNOWN_SCAN; } - self.count_scanned(heal_type); + self.count_scanned(heal_type.clone()); - if source.no_wait {} - - todo!() - } - - fn heal_disk_meta() -> Result<()> { - todo!() - } - - fn heal_items(&self, buckets_only: bool) -> Result<()> { - if self.client_token == BG_HEALING_UUID.to_string() { + if source.no_wait { + let task_str = format!("{:?}", task); + if GLOBAL_BackgroundHealRoutine.read().await.tasks_tx.try_send(task).is_ok() { + info!("Task in the queue: {:?}", task_str); + } return Ok(()); } - todo!() + let (resp_tx, mut resp_rx) = mpsc::channel(1); + task.resp_tx = Some(resp_tx); + + let task_str = format!("{:?}", task); + if GLOBAL_BackgroundHealRoutine.read().await.tasks_tx.try_send(task).is_ok() { + info!("Task in the queue: {:?}", task_str); + } + let count_ok_drives = |drivers: &[HealDriveInfo]| { + let mut count = 0; + for drive in drivers.iter() { + if drive.state == DRIVE_STATE_OK { + count += 1; + } + } + count + }; + + loop { + match resp_rx.recv().await { + Some(mut res) => { + if res.err.is_none() { + self.count_healed(heal_type.clone()); + } else { + self.count_failed(heal_type.clone()); + } + if !self.report_progress { + if let Some(err) = res.err { + if err.to_string() == ERR_SKIP_FILE { + return Ok(()); + } + return Err(err); + } else { + return Ok(()); + } + } + res.result.heal_item_type = heal_type.clone(); + if let Some(err) = res.err.as_ref() { + res.result.detail = err.to_string(); + } + if res.result.parity_blocks > 0 + && res.result.data_blocks > 0 + && res.result.data_blocks > res.result.parity_blocks + { + let got = count_ok_drives(&res.result.after); + if got < res.result.parity_blocks { + res.result.detail = format!( + "quorum loss - expected {} minimum, got drive states in OK {}", + res.result.parity_blocks, got + ); + } + } + return self.push_heal_result_item(&res.result).await; + } + None => return Ok(()), + } + } } - async fn traverse_and_heal(&self) { + async fn heal_disk_meta(h: Arc>) -> Result<()> { + HealSequence::heal_rustfs_sys_meta(h, CONFIG_PREFIX).await + } + + async fn heal_items(h: Arc>, buckets_only: bool) -> Result<()> { + if h.read().await.client_token == *BG_HEALING_UUID { + return Ok(()); + } + + Self::heal_disk_meta(h.clone()).await?; + let bucket = h.read().await.bucket.clone(); + Self::heal_bucket(h.clone(), &bucket, buckets_only).await + } + + async fn traverse_and_heal(h: Arc>) { let buckets_only = false; + let result = match Self::heal_items(h.clone(), buckets_only).await { + Ok(_) => None, + Err(err) => Some(err), + }; + let _ = h.read().await.traverse_and_heal_done_tx.read().await.send(result).await; } - fn heal_rustfs_sys_meta(&self, meta_prefix: String) -> Result<()> { - todo!() + async fn heal_rustfs_sys_meta(h: Arc>, meta_prefix: &str) -> Result<()> { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => return Err(Error::from(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()))), + }; + let setting = h.read().await.setting; + store + .heal_objects(RUSTFS_META_BUCKET, meta_prefix, &setting, h.clone(), true) + .await } async fn is_done(&self) -> bool { @@ -316,14 +410,101 @@ impl HealSequence { } false } + + pub async fn heal_bucket(hs: Arc>, bucket: &str, bucket_only: bool) -> Result<()> { + let (object, setting) = { + let mut hs_w = hs.write().await; + hs_w.queue_heal_task( + HealSource { + bucket: bucket.to_string(), + ..Default::default() + }, + HEAL_ITEM_BUCKET.to_string(), + ) + .await?; + + if bucket_only { + return Ok(()); + } + + if !hs_w.setting.recursive { + if !hs_w.object.is_empty() { + HealSequence::heal_object(hs.clone(), bucket, &hs_w.object, "", hs_w.setting.scan_mode).await?; + } + return Ok(()); + } + (hs_w.object.clone(), hs_w.setting) + }; + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => return Err(Error::from(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()))), + }; + store.heal_objects(bucket, &object, &setting, hs.clone(), false).await + } + + pub async fn heal_object( + hs: Arc>, + bucket: &str, + object: &str, + version_id: &str, + _scan_mode: HealScanMode, + ) -> Result<()> { + let mut hs_w = hs.write().await; + if hs_w.is_quitting().await { + return Err(Error::from_string(ERR_HEAL_STOP_SIGNALLED)); + } + + let setting = hs_w.setting; + hs_w.queue_heal_task( + HealSource { + bucket: bucket.to_string(), + object: object.to_string(), + version_id: version_id.to_string(), + opts: Some(setting), + ..Default::default() + }, + HEAL_ITEM_OBJECT.to_string(), + ) + .await?; + + Ok(()) + } + + pub async fn heal_meta_object( + hs: Arc>, + bucket: &str, + object: &str, + version_id: &str, + _scan_mode: HealScanMode, + ) -> Result<()> { + let mut hs_w = hs.write().await; + if hs_w.is_quitting().await { + return Err(Error::from_string(ERR_HEAL_STOP_SIGNALLED)); + } + + hs_w.queue_heal_task( + HealSource { + bucket: bucket.to_string(), + object: object.to_string(), + version_id: version_id.to_string(), + ..Default::default() + }, + HEAL_ITEM_BUCKET_METADATA.to_string(), + ) + .await?; + + Ok(()) + } } pub async fn heal_sequence_start(h: Arc>) { let r = h.read().await; { let mut current_status_w = r.current_status.write().await; - (*current_status_w).summary = HEAL_RUNNING_STATUS.to_string(); - (*current_status_w).start_time = SystemTime::now() + current_status_w.summary = HEAL_RUNNING_STATUS.to_string(); + current_status_w.start_time = SystemTime::now() .duration_since(UNIX_EPOCH) .expect("Time went backwards") .as_secs(); @@ -331,7 +512,7 @@ pub async fn heal_sequence_start(h: Arc>) { let h_clone = h.clone(); spawn(async move { - h_clone.read().await.traverse_and_heal().await; + HealSequence::traverse_and_heal(h_clone).await; }); let h_clone_1 = h.clone(); @@ -339,32 +520,27 @@ pub async fn heal_sequence_start(h: Arc>) { select! { _ = r.is_done() => { *(r.end_time.write().await) = SystemTime::now(); - let mut current_status_w = r.current_status.write().await; - (*current_status_w).summary = HEAL_FINISHED_STATUS.to_string(); + let mut current_status_w = r.current_status.write().await; + current_status_w.summary = HEAL_FINISHED_STATUS.to_string(); - spawn(async move { - let binding = h_clone_1.read().await; - let mut rx_w = binding.traverse_and_heal_done_rx.write().await; - rx_w.recv().await; + spawn(async move { + let binding = h_clone_1.read().await; + let mut rx_w = binding.traverse_and_heal_done_rx.write().await; + rx_w.recv().await; }); } result = x.recv() => { - match result { - Some(err) => { - match err { - Some(err) => { - let mut current_status_w = r.current_status.write().await; - (current_status_w).summary = HEAL_STOPPED_STATUS.to_string(); - (current_status_w).failure_detail = err.to_string(); - }, - None => { - let mut current_status_w = r.current_status.write().await; - (current_status_w).summary = HEAL_FINISHED_STATUS.to_string(); - } + if let Some(err) = result { + match err { + Some(err) => { + let mut current_status_w = r.current_status.write().await; + (current_status_w).summary = HEAL_STOPPED_STATUS.to_string(); + (current_status_w).failure_detail = err.to_string(); + }, + None => { + let mut current_status_w = r.current_status.write().await; + (current_status_w).summary = HEAL_FINISHED_STATUS.to_string(); } - }, - None => { - } } @@ -555,18 +731,16 @@ impl AllHealState { let path_s = path.to_str().unwrap(); if r.force_started { self.stop_heal_sequence(path_s).await?; - } else { - if let Some(hs) = self.get_heal_sequence(path_s).await { - if !hs.read().await.has_ended().await { - return Err(Error::from_string(format!("Heal is already running on the given path (use force-start option to stop and start afresh). The heal was started by IP {} at {:?}, token is {}", r.client_address, r.start_time, r.client_token))); - } + } else if let Some(hs) = self.get_heal_sequence(path_s).await { + if !hs.read().await.has_ended().await { + return Err(Error::from_string(format!("Heal is already running on the given path (use force-start option to stop and start afresh). The heal was started by IP {} at {:?}, token is {}", r.client_address, r.start_time, r.client_token))); } } let _ = self.mu.write().await; for (k, v) in self.heal_seq_map.iter() { - if !v.read().await.has_ended().await && (has_profix(&k, path_s) || has_profix(path_s, &k)) { + if !v.read().await.has_ended().await && (has_profix(k, path_s) || has_profix(path_s, k)) { return Err(Error::from_string(format!( "The provided heal sequence path overlaps with an existing heal path: {}", k diff --git a/ecstore/src/options.rs b/ecstore/src/options.rs index bf787c40a..2da19e2c6 100644 --- a/ecstore/src/options.rs +++ b/ecstore/src/options.rs @@ -77,7 +77,7 @@ fn get_default_opts( pub fn extract_metadata(headers: &HeaderMap) -> HashMap { let mut metadata = HashMap::new(); - extract_metadata_from_mime(&headers, &mut metadata); + extract_metadata_from_mime(headers, &mut metadata); metadata } diff --git a/ecstore/src/peer.rs b/ecstore/src/peer.rs index e76cbf765..369b47dfb 100644 --- a/ecstore/src/peer.rs +++ b/ecstore/src/peer.rs @@ -1,14 +1,26 @@ use async_trait::async_trait; use futures::future::join_all; use protos::node_service_time_out_client; -use protos::proto_gen::node_service::{DeleteBucketRequest, GetBucketInfoRequest, ListBucketRequest, MakeBucketRequest}; +use protos::proto_gen::node_service::{ + DeleteBucketRequest, GetBucketInfoRequest, HealBucketRequest, ListBucketRequest, MakeBucketRequest, +}; use regex::Regex; use std::{collections::HashMap, fmt::Debug, sync::Arc}; +use tokio::sync::RwLock; use tonic::Request; use tracing::warn; -use crate::disk::DiskAPI; +use crate::disk::error::{is_all_buckets_not_found, is_all_not_found}; +use crate::disk::{DiskAPI, DiskStore}; +use crate::global::GLOBAL_LOCAL_DISK_MAP; +use crate::heal::heal_commands::{ + HealDriveInfo, HealOpts, HealResultItem, DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE, DRIVE_STATE_OK, + HEAL_ITEM_BUCKET, +}; +use crate::heal::heal_ops::RUESTFS_RESERVED_BUCKET; +use crate::quorum::{bucket_op_ignored_errs, reduce_write_quorum_errs}; use crate::store::all_local_disk; +use crate::utils::wildcard::is_rustfs_meta_bucket_name; use crate::{ disk::{self, error::DiskError, VolumeInfo}, endpoints::{EndpointServerPools, Node}, @@ -20,6 +32,7 @@ type Client = Arc>; #[async_trait] pub trait PeerS3Client: Debug + Sync + Send + 'static { + async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result; async fn make_bucket(&self, bucket: &str, opts: &MakeBucketOptions) -> Result<()>; async fn list_bucket(&self, opts: &BucketOptions) -> Result>; async fn delete_bucket(&self, bucket: &str, opts: &DeleteBucketOptions) -> Result<()>; @@ -61,6 +74,79 @@ impl S3PeerSys { } impl S3PeerSys { + pub async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + let mut opts = *opts; + let mut futures = Vec::with_capacity(self.clients.len()); + for client in self.clients.iter() { + // client_clon + futures.push(async move { + match client.get_bucket_info(bucket, &BucketOptions::default()).await { + Ok(_) => None, + Err(err) => Some(err), + } + }); + } + let errs = join_all(futures).await; + + let mut pool_errs = Vec::new(); + for pool_idx in 0..self.pools_count { + let mut per_pool_errs = Vec::new(); + for (i, client) in self.clients.iter().enumerate() { + if let Some(v) = client.get_pools() { + if v.contains(&pool_idx) { + per_pool_errs.push(errs[i].clone()); + } + } + } + let qu = per_pool_errs.len() / 2; + pool_errs.push(reduce_write_quorum_errs(&per_pool_errs, &bucket_op_ignored_errs(), qu)); + } + + if !opts.recreate { + opts.remove = is_all_not_found(&pool_errs); + opts.recursive = !opts.remove; + } + + let mut futures = Vec::new(); + let heal_bucket_results = Arc::new(RwLock::new(vec![HealResultItem::default(); self.clients.len()])); + for (idx, client) in self.clients.iter().enumerate() { + let opts_clone = opts; + let heal_bucket_results_clone = heal_bucket_results.clone(); + futures.push(async move { + match client.heal_bucket(bucket, &opts_clone).await { + Ok(res) => { + heal_bucket_results_clone.write().await[idx] = res; + None + } + Err(err) => Some(err), + } + }); + } + let errs = join_all(futures).await; + + for pool_idx in 0..self.pools_count { + let mut per_pool_errs = Vec::new(); + for (i, client) in self.clients.iter().enumerate() { + if let Some(v) = client.get_pools() { + if v.contains(&pool_idx) { + per_pool_errs.push(errs[i].clone()); + } + } + } + let qu = per_pool_errs.len() / 2; + if let Some(pool_err) = reduce_write_quorum_errs(&per_pool_errs, &bucket_op_ignored_errs(), qu) { + return Err(pool_err); + } + } + + for (i, err) in errs.iter().enumerate() { + if err.is_none() { + return Ok(heal_bucket_results.read().await[i].clone()); + } + } + Err(DiskError::VolumeNotFound.into()) + } + pub async fn make_bucket(&self, bucket: &str, opts: &MakeBucketOptions) -> Result<()> { let mut futures = Vec::with_capacity(self.clients.len()); for cli in self.clients.iter() { @@ -236,6 +322,11 @@ impl PeerS3Client for LocalPeerS3Client { fn get_pools(&self) -> Option> { self.pools.clone() } + + async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + heal_bucket_local(bucket, opts).await + } + async fn list_bucket(&self, _opts: &BucketOptions) -> Result> { let local_disks = all_local_disk().await; @@ -420,6 +511,29 @@ impl PeerS3Client for RemotePeerS3Client { fn get_pools(&self) -> Option> { self.pools.clone() } + + async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + let options: String = serde_json::to_string(opts)?; + let mut client = node_service_time_out_client(&self.addr) + .await + .map_err(|err| Error::from_string(format!("can not get client, err: {}", err)))?; + let request = Request::new(HealBucketRequest { + bucket: bucket.to_string(), + options, + }); + let response = client.heal_bucket(request).await?.into_inner(); + if !response.success { + return Err(Error::from_string(response.error_info.unwrap_or_default())); + } + + Ok(HealResultItem { + heal_item_type: HEAL_ITEM_BUCKET.to_string(), + bucket: bucket.to_string(), + set_count: 0, + ..Default::default() + }) + } + async fn list_bucket(&self, opts: &BucketOptions) -> Result> { let options = serde_json::to_string(opts)?; let mut client = node_service_time_out_client(&self.addr) @@ -538,3 +652,134 @@ pub fn is_reserved_or_invalid_bucket(bucket_entry: &str, strict: bool) -> bool { result || is_meta_bucket(bucket_entry) || is_reserved_bucket(bucket_entry) } + +pub async fn heal_bucket_local(bucket: &str, opts: &HealOpts) -> Result { + let disks = clone_drives().await; + let before_state = Arc::new(RwLock::new(vec![String::new(); disks.len()])); + let after_state = Arc::new(RwLock::new(vec![String::new(); disks.len()])); + + let mut futures = Vec::new(); + for (index, disk) in disks.iter().enumerate() { + let disk = disk.clone(); + let bucket = bucket.to_string(); + let bs_clone = before_state.clone(); + let as_clone = after_state.clone(); + futures.push(async move { + let disk = match disk { + Some(disk) => disk, + None => { + bs_clone.write().await[index] = DRIVE_STATE_OFFLINE.to_string(); + as_clone.write().await[index] = DRIVE_STATE_OFFLINE.to_string(); + return Some(Error::new(DiskError::DiskNotFound)); + } + }; + bs_clone.write().await[index] = DRIVE_STATE_OK.to_string(); + as_clone.write().await[index] = DRIVE_STATE_OK.to_string(); + + if bucket == RUESTFS_RESERVED_BUCKET { + return None; + } + + match disk.stat_volume(&bucket).await { + Ok(_) => None, + Err(err) => match err.downcast_ref() { + Some(DiskError::DiskNotFound) => { + bs_clone.write().await[index] = DRIVE_STATE_OFFLINE.to_string(); + as_clone.write().await[index] = DRIVE_STATE_OFFLINE.to_string(); + Some(err) + } + Some(DiskError::VolumeNotFound) => { + bs_clone.write().await[index] = DRIVE_STATE_MISSING.to_string(); + as_clone.write().await[index] = DRIVE_STATE_MISSING.to_string(); + Some(err) + } + _ => { + bs_clone.write().await[index] = DRIVE_STATE_CORRUPT.to_string(); + as_clone.write().await[index] = DRIVE_STATE_CORRUPT.to_string(); + Some(err) + } + }, + } + }); + } + let errs = join_all(futures).await; + let mut res = HealResultItem { + heal_item_type: HEAL_ITEM_BUCKET.to_string(), + bucket: bucket.to_string(), + disk_count: disks.len(), + set_count: 0, + ..Default::default() + }; + + if opts.dry_run { + return Ok(res); + } + + for (disk, state) in disks.iter().zip(before_state.read().await.iter()) { + res.before.push(HealDriveInfo { + uuid: "".to_string(), + endpoint: disk.clone().map(|s| s.to_string()).unwrap_or_default(), + state: state.to_string(), + }); + } + + if !is_rustfs_meta_bucket_name(bucket) && !is_all_buckets_not_found(&errs) && opts.remove { + let mut futures = Vec::new(); + for disk in disks.iter() { + let disk = disk.clone(); + let bucket = bucket.to_string(); + futures.push(async move { + match disk { + Some(disk) => { + let _ = disk.delete_volume(&bucket).await; + None + } + None => Some(Error::new(DiskError::DiskNotFound)), + } + }); + } + + let _ = join_all(futures).await; + } + + if !opts.remove { + let mut futures = Vec::new(); + for (idx, disk) in disks.iter().enumerate() { + let disk = disk.clone(); + let bucket = bucket.to_string(); + let bs_clone = before_state.clone(); + let as_clone = after_state.clone(); + let errs_clone = errs.clone(); + futures.push(async move { + if bs_clone.read().await[idx] == DRIVE_STATE_MISSING { + match disk.as_ref().unwrap().make_volume(&bucket).await { + Ok(_) => { + as_clone.write().await[idx] = DRIVE_STATE_OK.to_string(); + return None; + } + Err(err) => { + return Some(err); + } + } + } + errs_clone[idx].clone() + }); + } + + let _ = join_all(futures).await; + } + + for (disk, state) in disks.iter().zip(after_state.read().await.iter()) { + res.before.push(HealDriveInfo { + uuid: "".to_string(), + endpoint: disk.clone().map(|s| s.to_string()).unwrap_or_default(), + state: state.to_string(), + }); + } + + Ok(res) +} + +async fn clone_drives() -> Vec> { + GLOBAL_LOCAL_DISK_MAP.read().await.values().cloned().collect::>() +} diff --git a/ecstore/src/quorum.rs b/ecstore/src/quorum.rs index aeb652c78..84d36df58 100644 --- a/ecstore/src/quorum.rs +++ b/ecstore/src/quorum.rs @@ -40,6 +40,16 @@ pub fn object_op_ignored_errs() -> Vec> { base } +// bucket_op_ignored_errs +pub fn bucket_op_ignored_errs() -> Vec> { + let mut base = base_ignored_errs(); + + let ext: Vec> = vec![Box::new(DiskError::DiskAccessDenied), Box::new(DiskError::UnformattedDisk)]; + + base.extend(ext); + base +} + // 用于检查错误是否被忽略的函数 fn is_err_ignored(err: &Error, ignored_errs: &[Box]) -> bool { ignored_errs.iter().any(|ignored_err| ignored_err.is(err)) diff --git a/ecstore/src/sets.rs b/ecstore/src/sets.rs index 7b88d9e4c..45834a8bf 100644 --- a/ecstore/src/sets.rs +++ b/ecstore/src/sets.rs @@ -17,12 +17,9 @@ use crate::{ endpoints::{Endpoints, PoolEndpoints}, error::{Error, Result}, global::{is_dist_erasure, GLOBAL_LOCAL_DISK_SET_DRIVES}, - heal::{ - heal_commands::{ - HealDriveInfo, HealOpts, HealResultItem, DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE, - DRIVE_STATE_OK, HEAL_ITEM_METADATA, - }, - heal_ops::HealObjectFn, + heal::heal_commands::{ + HealDriveInfo, HealOpts, HealResultItem, DRIVE_STATE_CORRUPT, DRIVE_STATE_MISSING, DRIVE_STATE_OFFLINE, DRIVE_STATE_OK, + HEAL_ITEM_METADATA, }, set_disk::SetDisks, store_api::{ @@ -34,6 +31,7 @@ use crate::{ utils::hash, }; +use crate::heal::heal_ops::HealSequence; use tokio::time::Duration; use tokio_util::sync::CancellationToken; use tracing::info; @@ -179,7 +177,7 @@ impl Sets { self.connect_disks().await; // TODO: config interval - let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(15 * 3)); + let mut interval = tokio::time::interval(Duration::from_secs(15 * 3)); let cloned_token = self.ctx.clone(); loop { tokio::select! { @@ -549,11 +547,9 @@ impl StorageAPI for Sets { } // Save new formats `format.json` on unformatted disks. for (fm, disk) in tmp_new_formats.iter_mut().zip(disks.iter()) { - if fm.is_some() && disk.is_some() { - if save_format_file(disk, fm, &format_op_id).await.is_err() { - let _ = disk.as_ref().unwrap().close().await; - *fm = None; - } + if fm.is_some() && disk.is_some() && save_format_file(disk, fm, &format_op_id).await.is_err() { + let _ = disk.as_ref().unwrap().close().await; + *fm = None; } } @@ -591,7 +587,14 @@ impl StorageAPI for Sets { .heal_object(bucket, object, version_id, opts) .await } - async fn heal_objects(&self, _bucket: &str, _prefix: &str, _opts: &HealOpts, _func: HealObjectFn) -> Result<()> { + async fn heal_objects( + &self, + _bucket: &str, + _prefix: &str, + _opts: &HealOpts, + _hs: Arc>, + _is_meta: bool, + ) -> Result<()> { unimplemented!() } async fn get_pool_and_set(&self, _id: &str) -> Result<(Option, Option, Option)> { @@ -604,13 +607,11 @@ impl StorageAPI for Sets { async fn _close_storage_disks(disks: &[Option]) { let mut futures = Vec::with_capacity(disks.len()); - for disk in disks.iter() { - if let Some(disk) = disk { - let disk = disk.clone(); - futures.push(tokio::spawn(async move { - let _ = disk.close().await; - })); - } + for disk in disks.iter().flatten() { + let disk = disk.clone(); + futures.push(tokio::spawn(async move { + let _ = disk.close().await; + })); } let _ = join_all(futures).await; } @@ -690,19 +691,16 @@ fn new_heal_format_sets( for (i, set) in ref_format.erasure.sets.iter().enumerate() { for j in 0..set.len() { if let Some(Some(err)) = errs.get(i * set_drive_count + j) { - match err.downcast_ref::() { - Some(DiskError::UnformattedDisk) => { - let mut fm = FormatV3::new(set_count, set_drive_count); - fm.id = ref_format.id; - fm.format = ref_format.format.clone(); - fm.version = ref_format.version.clone(); - fm.erasure.this = ref_format.erasure.sets[i][j]; - fm.erasure.sets = ref_format.erasure.sets.clone(); - fm.erasure.version = ref_format.erasure.version.clone(); - fm.erasure.distribution_algo = ref_format.erasure.distribution_algo.clone(); - new_formats[i][j] = Some(fm); - } - _ => {} + if let Some(DiskError::UnformattedDisk) = err.downcast_ref::() { + let mut fm = FormatV3::new(set_count, set_drive_count); + fm.id = ref_format.id; + fm.format = ref_format.format.clone(); + fm.version = ref_format.version.clone(); + fm.erasure.this = ref_format.erasure.sets[i][j]; + fm.erasure.sets = ref_format.erasure.sets.clone(); + fm.erasure.version = ref_format.erasure.version.clone(); + fm.erasure.distribution_algo = ref_format.erasure.distribution_algo.clone(); + new_formats[i][j] = Some(fm); } } if let (Some(format), None) = (&formats[i * set_drive_count + j], &errs[i * set_drive_count + j]) { diff --git a/ecstore/src/store.rs b/ecstore/src/store.rs index 8452bbe9a..971262c4e 100644 --- a/ecstore/src/store.rs +++ b/ecstore/src/store.rs @@ -11,7 +11,7 @@ use crate::global::{ }; use crate::heal::data_usage::{DataUsageInfo, DATA_USAGE_ROOT}; use crate::heal::heal_commands::{HealOpts, HealResultItem, HealScanMode, HEAL_ITEM_METADATA}; -use crate::heal::heal_ops::HealObjectFn; +use crate::heal::heal_ops::{HealEntryFn, HealSequence}; use crate::new_object_layer_fn; use crate::store_api::{ListMultipartsInfo, ObjectIO}; use crate::store_err::{ @@ -43,6 +43,7 @@ use http::HeaderMap; use lazy_static::lazy_static; use rand::Rng; use s3s::dto::{BucketVersioningStatus, ObjectLockConfiguration, ObjectLockEnabled, VersioningConfiguration}; +use s3s::{S3Error, S3ErrorCode}; use std::cmp::Ordering; use std::slice::Iter; use std::time::SystemTime; @@ -535,7 +536,7 @@ impl ECStore { } }); if let Err(err) = set - .ns_scanner(&all_buckets_clone, want_cycle.try_into().unwrap(), tx, heal_scan_mode) + .ns_scanner(&all_buckets_clone, want_cycle as u32, tx, heal_scan_mode) .await { let mut f_w = first_err_clone.write().await; @@ -554,7 +555,7 @@ impl ECStore { let mut ctx_clone = cancel.subscribe(); let all_buckets_clone = all_buckets.clone(); let task = tokio::spawn(async move { - let mut last_update = None; + let mut last_update: Option = None; let mut interval = interval(Duration::from_secs(30)); let all_merged = Arc::new(RwLock::new(DataUsageCache::default())); loop { @@ -563,17 +564,11 @@ impl ECStore { return; } _ = update_close_rx.recv() => { - last_update = match tokio::spawn(update_scan(all_merged.clone(), results.clone(), last_update.clone(), all_buckets_clone.clone(), updates.clone())).await { - Ok(v) => v, - Err(_) => return, - }; + update_scan(all_merged.clone(), results.clone(), &mut last_update, all_buckets_clone.clone(), updates.clone()).await; return; } _ = interval.tick() => { - last_update = match tokio::spawn(update_scan(all_merged.clone(), results.clone(), last_update.clone(), all_buckets_clone.clone(), updates.clone())).await { - Ok(v) => v, - Err(_) => return, - }; + update_scan(all_merged.clone(), results.clone(), &mut last_update, all_buckets_clone.clone(), updates.clone()).await; } } } @@ -616,8 +611,7 @@ impl ECStore { let mut idx_res = Vec::with_capacity(self.pools.len()); - let mut idx = 0; - for result in results { + for (idx, result) in results.into_iter().enumerate() { match result { Ok(res) => { idx_res.push(IndexRes { @@ -634,8 +628,6 @@ impl ECStore { }); } } - - idx += 1; } // TODO: test order @@ -693,10 +685,10 @@ impl ECStore { async fn update_scan( all_merged: Arc>, results: Arc>>, - last_update: Option, + last_update: &mut Option, all_buckets: Vec, updates: Sender, -) -> Option { +) { let mut w = all_merged.write().await; *w = DataUsageCache { info: DataUsageCacheInfo { @@ -707,15 +699,14 @@ async fn update_scan( }; for info in results.read().await.iter() { if info.info.last_update.is_none() { - return last_update; + return; } w.merge(info); } - if w.info.last_update > last_update && w.root().is_none() { + if w.info.last_update > *last_update && w.root().is_none() { let _ = updates.send(w.dui(&w.info.name, &all_buckets)).await; - return w.info.last_update; + *last_update = w.info.last_update; } - last_update } pub async fn find_local_disk(disk_path: &String) -> Option { @@ -1379,7 +1370,7 @@ impl StorageAPI for ECStore { Ok(ListMultipartsInfo { key_marker: key_marker.to_owned(), upload_id_marker: upload_id_marker.to_owned(), - max_uploads: max_uploads, + max_uploads, uploads, prefix: prefix.to_owned(), delimiter: delimiter.to_owned(), @@ -1543,8 +1534,8 @@ impl StorageAPI for ECStore { Ok((r, None)) } - async fn heal_bucket(&self, _bucket: &str, _opts: &HealOpts) -> Result { - unimplemented!() + async fn heal_bucket(&self, bucket: &str, opts: &HealOpts) -> Result { + self.peer_sys.heal_bucket(bucket, opts).await } async fn heal_object( &self, @@ -1604,7 +1595,95 @@ impl StorageAPI for ECStore { Ok((HealResultItem::default(), Some(Error::new(DiskError::FileNotFound)))) } - async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()> { + async fn heal_objects( + &self, + bucket: &str, + prefix: &str, + opts: &HealOpts, + hs: Arc>, + is_meta: bool, + ) -> Result<()> { + let opts_clone = *opts; + let heal_entry: HealEntryFn = Arc::new(move |bucket: String, entry: MetaCacheEntry, scan_mode: HealScanMode| { + let opts_clone = opts_clone; + let hs_clone = hs.clone(); + Box::pin(async move { + if entry.is_dir() { + return Ok(()); + } + + if bucket == RUSTFS_META_BUCKET + && Pattern::new("buckets/*/.metacache/*") + .map(|p| p.matches(&entry.name)) + .unwrap_or(false) + || Pattern::new("tmp/*").map(|p| p.matches(&entry.name)).unwrap_or(false) + || Pattern::new("multipart/*").map(|p| p.matches(&entry.name)).unwrap_or(false) + || Pattern::new("tmp-old/*").map(|p| p.matches(&entry.name)).unwrap_or(false) + { + return Ok(()); + } + let fivs = match entry.file_info_versions(&bucket) { + Ok(fivs) => fivs, + Err(_) => { + if is_meta { + return HealSequence::heal_meta_object(hs_clone.clone(), &bucket, &entry.name, "", scan_mode).await; + } else { + return HealSequence::heal_object(hs_clone.clone(), &bucket, &entry.name, "", scan_mode).await; + } + } + }; + + if opts_clone.remove && !opts_clone.dry_run { + let layer = new_object_layer_fn(); + let lock = layer.read().await; + let store = match lock.as_ref() { + Some(s) => s, + None => { + return Err(Error::from(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string()))) + } + }; + if let Err(err) = store.check_abandoned_parts(&bucket, &entry.name, &opts_clone).await { + info!("unable to check object {}/{} for abandoned data: {}", bucket, entry.name, err.to_string()); + } + } + for version in fivs.versions.iter() { + if is_meta { + if let Err(err) = HealSequence::heal_meta_object( + hs_clone.clone(), + &bucket, + &version.name, + &version.version_id.map(|v| v.to_string()).unwrap_or("".to_string()), + scan_mode, + ) + .await + { + match err.downcast_ref() { + Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} + _ => { + return Err(err); + } + } + } + } else if let Err(err) = HealSequence::heal_object( + hs_clone.clone(), + &bucket, + &version.name, + &version.version_id.map(|v| v.to_string()).unwrap_or("".to_string()), + scan_mode, + ) + .await + { + match err.downcast_ref() { + Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} + _ => { + return Err(err); + } + } + } + } + Ok(()) + }) + }); let mut first_err = None; for (idx, pool) in self.pools.iter().enumerate() { if opts.pool.is_some() && opts.pool.unwrap() != idx { @@ -1617,7 +1696,7 @@ impl StorageAPI for ECStore { continue; } - if let Err(err) = set.list_and_heal(bucket, prefix, opts, func.clone()).await { + if let Err(err) = set.list_and_heal(bucket, prefix, opts, heal_entry.clone()).await { if first_err.is_none() { first_err = Some(err) } @@ -1855,67 +1934,6 @@ fn check_put_object_args(bucket: &str, object: &str) -> Result<()> { Ok(()) } -pub async fn heal_entry( - bucket: String, - entry: MetaCacheEntry, - scan_mode: HealScanMode, - opts: HealOpts, - func: HealObjectFn, -) -> Result<()> { - if entry.is_dir() { - return Ok(()); - } - - // We might land at .metacache, .trash, .multipart - // no need to heal them skip, only when bucket - // is '.rustfs.sys' - if bucket == RUSTFS_META_BUCKET { - if Pattern::new("buckets/*/.metacache/*") - .map(|p| p.matches(&entry.name)) - .unwrap_or(false) - || Pattern::new("tmp/*").map(|p| p.matches(&entry.name)).unwrap_or(false) - || Pattern::new("multipart/*").map(|p| p.matches(&entry.name)).unwrap_or(false) - || Pattern::new("tmp-old/*").map(|p| p.matches(&entry.name)).unwrap_or(false) - { - return Ok(()); - } - } - - 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")), - }; - - match entry.file_info_versions(&bucket) { - Ok(fivs) => { - if opts.remove && !opts.dry_run { - if let Err(err) = store.check_abandoned_parts(&bucket, &entry.name, &opts).await { - return Err(Error::from_string(format!( - "unable to check object {}/{} for abandoned data: {}", - bucket, entry.name, err - ))); - } - } - - for version in fivs.versions.iter() { - let version_id = version.version_id.map_or("".to_string(), |version_id| version_id.to_string()); - if let Err(err) = func(&bucket, &entry.name, &version_id, scan_mode) { - match err.downcast_ref::() { - Some(DiskError::FileNotFound) | Some(DiskError::FileVersionNotFound) => {} - _ => return Err(err), - } - } - } - } - Err(_) => { - return func(&bucket, &entry.name, "", scan_mode); - } - } - Ok(()) -} - async fn get_disk_infos(disks: &[Option]) -> Vec> { let opts = &DiskInfoOptions::default(); let mut res = vec![None; disks.len()]; diff --git a/ecstore/src/store_api.rs b/ecstore/src/store_api.rs index dc8c91141..1a7c4c615 100644 --- a/ecstore/src/store_api.rs +++ b/ecstore/src/store_api.rs @@ -1,12 +1,8 @@ -use std::collections::HashMap; - +use crate::heal::heal_ops::HealSequence; use crate::{ disk::DiskStore, error::{Error, Result}, - heal::{ - heal_commands::{HealOpts, HealResultItem}, - heal_ops::HealObjectFn, - }, + heal::heal_commands::{HealOpts, HealResultItem}, utils::path::decode_dir_object, xhttp, }; @@ -15,7 +11,10 @@ use http::HeaderMap; use rmp_serde::Serializer; use s3s::dto::StreamingBlob; use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::sync::Arc; use time::OffsetDateTime; +use tokio::sync::RwLock; use uuid::Uuid; pub const ERASURE_ALGORITHM: &str = "rs-vandermonde"; @@ -920,7 +919,14 @@ pub trait StorageAPI: ObjectIO { version_id: &str, opts: &HealOpts, ) -> Result<(HealResultItem, Option)>; - async fn heal_objects(&self, bucket: &str, prefix: &str, opts: &HealOpts, func: HealObjectFn) -> Result<()>; + async fn heal_objects( + &self, + bucket: &str, + prefix: &str, + opts: &HealOpts, + hs: Arc>, + is_meta: bool, + ) -> Result<()>; async fn get_pool_and_set(&self, id: &str) -> Result<(Option, Option, Option)>; async fn check_abandoned_parts(&self, bucket: &str, object: &str, opts: &HealOpts) -> Result<()>; } diff --git a/ecstore/src/utils/bool_flag.rs b/ecstore/src/utils/bool_flag.rs index 0158e876f..45f4a4b11 100644 --- a/ecstore/src/utils/bool_flag.rs +++ b/ecstore/src/utils/bool_flag.rs @@ -2,14 +2,8 @@ use crate::error::{Error, Result}; pub fn parse_bool(str: &str) -> Result { match str { - "1" | "t" | "T" | "true" | "TRUE" | "True" | "on" | "ON" | "On" | "enabled" => { - return Ok(true); - } - "0" | "f" | "F" | "false" | "FALSE" | "False" | "off" | "OFF" | "Off" | "disabled" => { - return Ok(false); - } - _ => { - return Err(Error::from_string(format!("ParseBool: parsing {}", str))); - } + "1" | "t" | "T" | "true" | "TRUE" | "True" | "on" | "ON" | "On" | "enabled" => Ok(true), + "0" | "f" | "F" | "false" | "FALSE" | "False" | "off" | "OFF" | "Off" | "disabled" => Ok(false), + _ => Err(Error::from_string(format!("ParseBool: parsing {}", str))), } } diff --git a/ecstore/src/utils/ellipses.rs b/ecstore/src/utils/ellipses.rs index 9badb80ce..07c33c1cf 100644 --- a/ecstore/src/utils/ellipses.rs +++ b/ecstore/src/utils/ellipses.rs @@ -40,6 +40,10 @@ impl Pattern { pub fn len(&self) -> usize { self.seq.len() } + + pub fn is_empty(&self) -> bool { + self.seq.is_empty() + } } /// contains a list of patterns provided in the input. diff --git a/ecstore/src/utils/wildcard.rs b/ecstore/src/utils/wildcard.rs index e46e118de..8e178d84f 100644 --- a/ecstore/src/utils/wildcard.rs +++ b/ecstore/src/utils/wildcard.rs @@ -1,3 +1,5 @@ +use crate::disk::RUSTFS_META_BUCKET; + pub fn match_simple(pattern: &str, name: &str) -> bool { if pattern.is_empty() { return name == pattern; @@ -65,3 +67,7 @@ pub fn match_as_pattern_prefix(pattern: &str, text: &str) -> bool { } text.len() <= pattern.len() } + +pub fn is_rustfs_meta_bucket_name(bucket: &str) -> bool { + bucket.starts_with(RUSTFS_META_BUCKET) +} diff --git a/rustfs/src/grpc.rs b/rustfs/src/grpc.rs index 55884c9d2..0567f66f9 100644 --- a/rustfs/src/grpc.rs +++ b/rustfs/src/grpc.rs @@ -6,7 +6,7 @@ use ecstore::{ UpdateMetadataOpts, WalkDirOptions, }, erasure::Writer, - heal::data_usage_cache::DataUsageCache, + heal::{data_usage_cache::DataUsageCache, heal_commands::HealOpts}, peer::{LocalPeerS3Client, PeerS3Client}, store::{all_local_disk_path, find_local_disk}, store_api::{BucketOptions, DeleteBucketOptions, FileInfo, MakeBucketOptions}, @@ -21,14 +21,14 @@ use protos::{ DeleteBucketResponse, DeletePathsRequest, DeletePathsResponse, DeleteRequest, DeleteResponse, DeleteVersionRequest, DeleteVersionResponse, DeleteVersionsRequest, DeleteVersionsResponse, DeleteVolumeRequest, DeleteVolumeResponse, DiskInfoRequest, DiskInfoResponse, GenerallyLockRequest, GenerallyLockResponse, GetBucketInfoRequest, - GetBucketInfoResponse, ListBucketRequest, ListBucketResponse, ListDirRequest, ListDirResponse, ListVolumesRequest, - ListVolumesResponse, MakeBucketRequest, MakeBucketResponse, MakeVolumeRequest, MakeVolumeResponse, MakeVolumesRequest, - MakeVolumesResponse, NsScannerRequest, NsScannerResponse, PingRequest, PingResponse, ReadAllRequest, ReadAllResponse, - ReadAtRequest, ReadAtResponse, ReadMultipleRequest, ReadMultipleResponse, ReadVersionRequest, ReadVersionResponse, - ReadXlRequest, ReadXlResponse, RenameDataRequest, RenameDataResponse, RenameFileRequst, RenameFileResponse, - RenamePartRequst, RenamePartResponse, StatVolumeRequest, StatVolumeResponse, UpdateMetadataRequest, - UpdateMetadataResponse, VerifyFileRequest, VerifyFileResponse, WalkDirRequest, WalkDirResponse, WriteAllRequest, - WriteAllResponse, WriteMetadataRequest, WriteMetadataResponse, WriteRequest, WriteResponse, + GetBucketInfoResponse, HealBucketRequest, HealBucketResponse, ListBucketRequest, ListBucketResponse, ListDirRequest, + ListDirResponse, ListVolumesRequest, ListVolumesResponse, MakeBucketRequest, MakeBucketResponse, MakeVolumeRequest, + MakeVolumeResponse, MakeVolumesRequest, MakeVolumesResponse, NsScannerRequest, NsScannerResponse, PingRequest, + PingResponse, ReadAllRequest, ReadAllResponse, ReadAtRequest, ReadAtResponse, ReadMultipleRequest, ReadMultipleResponse, + ReadVersionRequest, ReadVersionResponse, ReadXlRequest, ReadXlResponse, RenameDataRequest, RenameDataResponse, + RenameFileRequst, RenameFileResponse, RenamePartRequst, RenamePartResponse, StatVolumeRequest, StatVolumeResponse, + UpdateMetadataRequest, UpdateMetadataResponse, VerifyFileRequest, VerifyFileResponse, WalkDirRequest, WalkDirResponse, + WriteAllRequest, WriteAllResponse, WriteMetadataRequest, WriteMetadataResponse, WriteRequest, WriteResponse, }, }; use tokio::sync::mpsc; @@ -110,6 +110,32 @@ impl Node for NodeService { })) } + async fn heal_bucket(&self, request: Request) -> Result, Status> { + debug!("heal bucket"); + let request = request.into_inner(); + let options = match serde_json::from_str::(&request.options) { + Ok(options) => options, + Err(err) => { + return Ok(tonic::Response::new(HealBucketResponse { + success: false, + error_info: Some(format!("decode HealOpts failed: {}", err)), + })) + } + }; + + match self.local_peer.heal_bucket(&request.bucket, &options).await { + Ok(_) => Ok(tonic::Response::new(HealBucketResponse { + success: true, + error_info: None, + })), + + Err(err) => Ok(tonic::Response::new(HealBucketResponse { + success: false, + error_info: Some(format!("heal bucket failed: {}", err)), + })), + } + } + async fn list_bucket(&self, request: Request) -> Result, Status> { debug!("list bucket"); diff --git a/rustfs/src/storage/acess.rs b/rustfs/src/storage/acess.rs index b437a3594..6a67b903d 100644 --- a/rustfs/src/storage/acess.rs +++ b/rustfs/src/storage/acess.rs @@ -51,7 +51,7 @@ impl S3Access for FS { let req_info = ReqInfo { card: cx.credentials().cloned(), - action: action, + action, ..Default::default() }; diff --git a/rustfs/src/storage/ecfs.rs b/rustfs/src/storage/ecfs.rs index 4b1f10902..ebcdb0cff 100644 --- a/rustfs/src/storage/ecfs.rs +++ b/rustfs/src/storage/ecfs.rs @@ -341,15 +341,14 @@ impl S3 for FS { let content_type = { if let Some(content_type) = info.content_type { - let ct = match ContentType::from_str(&content_type) { + match ContentType::from_str(&content_type) { Ok(res) => Some(res), Err(err) => { error!("parse content-type err {} {:?}", &content_type, err); // None } - }; - ct + } } else { None } @@ -411,15 +410,14 @@ impl S3 for FS { let content_type = { if let Some(content_type) = info.content_type { - let ct = match ContentType::from_str(&content_type) { + match ContentType::from_str(&content_type) { Ok(res) => Some(res), Err(err) => { error!("parse content-type err {} {:?}", &content_type, err); // None } - }; - ct + } } else { None } @@ -1536,9 +1534,7 @@ impl S3 for FS { } } - let mut grants = Vec::new(); - - grants.push(Grant { + let grants = vec![Grant { grantee: Some(Grantee { type_: Type::from_static(Type::CANONICAL_USER), display_name: None, @@ -1547,12 +1543,11 @@ impl S3 for FS { uri: None, }), permission: Some(Permission::from_static(Permission::FULL_CONTROL)), - }); + }]; Ok(S3Response::new(GetBucketAclOutput { grants: Some(grants), owner: Some(RUSTFS_OWNER.to_owned()), - ..Default::default() })) } @@ -1589,7 +1584,7 @@ impl S3 for FS { v.grants.is_some_and(|gs| { // !gs.is_empty() - && gs.get(0).is_some_and(|g| { + && gs.first().is_some_and(|g| { g.to_owned() .permission .is_some_and(|p| p.as_str() == Permission::FULL_CONTROL) @@ -1617,9 +1612,7 @@ impl S3 for FS { return Err(S3Error::with_message(S3ErrorCode::InternalError, format!("{}", e))); } - let mut grants = Vec::new(); - - grants.push(Grant { + let grants = vec![Grant { grantee: Some(Grantee { type_: Type::from_static(Type::CANONICAL_USER), display_name: None, @@ -1628,7 +1621,7 @@ impl S3 for FS { uri: None, }), permission: Some(Permission::from_static(Permission::FULL_CONTROL)), - }); + }]; Ok(S3Response::new(GetObjectAclOutput { grants: Some(grants), @@ -1665,7 +1658,7 @@ impl S3 for FS { v.grants.is_some_and(|gs| { // !gs.is_empty() - && gs.get(0).is_some_and(|g| { + && gs.first().is_some_and(|g| { g.to_owned() .permission .is_some_and(|p| p.as_str() == Permission::FULL_CONTROL) From ec8b73bd9ccc9d381bc9d40126108ee89c673b75 Mon Sep 17 00:00:00 2001 From: mujunxiang <1948535941@qq.com> Date: Tue, 19 Nov 2024 17:30:50 +0800 Subject: [PATCH 09/11] cllipy Signed-off-by: mujunxiang <1948535941@qq.com> --- ecstore/src/heal/data_scanner.rs | 6 ++-- ecstore/src/heal/heal_ops.rs | 62 +++++++++++++++----------------- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/ecstore/src/heal/data_scanner.rs b/ecstore/src/heal/data_scanner.rs index 2a6ba54f0..c6b1072e5 100644 --- a/ecstore/src/heal/data_scanner.rs +++ b/ecstore/src/heal/data_scanner.rs @@ -514,7 +514,9 @@ impl FolderScanner { let this_hash = hash_path(&folder.name); let was_compacted = into.compacted; - loop { + // do not really loop + let mut times = 1; + while times > 0 { let mut abandoned_children: DataUsageHashMap = if !into.compacted { self.old_cache.find_children_copy(this_hash.clone()) } else { @@ -902,7 +904,7 @@ impl FolderScanner { scan(&this, into, self).await; } } - break; + times -= 1; } if !was_compacted { self.new_cache.replace_hashed(&this_hash, &Some(folder.parent.clone()), into); diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index 8cfcae7e0..e6e5dfb85 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -326,44 +326,40 @@ impl HealSequence { count }; - loop { - match resp_rx.recv().await { - Some(mut res) => { - if res.err.is_none() { - self.count_healed(heal_type.clone()); - } else { - self.count_failed(heal_type.clone()); - } - if !self.report_progress { - if let Some(err) = res.err { - if err.to_string() == ERR_SKIP_FILE { - return Ok(()); - } - return Err(err); - } else { + match resp_rx.recv().await { + Some(mut res) => { + if res.err.is_none() { + self.count_healed(heal_type.clone()); + } else { + self.count_failed(heal_type.clone()); + } + if !self.report_progress { + if let Some(err) = res.err { + if err.to_string() == ERR_SKIP_FILE { return Ok(()); } + return Err(err); + } else { + return Ok(()); } - res.result.heal_item_type = heal_type.clone(); - if let Some(err) = res.err.as_ref() { - res.result.detail = err.to_string(); - } - if res.result.parity_blocks > 0 - && res.result.data_blocks > 0 - && res.result.data_blocks > res.result.parity_blocks - { - let got = count_ok_drives(&res.result.after); - if got < res.result.parity_blocks { - res.result.detail = format!( - "quorum loss - expected {} minimum, got drive states in OK {}", - res.result.parity_blocks, got - ); - } - } - return self.push_heal_result_item(&res.result).await; } - None => return Ok(()), + res.result.heal_item_type = heal_type.clone(); + if let Some(err) = res.err.as_ref() { + res.result.detail = err.to_string(); + } + if res.result.parity_blocks > 0 && res.result.data_blocks > 0 && res.result.data_blocks > res.result.parity_blocks + { + let got = count_ok_drives(&res.result.after); + if got < res.result.parity_blocks { + res.result.detail = format!( + "quorum loss - expected {} minimum, got drive states in OK {}", + res.result.parity_blocks, got + ); + } + } + return self.push_heal_result_item(&res.result).await; } + None => return Ok(()), } } From e6d5fe328d247c6bd1a4483738f3fe05c1b95c7c Mon Sep 17 00:00:00 2001 From: mujunxiang <1948535941@qq.com> Date: Wed, 20 Nov 2024 09:10:19 +0800 Subject: [PATCH 10/11] clippy(2) Signed-off-by: mujunxiang <1948535941@qq.com> --- ecstore/src/disk/mod.rs | 8 ++++---- ecstore/src/heal/heal_ops.rs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ecstore/src/disk/mod.rs b/ecstore/src/disk/mod.rs index 92afc3b81..ec393a1a2 100644 --- a/ecstore/src/disk/mod.rs +++ b/ecstore/src/disk/mod.rs @@ -56,8 +56,8 @@ pub type DiskStore = Arc; #[derive(Debug)] pub enum Disk { - Local(LocalDisk), - Remote(RemoteDisk), + Local(Box), + Remote(Box), } #[async_trait::async_trait] @@ -365,10 +365,10 @@ impl DiskAPI for Disk { 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(Disk::Local(s))) + Ok(Arc::new(Disk::Local(Box::new(s)))) } else { let remote_disk = remote::RemoteDisk::new(ep, opt).await?; - Ok(Arc::new(Disk::Remote(remote_disk))) + Ok(Arc::new(Disk::Remote(Box::new(remote_disk)))) } } diff --git a/ecstore/src/heal/heal_ops.rs b/ecstore/src/heal/heal_ops.rs index e6e5dfb85..c869e4ebb 100644 --- a/ecstore/src/heal/heal_ops.rs +++ b/ecstore/src/heal/heal_ops.rs @@ -357,9 +357,9 @@ impl HealSequence { ); } } - return self.push_heal_result_item(&res.result).await; + self.push_heal_result_item(&res.result).await } - None => return Ok(()), + None => Ok(()), } } From 1d81a9e40ff70719dd22172ab59ada23e379a7a7 Mon Sep 17 00:00:00 2001 From: mujunxiang <1948535941@qq.com> Date: Wed, 20 Nov 2024 09:47:10 +0800 Subject: [PATCH 11/11] fix cache bug Signed-off-by: mujunxiang <1948535941@qq.com> --- ecstore/src/cache_value/cache.rs | 6 ++++-- ecstore/src/disk/local.rs | 19 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/ecstore/src/cache_value/cache.rs b/ecstore/src/cache_value/cache.rs index cdd6b6c19..15f116dec 100644 --- a/ecstore/src/cache_value/cache.rs +++ b/ecstore/src/cache_value/cache.rs @@ -1,5 +1,7 @@ use std::{ fmt::Debug, + future::Future, + pin::Pin, ptr, sync::{ atomic::{AtomicPtr, AtomicU64, Ordering}, @@ -12,7 +14,7 @@ use tokio::{spawn, sync::Mutex}; use crate::error::Result; -type UpdateFn = Box Result + Send + Sync>; +pub type UpdateFn = Box Pin> + Send>> + Send + Sync + 'static>; #[derive(Clone, Debug, Default)] pub struct Opts { @@ -96,7 +98,7 @@ impl Cache { } async fn update(&self) -> Result<()> { - match (self.update_fn)() { + match (self.update_fn)().await { Ok(val) => { self.val.store(Box::into_raw(Box::new(val)), Ordering::SeqCst); let now = SystemTime::now() diff --git a/ecstore/src/disk/local.rs b/ecstore/src/disk/local.rs index 9f1a68656..b0b5f24e6 100644 --- a/ecstore/src/disk/local.rs +++ b/ecstore/src/disk/local.rs @@ -10,7 +10,7 @@ use super::{ }; use crate::bitrot::bitrot_verify; use crate::bucket::metadata_sys::GLOBAL_BucketMetadataSys; -use crate::cache_value::cache::{Cache, Opts}; +use crate::cache_value::cache::{Cache, Opts, UpdateFn}; use crate::disk::error::{ convert_access_error, is_sys_err_handle_invalid, is_sys_err_invalid_arg, is_sys_err_is_dir, is_sys_err_not_dir, map_err_not_exists, os_err_to_file_err, @@ -55,7 +55,6 @@ use std::{ use time::OffsetDateTime; use tokio::fs::{self, File}; use tokio::io::{AsyncReadExt, AsyncWriteExt, ErrorKind}; -use tokio::runtime::Runtime; use tokio::sync::mpsc::Sender; use tokio::sync::RwLock; use tracing::{error, info, warn}; @@ -148,10 +147,10 @@ impl LocalDisk { last_check: format_last_check, }; let root_clone = root.clone(); - let disk_id = Arc::new(id.map_or("".to_string(), |id| id.to_string())); - let update_fn = move || { - let rt = Runtime::new().unwrap(); - rt.block_on(async { + let update_fn: UpdateFn = Box::new(move || { + let disk_id = id.map_or("".to_string(), |id| id.to_string()); + let root = root_clone.clone(); + Box::pin(async move { match get_disk_info(root.clone()).await { Ok((info, root)) => { let disk_info = DiskInfo { @@ -177,14 +176,14 @@ impl LocalDisk { Err(err) => Err(err), } }) - }; + }); - let cache = Cache::new(Box::new(update_fn), Duration::from_secs(1), Opts::default()); + let cache = Cache::new(update_fn, Duration::from_secs(1), Opts::default()); // TODO: DIRECT suport // TODD: DiskInfo let mut disk = Self { - root: root_clone.clone(), + root: root.clone(), endpoint: ep.clone(), format_path, format_info: RwLock::new(format_info), @@ -200,7 +199,7 @@ impl LocalDisk { // format_data: Mutex::new(format_data), // format_last_check: Mutex::new(format_last_check), }; - let (info, _root) = get_disk_info(root_clone).await?; + let (info, _root) = get_disk_info(root).await?; disk.major = info.major; disk.minor = info.minor; disk.fstype = info.fstype;