Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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