Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion crates/ecstore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ num_cpus = { workspace = true }
rand.workspace = true
pin-project-lite.workspace = true
md-5.workspace = true
memmap2 = { workspace = true }
libc.workspace = true
rustix = { workspace = true }
rustfs-madmin.workspace = true
Expand Down
37 changes: 34 additions & 3 deletions crates/ecstore/src/bitrot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ use std::time::Instant;
use tokio::io::AsyncRead;
use tracing::debug;

/// Adjusts a raw (offset, length) pair to account for per-shard checksum overhead.
/// Returns (adjusted_offset, adjusted_length).
pub(crate) fn adjust_shard_read_params(
offset: usize,
length: usize,
shard_size: usize,
checksum_algo: &HashAlgorithm,
) -> (usize, usize) {
let adj_len = length.div_ceil(shard_size) * checksum_algo.size() + length;
let adj_off = offset.div_ceil(shard_size) * checksum_algo.size() + offset;
(adj_off, adj_len)
}
Comment thread
Copilot marked this conversation as resolved.

/// Create a BitrotReader from either inline data or disk file stream
///
/// # Parameters
Expand All @@ -33,7 +46,7 @@ use tracing::debug;
/// * `shard_size` - Shard size for erasure coding
/// * `checksum_algo` - Hash algorithm for bitrot verification
/// * `skip_verify` - If true, skip checksum verification
/// * `use_zero_copy` - If true, use zero-copy read (mmap on Unix)
/// * `use_zero_copy` - If true, use zero-copy read (pread on Unix)
#[allow(clippy::too_many_arguments)]
pub async fn create_bitrot_reader(
inline_data: Option<&[u8]>,
Expand All @@ -48,8 +61,7 @@ pub async fn create_bitrot_reader(
use_zero_copy: bool,
) -> disk::error::Result<Option<BitrotReader<Box<dyn AsyncRead + Send + Sync + Unpin>>>> {
// Calculate the total length to read, including the checksum overhead
let length = length.div_ceil(shard_size) * checksum_algo.size() + length;
let offset = offset.div_ceil(shard_size) * checksum_algo.size() + offset;
let (offset, length) = adjust_shard_read_params(offset, length, shard_size, &checksum_algo);
if let Some(data) = inline_data {
// Use inline data
let mut rd = Cursor::new(Bytes::copy_from_slice(data));
Expand Down Expand Up @@ -336,4 +348,23 @@ mod tests {
println!("error: {error:?}");
assert_eq!(error, DiskError::DiskNotFound);
}

#[test]
fn test_adjust_shard_read_params_no_checksum() {
let algo = HashAlgorithm::None;
let (adj_off, adj_len) = adjust_shard_read_params(10, 100, 64, &algo);
assert_eq!(adj_off, 10);
assert_eq!(adj_len, 100);
}

#[test]
fn test_adjust_shard_read_params_known_values() {
// shard_size=128, SHA256.size()=32, offset=0, length=128
// adj_len = 128.div_ceil(128) * 32 + 128 = 1 * 32 + 128 = 160
// adj_off = 0.div_ceil(128) * 32 + 0 = 0
let algo = HashAlgorithm::SHA256;
let (adj_off, adj_len) = adjust_shard_read_params(0, 128, 128, &algo);
assert_eq!(adj_off, 0);
assert_eq!(adj_len, 160);
}
}
10 changes: 8 additions & 2 deletions crates/ecstore/src/disk/disk_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use std::{
};
use tokio::{sync::RwLock, time};
use tokio_util::sync::CancellationToken;
use tracing::{info, warn};
use tracing::{Instrument, debug_span, info, warn};
use uuid::Uuid;

/// Disk health status constants
Expand Down Expand Up @@ -495,6 +495,10 @@ impl LocalDiskWrapper {
self.disk.clone()
}

pub fn get_object_path_if_local(&self, volume: &str, path: &str) -> crate::disk::error::Result<std::path::PathBuf> {
self.disk.get_object_path(volume, path)
}

pub fn runtime_state(&self) -> RuntimeDriveHealthState {
self.health.runtime_state()
}
Expand Down Expand Up @@ -834,7 +838,9 @@ impl LocalDiskWrapper {
}

// Check if disk is stale
self.check_disk_stale().await?;
self.check_disk_stale()
.instrument(debug_span!(target: "rustfs_get_trace", "get.xl_stale_check"))
.await?;

// Record operation start
let now = std::time::SystemTime::now()
Expand Down
Loading
Loading