mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
refactor(storage): resolve staged dead code in store module (#730)
Drop the store module's blanket #![allow(dead_code)] and resolve every unit it was masking, instead of keeping them staged: - write_persistent_key_only_index: the keys-only writer wrapper only had test callers; the in-process rebuild flow already exists and uses the _with_metadata variant (prepare -> rebuild, triggered lazily from the opt-in listing path). Tests call _with_metadata directly now. - ListIndexLifecycle::recover_after_restart / mark_corrupt: production derives index health per request from the persisted artifacts (index file + namespace mutation journal), and restart recovery already lives in load_persistent_key_only_index's journal restore. The persisted- lifecycle design these transitions served was superseded, and Corrupt had no detector, so the never-constructed Corrupt state/reason variants go with them. - record_list_objects_index_opt_in_fallback (+ helpers): superseded by the inline per-site fallback recording in the opt-in listing path; the recorder recomputed health with a hardcoded None provider, so it could only ever report a disabled-based reason. - Provider-contract traits (Generation/Page/PageIterator/KeyLookup): provider dispatch went the ListObjectsIndexProviderKind enum route; only ListMetadataIndexHealth is live (dyn in source-mode selection) and stays, minus its unused is_healthy default. - Delete the unused list_quorum_from_env/RUSTFS_API_LIST_QUORUM pair, fold should_resume_local_decommission and should_auto_start_rebalance_after_recovered_meta into their surviving primitives, drop get_disk_via_endpoint, and cfg(test) the remaining test-only conveniences.
This commit is contained in:
@@ -49,21 +49,6 @@ fn resolve_startup_pool_defaults_with(
|
|||||||
drive_counts.into_iter().map(ec_drives_no_config).collect()
|
drive_counts.into_iter().map(ec_drives_no_config).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_resume_local_decommission(endpoints: &EndpointServerPools, idx: usize) -> Result<bool> {
|
|
||||||
let pool = endpoints.as_ref().get(idx).ok_or_else(|| {
|
|
||||||
Error::other(format!(
|
|
||||||
"store init failed to resolve decommission resume pool index {idx} from current endpoints"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
let endpoint = pool.endpoints.as_ref().first().ok_or_else(|| {
|
|
||||||
Error::other(format!(
|
|
||||||
"store init failed to resolve decommission resume pool index {idx}: no endpoints available"
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(endpoint.is_local)
|
|
||||||
}
|
|
||||||
|
|
||||||
const LOCAL_DECOMMISSION_RESUME_MAX_CONFIG_RETRIES: usize = 6;
|
const LOCAL_DECOMMISSION_RESUME_MAX_CONFIG_RETRIES: usize = 6;
|
||||||
const LOCAL_DECOMMISSION_INITIAL_RESUME_DELAY: Duration = Duration::from_secs(60 * 3);
|
const LOCAL_DECOMMISSION_INITIAL_RESUME_DELAY: Duration = Duration::from_secs(60 * 3);
|
||||||
const LOCAL_DECOMMISSION_RESUME_RETRY_DELAY: Duration = Duration::from_secs(30);
|
const LOCAL_DECOMMISSION_RESUME_RETRY_DELAY: Duration = Duration::from_secs(30);
|
||||||
@@ -84,10 +69,6 @@ fn pool_meta_has_active_decommission(meta: &PoolMeta) -> bool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_auto_start_rebalance_after_recovered_meta(pool_meta: &PoolMeta, rebalance_meta_loaded: bool) -> bool {
|
|
||||||
should_auto_start_rebalance_after_init(pool_meta_has_active_decommission(pool_meta), rebalance_meta_loaded)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn wait_for_local_decommission_resume_delay(rx: &CancellationToken, delay: Duration) -> bool {
|
async fn wait_for_local_decommission_resume_delay(rx: &CancellationToken, delay: Duration) -> bool {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = rx.cancelled() => false,
|
_ = rx.cancelled() => false,
|
||||||
@@ -522,9 +503,9 @@ impl ECStore {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
LOCAL_DECOMMISSION_RESUME_MAX_CONFIG_RETRIES, load_pool_meta_for_startup, pool_first_endpoint_is_local,
|
LOCAL_DECOMMISSION_RESUME_MAX_CONFIG_RETRIES, load_pool_meta_for_startup, pool_first_endpoint_is_local,
|
||||||
resolve_startup_pool_defaults_with, resolve_store_init_stage_result, save_validated_pool_meta_for_startup,
|
pool_meta_has_active_decommission, resolve_startup_pool_defaults_with, resolve_store_init_stage_result,
|
||||||
should_auto_start_rebalance_after_init, should_auto_start_rebalance_after_recovered_meta,
|
save_validated_pool_meta_for_startup, should_auto_start_rebalance_after_init, should_retry_local_decommission_resume,
|
||||||
should_resume_local_decommission, should_retry_local_decommission_resume, wait_for_local_decommission_resume_delay,
|
wait_for_local_decommission_resume_delay,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "test-util")]
|
#[cfg(feature = "test-util")]
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -696,46 +677,33 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_should_resume_local_decommission_respects_local_flag() {
|
fn test_pool_first_endpoint_is_local_respects_local_flag() {
|
||||||
let mut local_endpoint = Endpoint::try_from("http://127.0.0.1:9000/data").expect("endpoint should parse");
|
let mut local_endpoint = Endpoint::try_from("http://127.0.0.1:9000/data").expect("endpoint should parse");
|
||||||
local_endpoint.is_local = true;
|
local_endpoint.is_local = true;
|
||||||
let endpoints = EndpointServerPools::from(vec![PoolEndpoints {
|
let pool = PoolEndpoints {
|
||||||
legacy: false,
|
legacy: false,
|
||||||
set_count: 1,
|
set_count: 1,
|
||||||
drives_per_set: 1,
|
drives_per_set: 1,
|
||||||
endpoints: Endpoints::from(vec![local_endpoint]),
|
endpoints: Endpoints::from(vec![local_endpoint]),
|
||||||
cmd_line: "pool-0".to_string(),
|
cmd_line: "pool-0".to_string(),
|
||||||
platform: String::new(),
|
platform: String::new(),
|
||||||
}]);
|
};
|
||||||
|
|
||||||
assert!(should_resume_local_decommission(&endpoints, 0).expect("local endpoint should resume"));
|
assert!(pool_first_endpoint_is_local(&pool));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_should_resume_local_decommission_rejects_unresolvable_pool() {
|
fn test_pool_first_endpoint_is_local_rejects_missing_endpoint() {
|
||||||
let endpoints = EndpointServerPools::default();
|
let pool = PoolEndpoints {
|
||||||
let err = should_resume_local_decommission(&endpoints, 0).expect_err("missing pool should error");
|
|
||||||
assert_eq!(
|
|
||||||
err.to_string(),
|
|
||||||
"Io error: store init failed to resolve decommission resume pool index 0 from current endpoints"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_should_resume_local_decommission_rejects_missing_endpoint() {
|
|
||||||
let endpoints = EndpointServerPools::from(vec![PoolEndpoints {
|
|
||||||
legacy: false,
|
legacy: false,
|
||||||
set_count: 1,
|
set_count: 1,
|
||||||
drives_per_set: 1,
|
drives_per_set: 1,
|
||||||
endpoints: Endpoints::from(Vec::<Endpoint>::new()),
|
endpoints: Endpoints::from(Vec::<Endpoint>::new()),
|
||||||
cmd_line: "pool-0".to_string(),
|
cmd_line: "pool-0".to_string(),
|
||||||
platform: String::new(),
|
platform: String::new(),
|
||||||
}]);
|
};
|
||||||
let err = should_resume_local_decommission(&endpoints, 0).expect_err("missing endpoint should error");
|
|
||||||
assert_eq!(
|
assert!(!pool_first_endpoint_is_local(&pool));
|
||||||
err.to_string(),
|
|
||||||
"Io error: store init failed to resolve decommission resume pool index 0: no endpoints available"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -782,7 +750,10 @@ mod tests {
|
|||||||
}));
|
}));
|
||||||
let rebalance_meta = Some(RebalanceMeta::default());
|
let rebalance_meta = Some(RebalanceMeta::default());
|
||||||
|
|
||||||
assert!(!should_auto_start_rebalance_after_recovered_meta(&pool_meta, rebalance_meta.is_some()));
|
assert!(!should_auto_start_rebalance_after_init(
|
||||||
|
pool_meta_has_active_decommission(&pool_meta),
|
||||||
|
rebalance_meta.is_some()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -790,7 +761,10 @@ mod tests {
|
|||||||
let pool_meta = init_test_pool_meta(None);
|
let pool_meta = init_test_pool_meta(None);
|
||||||
let rebalance_meta = Some(RebalanceMeta::default());
|
let rebalance_meta = Some(RebalanceMeta::default());
|
||||||
|
|
||||||
assert!(should_auto_start_rebalance_after_recovered_meta(&pool_meta, rebalance_meta.is_some()));
|
assert!(should_auto_start_rebalance_after_init(
|
||||||
|
pool_meta_has_active_decommission(&pool_meta),
|
||||||
|
rebalance_meta.is_some()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -301,7 +301,6 @@ const LIST_CURSOR_SOURCE_INDEX_KEY_ONLY: &str = "index_key_only";
|
|||||||
const LIST_CURSOR_SOURCE_INDEX_VERIFIED_PAGE: &str = "index_verified_page";
|
const LIST_CURSOR_SOURCE_INDEX_VERIFIED_PAGE: &str = "index_verified_page";
|
||||||
const LIST_CURSOR_SOURCE_INDEX_METADATA_FAST: &str = "index_metadata_fast";
|
const LIST_CURSOR_SOURCE_INDEX_METADATA_FAST: &str = "index_metadata_fast";
|
||||||
const LIST_CURSOR_GENERATION_LIVE: &str = "live";
|
const LIST_CURSOR_GENERATION_LIVE: &str = "live";
|
||||||
const ENV_API_LIST_QUORUM: &str = "RUSTFS_API_LIST_QUORUM";
|
|
||||||
const DEFAULT_API_LIST_QUORUM: &str = "strict";
|
const DEFAULT_API_LIST_QUORUM: &str = "strict";
|
||||||
const ENV_API_LIST_OBJECTS_QUORUM: &str = "RUSTFS_LIST_OBJECTS_QUORUM";
|
const ENV_API_LIST_OBJECTS_QUORUM: &str = "RUSTFS_LIST_OBJECTS_QUORUM";
|
||||||
const DEFAULT_API_LIST_OBJECTS_QUORUM: &str = "optimal";
|
const DEFAULT_API_LIST_OBJECTS_QUORUM: &str = "optimal";
|
||||||
@@ -406,7 +405,6 @@ enum ListIndexFallbackReason {
|
|||||||
Unhealthy,
|
Unhealthy,
|
||||||
Lagging,
|
Lagging,
|
||||||
Degraded,
|
Degraded,
|
||||||
Corrupt,
|
|
||||||
MissingGeneration,
|
MissingGeneration,
|
||||||
GenerationMismatch,
|
GenerationMismatch,
|
||||||
UnsupportedRequest,
|
UnsupportedRequest,
|
||||||
@@ -421,7 +419,6 @@ impl ListIndexFallbackReason {
|
|||||||
Self::Unhealthy => "unhealthy",
|
Self::Unhealthy => "unhealthy",
|
||||||
Self::Lagging => "lagging",
|
Self::Lagging => "lagging",
|
||||||
Self::Degraded => "degraded",
|
Self::Degraded => "degraded",
|
||||||
Self::Corrupt => "corrupt",
|
|
||||||
Self::MissingGeneration => "missing_generation",
|
Self::MissingGeneration => "missing_generation",
|
||||||
Self::GenerationMismatch => "generation_mismatch",
|
Self::GenerationMismatch => "generation_mismatch",
|
||||||
Self::UnsupportedRequest => "unsupported_request",
|
Self::UnsupportedRequest => "unsupported_request",
|
||||||
@@ -492,13 +489,6 @@ impl ListObjectsIndexProviderState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_kind(kind: ListObjectsIndexProviderKind) -> Self {
|
|
||||||
match kind {
|
|
||||||
ListObjectsIndexProviderKind::WalkerKeyOnly => Self::walker_key_only(),
|
|
||||||
ListObjectsIndexProviderKind::PersistentKeyOnly => Self::persistent_key_only(None, None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn health_snapshot(&self) -> ListIndexHealthSnapshot {
|
fn health_snapshot(&self) -> ListIndexHealthSnapshot {
|
||||||
self.lifecycle.health_snapshot()
|
self.lifecycle.health_snapshot()
|
||||||
}
|
}
|
||||||
@@ -667,6 +657,9 @@ async fn observe_list_objects_mutations_with_store(store: Option<&ECStore>, buck
|
|||||||
Some(next)
|
Some(next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test-only observer over the live mutation snapshot; production reads go
|
||||||
|
// through `current_list_objects_mutation_snapshot` directly.
|
||||||
|
#[cfg(test)]
|
||||||
async fn current_list_objects_mutation_sequence(bucket: &str) -> u64 {
|
async fn current_list_objects_mutation_sequence(bucket: &str) -> u64 {
|
||||||
current_list_objects_mutation_snapshot(None, bucket).await.high_water_mark
|
current_list_objects_mutation_snapshot(None, bucket).await.high_water_mark
|
||||||
}
|
}
|
||||||
@@ -1539,17 +1532,6 @@ fn generated_persistent_key_only_generation(configured: Option<&str>) -> String
|
|||||||
format!("{LIST_OBJECTS_INDEX_PROVIDER_PERSISTENT_KEY_ONLY_DEFAULT_GENERATION}-{millis}")
|
format!("{LIST_OBJECTS_INDEX_PROVIDER_PERSISTENT_KEY_ONLY_DEFAULT_GENERATION}-{millis}")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn write_persistent_key_only_index(
|
|
||||||
store: Option<&ECStore>,
|
|
||||||
path: &Path,
|
|
||||||
bucket: &str,
|
|
||||||
generation: &str,
|
|
||||||
checkpoint_high_water_mark: u64,
|
|
||||||
keys: &[String],
|
|
||||||
) -> Result<PersistentKeyOnlyIndex> {
|
|
||||||
write_persistent_key_only_index_with_metadata(store, path, bucket, generation, checkpoint_high_water_mark, keys, &[]).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn write_persistent_key_only_index_with_metadata(
|
async fn write_persistent_key_only_index_with_metadata(
|
||||||
store: Option<&ECStore>,
|
store: Option<&ECStore>,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
@@ -1656,38 +1638,8 @@ enum ListIndexSourceDecision {
|
|||||||
FallbackToWalker(ListIndexFallbackReason),
|
FallbackToWalker(ListIndexFallbackReason),
|
||||||
}
|
}
|
||||||
|
|
||||||
trait ListMetadataIndexGeneration {
|
|
||||||
fn generation_id(&self) -> &str;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ListMetadataIndexHealth {
|
trait ListMetadataIndexHealth {
|
||||||
fn fallback_reason(&self) -> Option<ListIndexFallbackReason>;
|
fn fallback_reason(&self) -> Option<ListIndexFallbackReason>;
|
||||||
|
|
||||||
fn is_healthy(&self) -> bool {
|
|
||||||
self.fallback_reason().is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ListMetadataIndexPage {
|
|
||||||
fn source_mode(&self) -> ListSourceMode;
|
|
||||||
fn generation(&self) -> &dyn ListMetadataIndexGeneration;
|
|
||||||
fn keys(&self) -> &[String];
|
|
||||||
|
|
||||||
fn metadata_authority(&self) -> ListMetadataAuthority {
|
|
||||||
self.source_mode().metadata_authority()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ListMetadataIndexPageIterator {
|
|
||||||
type Page: ListMetadataIndexPage;
|
|
||||||
|
|
||||||
fn next_page(&mut self) -> Option<Self::Page>;
|
|
||||||
}
|
|
||||||
|
|
||||||
trait ListMetadataIndexKeyLookup {
|
|
||||||
type Page: ListMetadataIndexPage;
|
|
||||||
|
|
||||||
fn lookup_page(&self, opts: &ListPathOptions) -> ListIndexSourceDecision;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_list_index_provider_source_mode(
|
fn select_list_index_provider_source_mode(
|
||||||
@@ -1748,7 +1700,6 @@ enum ListIndexLifecycleState {
|
|||||||
Healthy,
|
Healthy,
|
||||||
Lagging,
|
Lagging,
|
||||||
Degraded,
|
Degraded,
|
||||||
Corrupt,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListIndexLifecycleState {
|
impl ListIndexLifecycleState {
|
||||||
@@ -1759,7 +1710,6 @@ impl ListIndexLifecycleState {
|
|||||||
Self::Healthy => None,
|
Self::Healthy => None,
|
||||||
Self::Lagging => Some(ListIndexFallbackReason::Lagging),
|
Self::Lagging => Some(ListIndexFallbackReason::Lagging),
|
||||||
Self::Degraded => Some(ListIndexFallbackReason::Degraded),
|
Self::Degraded => Some(ListIndexFallbackReason::Degraded),
|
||||||
Self::Corrupt => Some(ListIndexFallbackReason::Corrupt),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1826,16 +1776,6 @@ impl ListIndexLifecycle {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recover_after_restart(mut self) -> Self {
|
|
||||||
self.staging_generation = None;
|
|
||||||
self.state = if self.active_generation.is_some() {
|
|
||||||
ListIndexLifecycleState::Healthy
|
|
||||||
} else {
|
|
||||||
ListIndexLifecycleState::Disabled
|
|
||||||
};
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn observe_mutation_high_water_mark(&mut self, mutation_high_water_mark: u64) {
|
fn observe_mutation_high_water_mark(&mut self, mutation_high_water_mark: u64) {
|
||||||
self.mutation_high_water_mark = self.mutation_high_water_mark.max(mutation_high_water_mark);
|
self.mutation_high_water_mark = self.mutation_high_water_mark.max(mutation_high_water_mark);
|
||||||
if matches!(self.state, ListIndexLifecycleState::Healthy | ListIndexLifecycleState::Lagging)
|
if matches!(self.state, ListIndexLifecycleState::Healthy | ListIndexLifecycleState::Lagging)
|
||||||
@@ -1849,10 +1789,6 @@ impl ListIndexLifecycle {
|
|||||||
self.state = ListIndexLifecycleState::Degraded;
|
self.state = ListIndexLifecycleState::Degraded;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mark_corrupt(&mut self) {
|
|
||||||
self.state = ListIndexLifecycleState::Corrupt;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mutation_lag(&self) -> u64 {
|
fn mutation_lag(&self) -> u64 {
|
||||||
self.mutation_high_water_mark.saturating_sub(self.checkpoint_high_water_mark)
|
self.mutation_high_water_mark.saturating_sub(self.checkpoint_high_water_mark)
|
||||||
}
|
}
|
||||||
@@ -2003,11 +1939,6 @@ fn normalize_list_quorum(value: &str) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_quorum_from_env() -> String {
|
|
||||||
let value = rustfs_utils::get_env_str(ENV_API_LIST_QUORUM, DEFAULT_API_LIST_QUORUM);
|
|
||||||
normalize_list_quorum(&value).to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn list_objects_quorum_from_env() -> String {
|
fn list_objects_quorum_from_env() -> String {
|
||||||
let value = rustfs_utils::get_env_str(ENV_API_LIST_OBJECTS_QUORUM, DEFAULT_API_LIST_OBJECTS_QUORUM);
|
let value = rustfs_utils::get_env_str(ENV_API_LIST_OBJECTS_QUORUM, DEFAULT_API_LIST_OBJECTS_QUORUM);
|
||||||
normalize_list_quorum(&value).to_owned()
|
normalize_list_quorum(&value).to_owned()
|
||||||
@@ -2086,38 +2017,10 @@ fn list_objects_index_provider_state_from_env() -> Option<ListObjectsIndexProvid
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_objects_key_only_provider_health(provider: Option<ListObjectsIndexProviderKind>) -> ListIndexHealthSnapshot {
|
|
||||||
provider
|
|
||||||
.map(ListObjectsIndexProviderState::from_kind)
|
|
||||||
.map(|state| state.health_snapshot())
|
|
||||||
.unwrap_or_else(|| ListIndexLifecycle::disabled(0).health_snapshot())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn record_list_objects_index_fallback(mode: ListSourceMode, reason: ListIndexFallbackReason) {
|
fn record_list_objects_index_fallback(mode: ListSourceMode, reason: ListIndexFallbackReason) {
|
||||||
rustfs_io_metrics::record_list_objects_index_fallback(mode.cursor_value(), reason.metric_label());
|
rustfs_io_metrics::record_list_objects_index_fallback(mode.cursor_value(), reason.metric_label());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_list_objects_index_opt_in_fallback(opts: &ListPathOptions, mode: ListSourceMode) {
|
|
||||||
if !rustfs_io_metrics::get_stage_metrics_enabled() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let health = list_objects_key_only_provider_health(None);
|
|
||||||
let reason = match select_list_index_provider_source_mode(opts, mode, &health) {
|
|
||||||
ListIndexSourceDecision::FallbackToWalker(reason) => reason,
|
|
||||||
ListIndexSourceDecision::UseIndex(_) => ListIndexFallbackReason::UnsupportedRequest,
|
|
||||||
};
|
|
||||||
|
|
||||||
record_list_objects_index_fallback(mode, reason);
|
|
||||||
debug!(
|
|
||||||
bucket = %opts.bucket,
|
|
||||||
prefix = %opts.prefix,
|
|
||||||
source = mode.cursor_value(),
|
|
||||||
reason = reason.metric_label(),
|
|
||||||
"list_objects opt-in index path fell back to walker"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn append_list_cache_id_to_marker(marker: String, cache_id: Option<&str>) -> String {
|
fn append_list_cache_id_to_marker(marker: String, cache_id: Option<&str>) -> String {
|
||||||
let Some(id) = cache_id else {
|
let Some(id) = cache_id else {
|
||||||
return marker;
|
return marker;
|
||||||
@@ -2284,6 +2187,8 @@ struct VerifiedIndexCandidateResult {
|
|||||||
stats: VerifiedIndexCandidateStats,
|
stats: VerifiedIndexCandidateStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test-only convenience over the live `_with_optional_stats` implementation.
|
||||||
|
#[cfg(test)]
|
||||||
async fn list_objects_from_verified_index_candidates<F, Fut>(
|
async fn list_objects_from_verified_index_candidates<F, Fut>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
marker: Option<&str>,
|
marker: Option<&str>,
|
||||||
@@ -2309,6 +2214,8 @@ where
|
|||||||
.info)
|
.info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test-only convenience over the live `_with_optional_stats` implementation.
|
||||||
|
#[cfg(test)]
|
||||||
async fn list_objects_from_verified_index_candidates_with_stats<F, Fut>(
|
async fn list_objects_from_verified_index_candidates_with_stats<F, Fut>(
|
||||||
prefix: &str,
|
prefix: &str,
|
||||||
marker: Option<&str>,
|
marker: Option<&str>,
|
||||||
@@ -6753,11 +6660,10 @@ mod test {
|
|||||||
ENV_API_LIST_OBJECTS_METADATA_FAST_STALENESS_MS, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_BUCKET,
|
ENV_API_LIST_OBJECTS_METADATA_FAST_STALENESS_MS, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_BUCKET,
|
||||||
ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_ENABLED, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_SEQUENCE,
|
ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_ENABLED, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_SEQUENCE,
|
||||||
ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_STATUS, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_PATH,
|
ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_CHAOS_STATUS, ENV_API_LIST_OBJECTS_NAMESPACE_JOURNAL_PATH,
|
||||||
ENV_API_LIST_OBJECTS_QUORUM, ENV_API_LIST_QUORUM, FallbackListingEntries, FallbackListingEntry, GatherResultsState,
|
ENV_API_LIST_OBJECTS_QUORUM, FallbackListingEntries, FallbackListingEntry, GatherResultsState,
|
||||||
LIST_CURSOR_GENERATION_LIVE, LIST_OBJECTS_INDEX_PROVIDER_PERSISTENT_KEY_ONLY,
|
LIST_CURSOR_GENERATION_LIVE, LIST_OBJECTS_INDEX_PROVIDER_PERSISTENT_KEY_ONLY,
|
||||||
LIST_OBJECTS_INDEX_PROVIDER_WALKER_KEY_ONLY, ListIndexFallbackReason, ListIndexLifecycle, ListIndexLifecycleState,
|
LIST_OBJECTS_INDEX_PROVIDER_WALKER_KEY_ONLY, ListIndexFallbackReason, ListIndexLifecycle, ListIndexLifecycleState,
|
||||||
ListIndexSourceDecision, ListMetadataAuthority, ListMetadataIndexGeneration, ListMetadataIndexHealth,
|
ListIndexSourceDecision, ListMetadataAuthority, ListMetadataIndexHealth, ListObjectsIndexProviderKind,
|
||||||
ListMetadataIndexKeyLookup, ListMetadataIndexPage, ListMetadataIndexPageIterator, ListObjectsIndexProviderKind,
|
|
||||||
ListObjectsIndexProviderState, ListPathOptions, ListPathRawOptions, ListSourceMode, ListingEntryResolution,
|
ListObjectsIndexProviderState, ListPathOptions, ListPathRawOptions, ListSourceMode, ListingEntryResolution,
|
||||||
ListingSupplement, ListingSupplementOptions, MAX_OBJECT_LIST, NamespaceMutationJournalBackend,
|
ListingSupplement, ListingSupplementOptions, MAX_OBJECT_LIST, NamespaceMutationJournalBackend,
|
||||||
NamespaceMutationJournalSnapshot, NamespaceMutationJournalStatus, PERSISTENT_KEY_ONLY_INDEX_BUCKET_HEADER,
|
NamespaceMutationJournalSnapshot, NamespaceMutationJournalStatus, PERSISTENT_KEY_ONLY_INDEX_BUCKET_HEADER,
|
||||||
@@ -6770,19 +6676,19 @@ mod test {
|
|||||||
list_merged_entry_channel, list_metadata_resolution_params, list_objects_from_metadata_snapshot_candidates,
|
list_merged_entry_channel, list_metadata_resolution_params, list_objects_from_metadata_snapshot_candidates,
|
||||||
list_objects_from_verified_index_candidates, list_objects_from_verified_index_candidates_with_optional_stats,
|
list_objects_from_verified_index_candidates, list_objects_from_verified_index_candidates_with_optional_stats,
|
||||||
list_objects_from_verified_index_candidates_with_stats, list_objects_index_mode_from_env,
|
list_objects_from_verified_index_candidates_with_stats, list_objects_index_mode_from_env,
|
||||||
list_objects_index_provider_from_env, list_objects_index_provider_state_from_env, list_objects_key_only_provider_health,
|
list_objects_index_provider_from_env, list_objects_index_provider_state_from_env,
|
||||||
list_objects_metadata_fast_guardrails_from_env, list_objects_paginate, list_objects_quorum_from_env,
|
list_objects_metadata_fast_guardrails_from_env, list_objects_paginate, list_objects_quorum_from_env,
|
||||||
list_quorum_from_env, load_namespace_mutation_journal_state, load_persistent_key_only_index, max_keys_plus_one,
|
load_namespace_mutation_journal_state, load_persistent_key_only_index, max_keys_plus_one, merge_entry_channels,
|
||||||
merge_entry_channels, namespace_mutation_journal_chaos_bucket_from_env, namespace_mutation_journal_chaos_config_from_env,
|
namespace_mutation_journal_chaos_bucket_from_env, namespace_mutation_journal_chaos_config_from_env,
|
||||||
namespace_mutation_journal_chaos_enabled_from_env, namespace_mutation_journal_chaos_sequence_from_env,
|
namespace_mutation_journal_chaos_enabled_from_env, namespace_mutation_journal_chaos_sequence_from_env,
|
||||||
namespace_mutation_journal_chaos_status_from_env, normalize_list_quorum, observe_list_objects_mutations_with_store,
|
namespace_mutation_journal_chaos_status_from_env, normalize_list_quorum, observe_list_objects_mutations_with_store,
|
||||||
parse_namespace_mutation_journal_state, parse_persistent_key_only_index, parse_persistent_list_metadata_object,
|
parse_namespace_mutation_journal_state, parse_persistent_key_only_index, parse_persistent_list_metadata_object,
|
||||||
parse_version_marker, persist_observed_list_objects_mutation, persistent_key_only_index_has_complete_metadata_snapshot,
|
parse_version_marker, persist_observed_list_objects_mutation, persistent_key_only_index_has_complete_metadata_snapshot,
|
||||||
persistent_key_only_index_health, persistent_key_only_index_matches_provider, record_list_objects_index_opt_in_fallback,
|
persistent_key_only_index_health, persistent_key_only_index_matches_provider,
|
||||||
reset_list_objects_mutation_sequences_for_test, resolve_agreed_listing_entry, resolve_listing_entries,
|
reset_list_objects_mutation_sequences_for_test, resolve_agreed_listing_entry, resolve_listing_entries,
|
||||||
scanner_namespace_mutation_generation, select_list_index_provider_source_mode, select_list_index_source_mode,
|
scanner_namespace_mutation_generation, select_list_index_provider_source_mode, select_list_index_source_mode,
|
||||||
send_or_cancel, version_marker_for_entries, walk_result_from_set_errors, write_namespace_mutation_journal_state,
|
send_or_cancel, version_marker_for_entries, walk_result_from_set_errors, write_namespace_mutation_journal_state,
|
||||||
write_persistent_key_only_index,
|
write_persistent_key_only_index_with_metadata,
|
||||||
};
|
};
|
||||||
use crate::cache_value::metacache_set::{FallbackClaimTracker, TestReaderBehavior, list_path_raw};
|
use crate::cache_value::metacache_set::{FallbackClaimTracker, TestReaderBehavior, list_path_raw};
|
||||||
use crate::disk::{DiskAPI, DiskOption, endpoint::Endpoint, error::DiskError, new_disk};
|
use crate::disk::{DiskAPI, DiskOption, endpoint::Endpoint, error::DiskError, new_disk};
|
||||||
@@ -6846,16 +6752,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
struct TestIndexGeneration {
|
|
||||||
id: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListMetadataIndexGeneration for TestIndexGeneration {
|
|
||||||
fn generation_id(&self) -> &str {
|
|
||||||
&self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestIndexHealth {
|
struct TestIndexHealth {
|
||||||
reason: Option<ListIndexFallbackReason>,
|
reason: Option<ListIndexFallbackReason>,
|
||||||
}
|
}
|
||||||
@@ -6866,50 +6762,6 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestIndexPage {
|
|
||||||
mode: ListSourceMode,
|
|
||||||
generation: TestIndexGeneration,
|
|
||||||
keys: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListMetadataIndexPage for TestIndexPage {
|
|
||||||
fn source_mode(&self) -> ListSourceMode {
|
|
||||||
self.mode
|
|
||||||
}
|
|
||||||
|
|
||||||
fn generation(&self) -> &dyn ListMetadataIndexGeneration {
|
|
||||||
&self.generation
|
|
||||||
}
|
|
||||||
|
|
||||||
fn keys(&self) -> &[String] {
|
|
||||||
&self.keys
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestIndexIterator {
|
|
||||||
pages: std::vec::IntoIter<TestIndexPage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListMetadataIndexPageIterator for TestIndexIterator {
|
|
||||||
type Page = TestIndexPage;
|
|
||||||
|
|
||||||
fn next_page(&mut self) -> Option<Self::Page> {
|
|
||||||
self.pages.next()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestIndexLookup {
|
|
||||||
decision: ListIndexSourceDecision,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListMetadataIndexKeyLookup for TestIndexLookup {
|
|
||||||
type Page = TestIndexPage;
|
|
||||||
|
|
||||||
fn lookup_page(&self, _opts: &ListPathOptions) -> ListIndexSourceDecision {
|
|
||||||
self.decision
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_meta_entry(name: &str) -> MetaCacheEntry {
|
fn test_meta_entry(name: &str) -> MetaCacheEntry {
|
||||||
MetaCacheEntry {
|
MetaCacheEntry {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
@@ -7894,30 +7746,6 @@ mod test {
|
|||||||
assert_eq!(normalize_list_quorum("unknown"), "strict");
|
assert_eq!(normalize_list_quorum("unknown"), "strict");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[serial_test::serial]
|
|
||||||
fn list_quorum_from_env_defaults_to_strict() {
|
|
||||||
temp_env::with_var_unset(ENV_API_LIST_QUORUM, || {
|
|
||||||
assert_eq!(list_quorum_from_env(), "strict");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[serial_test::serial]
|
|
||||||
fn list_quorum_from_env_honors_supported_value() {
|
|
||||||
temp_env::with_var(ENV_API_LIST_QUORUM, Some("auto"), || {
|
|
||||||
assert_eq!(list_quorum_from_env(), "auto");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[serial_test::serial]
|
|
||||||
fn list_quorum_from_env_rejects_unknown_value() {
|
|
||||||
temp_env::with_var(ENV_API_LIST_QUORUM, Some("unsafe"), || {
|
|
||||||
assert_eq!(list_quorum_from_env(), "strict");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[serial_test::serial]
|
#[serial_test::serial]
|
||||||
fn list_objects_quorum_from_env_defaults_to_optimal() {
|
fn list_objects_quorum_from_env_defaults_to_optimal() {
|
||||||
@@ -8154,9 +7982,7 @@ mod test {
|
|||||||
fn list_objects_index_provider_from_env_is_default_off() {
|
fn list_objects_index_provider_from_env_is_default_off() {
|
||||||
temp_env::with_var_unset(ENV_API_LIST_OBJECTS_INDEX_PROVIDER, || {
|
temp_env::with_var_unset(ENV_API_LIST_OBJECTS_INDEX_PROVIDER, || {
|
||||||
assert_eq!(list_objects_index_provider_from_env(), None);
|
assert_eq!(list_objects_index_provider_from_env(), None);
|
||||||
let health = list_objects_key_only_provider_health(list_objects_index_provider_from_env());
|
assert_eq!(list_objects_index_provider_state_from_env(), None);
|
||||||
assert_eq!(health.state, ListIndexLifecycleState::Disabled);
|
|
||||||
assert_eq!(health.fallback_reason, Some(ListIndexFallbackReason::Disabled));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8168,7 +7994,9 @@ mod test {
|
|||||||
Some(LIST_OBJECTS_INDEX_PROVIDER_WALKER_KEY_ONLY),
|
Some(LIST_OBJECTS_INDEX_PROVIDER_WALKER_KEY_ONLY),
|
||||||
|| {
|
|| {
|
||||||
assert_eq!(list_objects_index_provider_from_env(), Some(ListObjectsIndexProviderKind::WalkerKeyOnly));
|
assert_eq!(list_objects_index_provider_from_env(), Some(ListObjectsIndexProviderKind::WalkerKeyOnly));
|
||||||
let health = list_objects_key_only_provider_health(list_objects_index_provider_from_env());
|
let health = list_objects_index_provider_state_from_env()
|
||||||
|
.expect("walker provider should be configured")
|
||||||
|
.health_snapshot();
|
||||||
assert_eq!(health.state, ListIndexLifecycleState::Healthy);
|
assert_eq!(health.state, ListIndexLifecycleState::Healthy);
|
||||||
assert_eq!(health.active_generation.as_deref(), Some(LIST_CURSOR_GENERATION_LIVE));
|
assert_eq!(health.active_generation.as_deref(), Some(LIST_CURSOR_GENERATION_LIVE));
|
||||||
assert_eq!(health.fallback_reason, None);
|
assert_eq!(health.fallback_reason, None);
|
||||||
@@ -8459,7 +8287,7 @@ mod test {
|
|||||||
let journal_root = tempdir.path().join("namespace-mutation-journal");
|
let journal_root = tempdir.path().join("namespace-mutation-journal");
|
||||||
let keys = vec!["object-a".to_string(), "object-b".to_string()];
|
let keys = vec!["object-a".to_string(), "object-b".to_string()];
|
||||||
|
|
||||||
write_persistent_key_only_index(None, &index_path, "bucket", "generation-42", 5, &keys)
|
write_persistent_key_only_index_with_metadata(None, &index_path, "bucket", "generation-42", 5, &keys, &[])
|
||||||
.await
|
.await
|
||||||
.expect("index should be written");
|
.expect("index should be written");
|
||||||
write_namespace_mutation_journal_state(NamespaceMutationJournalBackend::LocalPath(journal_root), "bucket", 9, false)
|
write_namespace_mutation_journal_state(NamespaceMutationJournalBackend::LocalPath(journal_root), "bucket", 9, false)
|
||||||
@@ -8644,7 +8472,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_objects_index_provider_state_uses_lifecycle_active_generation() {
|
fn list_objects_index_provider_state_uses_lifecycle_active_generation() {
|
||||||
let provider = ListObjectsIndexProviderState::from_kind(ListObjectsIndexProviderKind::WalkerKeyOnly);
|
let provider = ListObjectsIndexProviderState::walker_key_only();
|
||||||
let health = provider.health_snapshot();
|
let health = provider.health_snapshot();
|
||||||
|
|
||||||
assert_eq!(provider.kind, ListObjectsIndexProviderKind::WalkerKeyOnly);
|
assert_eq!(provider.kind, ListObjectsIndexProviderKind::WalkerKeyOnly);
|
||||||
@@ -8657,21 +8485,6 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_objects_index_opt_in_fallback_accepts_incompatible_cursor_without_panicking() {
|
|
||||||
record_list_objects_index_opt_in_fallback(
|
|
||||||
&ListPathOptions {
|
|
||||||
bucket: "bucket".to_string(),
|
|
||||||
prefix: "photos/".to_string(),
|
|
||||||
marker: Some(
|
|
||||||
"photos/2026/[rustfs_cache:v2,id:list-cache-id,src:index_verified_page,gen:generation-1]".to_string(),
|
|
||||||
),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
ListSourceMode::IndexKeyOnly,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn list_objects_verified_index_candidates_use_live_metadata_only() {
|
async fn list_objects_verified_index_candidates_use_live_metadata_only() {
|
||||||
let candidates = vec![
|
let candidates = vec![
|
||||||
@@ -9392,38 +9205,6 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_index_traits_keep_page_iteration_and_metadata_authority_explicit() {
|
|
||||||
let page = TestIndexPage {
|
|
||||||
mode: ListSourceMode::IndexMetadataFast,
|
|
||||||
generation: TestIndexGeneration {
|
|
||||||
id: "snapshot-7".to_string(),
|
|
||||||
},
|
|
||||||
keys: vec!["photos/2026/image.jpg".to_string()],
|
|
||||||
};
|
|
||||||
let mut iterator = TestIndexIterator {
|
|
||||||
pages: vec![page].into_iter(),
|
|
||||||
};
|
|
||||||
let page = iterator.next_page().expect("test iterator should produce one page");
|
|
||||||
|
|
||||||
assert_eq!(page.keys(), &["photos/2026/image.jpg".to_string()]);
|
|
||||||
assert_eq!(page.generation().generation_id(), "snapshot-7");
|
|
||||||
assert_eq!(page.metadata_authority(), ListMetadataAuthority::IndexSnapshotEventuallyConsistent);
|
|
||||||
assert!(!page.source_mode().can_satisfy_strong_listing());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_index_key_lookup_trait_returns_explicit_fallback_decision() {
|
|
||||||
let lookup = TestIndexLookup {
|
|
||||||
decision: ListIndexSourceDecision::FallbackToWalker(ListIndexFallbackReason::UnsupportedRequest),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
lookup.lookup_page(&ListPathOptions::default()),
|
|
||||||
ListIndexSourceDecision::FallbackToWalker(ListIndexFallbackReason::UnsupportedRequest)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_index_lifecycle_rebuild_requires_publish_before_health() {
|
fn list_index_lifecycle_rebuild_requires_publish_before_health() {
|
||||||
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
||||||
@@ -9446,40 +9227,6 @@ mod test {
|
|||||||
assert_eq!(snapshot.fallback_reason, None);
|
assert_eq!(snapshot.fallback_reason, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_index_lifecycle_restart_never_trusts_unpublished_staging_generation() {
|
|
||||||
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
|
||||||
lifecycle.begin_rebuild("generation-1", 100);
|
|
||||||
lifecycle.checkpoint_rebuild(90);
|
|
||||||
|
|
||||||
let recovered = lifecycle.recover_after_restart();
|
|
||||||
let snapshot = recovered.health_snapshot();
|
|
||||||
|
|
||||||
assert_eq!(snapshot.state, ListIndexLifecycleState::Disabled);
|
|
||||||
assert_eq!(snapshot.active_generation, None);
|
|
||||||
assert_eq!(snapshot.staging_generation, None);
|
|
||||||
assert_eq!(snapshot.fallback_reason, Some(ListIndexFallbackReason::Disabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn list_index_lifecycle_restart_keeps_only_last_published_generation() {
|
|
||||||
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
|
||||||
lifecycle.begin_rebuild("generation-1", 100);
|
|
||||||
lifecycle.checkpoint_rebuild(100);
|
|
||||||
assert!(lifecycle.publish_rebuild());
|
|
||||||
|
|
||||||
lifecycle.begin_rebuild("generation-2", 125);
|
|
||||||
lifecycle.checkpoint_rebuild(120);
|
|
||||||
|
|
||||||
let recovered = lifecycle.recover_after_restart();
|
|
||||||
let snapshot = recovered.health_snapshot();
|
|
||||||
|
|
||||||
assert_eq!(snapshot.state, ListIndexLifecycleState::Healthy);
|
|
||||||
assert_eq!(snapshot.active_generation.as_deref(), Some("generation-1"));
|
|
||||||
assert_eq!(snapshot.staging_generation, None);
|
|
||||||
assert_eq!(snapshot.fallback_reason, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_index_lifecycle_reports_lagging_and_fallback_reason() {
|
fn list_index_lifecycle_reports_lagging_and_fallback_reason() {
|
||||||
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
||||||
@@ -9493,11 +9240,10 @@ mod test {
|
|||||||
assert_eq!(snapshot.state, ListIndexLifecycleState::Lagging);
|
assert_eq!(snapshot.state, ListIndexLifecycleState::Lagging);
|
||||||
assert_eq!(snapshot.mutation_lag, 15);
|
assert_eq!(snapshot.mutation_lag, 15);
|
||||||
assert_eq!(snapshot.fallback_reason, Some(ListIndexFallbackReason::Lagging));
|
assert_eq!(snapshot.fallback_reason, Some(ListIndexFallbackReason::Lagging));
|
||||||
assert!(!snapshot.is_healthy());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn list_index_lifecycle_reports_degraded_and_corrupt_as_unhealthy() {
|
fn list_index_lifecycle_reports_degraded_as_fallback() {
|
||||||
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
let mut lifecycle = ListIndexLifecycle::disabled(10);
|
||||||
lifecycle.begin_rebuild("generation-1", 100);
|
lifecycle.begin_rebuild("generation-1", 100);
|
||||||
lifecycle.checkpoint_rebuild(100);
|
lifecycle.checkpoint_rebuild(100);
|
||||||
@@ -9507,13 +9253,6 @@ mod test {
|
|||||||
let degraded = lifecycle.health_snapshot();
|
let degraded = lifecycle.health_snapshot();
|
||||||
assert_eq!(degraded.state, ListIndexLifecycleState::Degraded);
|
assert_eq!(degraded.state, ListIndexLifecycleState::Degraded);
|
||||||
assert_eq!(degraded.fallback_reason, Some(ListIndexFallbackReason::Degraded));
|
assert_eq!(degraded.fallback_reason, Some(ListIndexFallbackReason::Degraded));
|
||||||
assert!(!degraded.is_healthy());
|
|
||||||
|
|
||||||
lifecycle.mark_corrupt();
|
|
||||||
let corrupt = lifecycle.health_snapshot();
|
|
||||||
assert_eq!(corrupt.state, ListIndexLifecycleState::Corrupt);
|
|
||||||
assert_eq!(corrupt.fallback_reason, Some(ListIndexFallbackReason::Corrupt));
|
|
||||||
assert!(!corrupt.is_healthy());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -12,8 +12,6 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// #730: store startup/listing helpers are staged while global state is moved to owners.
|
|
||||||
#![allow(dead_code)]
|
|
||||||
#![allow(clippy::map_entry)]
|
#![allow(clippy::map_entry)]
|
||||||
|
|
||||||
use crate::bucket::lifecycle::bucket_lifecycle_audit::LcEventSrc;
|
use crate::bucket::lifecycle::bucket_lifecycle_audit::LcEventSrc;
|
||||||
|
|||||||
@@ -61,10 +61,6 @@ pub async fn find_local_disk_by_ref(disk_ref: &str) -> Option<DiskStore> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_disk_via_endpoint(endpoint: &Endpoint) -> Option<DiskStore> {
|
|
||||||
runtime_sources::local_disk_for_endpoint(endpoint).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn all_local_disk_path() -> Vec<String> {
|
pub async fn all_local_disk_path() -> Vec<String> {
|
||||||
runtime_sources::local_disk_paths().await
|
runtime_sources::local_disk_paths().await
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user