// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Engine-only object body cache for RustFS.
//!
//! App-layer semantics and storage-specific read paths stay in the `rustfs`
//! crate; this crate owns the key, the eviction backend and the metrics.
//!
//! # Correctness boundary
//!
//! An entry is keyed by object identity — bucket, object, version, etag, size
//! and body variant — and every lookup runs after the caller has resolved fresh
//! metadata from a read quorum. Serving a hit is therefore sound because the
//! key matched metadata that was just read, not because the entry was recently
//! invalidated. Invalidation is process-local and is **hygiene**: it frees
//! capacity promptly, but the key is what keeps a stale body from being served.
//!
//! # Timing side channel
//!
//! A cache hit skips the erasure read, bitrot verification and decode, so it is
//! reliably faster than a miss. Any principal authorized to read an object can
//! therefore infer, by timing a single GET, whether *someone* read that object
//! within the entry's lifetime (`ttl` / `time_to_idle`).
//!
//! This never crosses an authorization boundary: the probe requires read access
//! to the exact bucket and object, which is checked before the cache is
//! consulted. It does leak co-tenants' recent access patterns on objects the
//! observer may already read. Deployments where access-pattern confidentiality
//! matters — a bucket shared read-only between competing tenants — should leave
//! the cache disabled for those buckets. Adding timing noise is not a viable
//! mitigation: it would cost exactly the latency the cache exists to save.

#[cfg(feature = "cache")]
pub mod backend;
#[cfg(feature = "cache")]
pub mod cache;
#[cfg(feature = "cache")]
pub mod config;
#[cfg(feature = "cache")]
pub mod entry;
#[cfg(feature = "cache")]
pub mod error;
#[cfg(feature = "cache")]
pub mod index;
#[cfg(feature = "cache")]
pub mod key;
#[cfg(feature = "cache")]
pub mod memory;
#[cfg(feature = "cache")]
pub mod metrics;
#[cfg(feature = "cache")]
pub mod moka_backend;
#[cfg(feature = "cache")]
pub mod noop;
#[cfg(feature = "runtime-memory")]
mod runtime_memory;
#[cfg(feature = "cache")]
pub mod singleflight;
#[cfg(feature = "cache")]
pub mod starshard_index;
#[cfg(feature = "cache")]
pub mod stats;

#[cfg(feature = "cache")]
pub use cache::{
    ObjectDataCache, ObjectDataCacheBodyReservation, ObjectDataCacheFillResult, ObjectDataCacheGetPlan,
    ObjectDataCacheGetRequest, ObjectDataCacheInvalidationReason, ObjectDataCacheInvalidationResult, ObjectDataCacheLookup,
    ObjectDataCacheReservedBody,
};
#[cfg(feature = "cache")]
pub use config::{ObjectDataCacheConfig, ObjectDataCacheMode};
#[cfg(feature = "cache")]
pub use error::ObjectDataCacheConfigError;
#[cfg(feature = "cache")]
pub use key::{NULL_VERSION_ID, ObjectDataCacheBodyVariant, ObjectDataCacheIdentity, ObjectDataCacheKey};
#[cfg(feature = "runtime-memory")]
pub use runtime_memory::{
    EffectiveMemory, MemoryBasis, effective_memory_from_system, resolve_effective_memory, select_effective_memory,
};
#[cfg(feature = "cache")]
pub use stats::{ObjectDataCacheStats, ObjectDataCacheStatsSnapshot};
