mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-27 01:50:38 +00:00
wip: track read path stats in context
This commit is contained in:
@@ -86,6 +86,11 @@
|
|||||||
//! [`RequestContext`] argument. Functions in the middle of the call chain
|
//! [`RequestContext`] argument. Functions in the middle of the call chain
|
||||||
//! only need to pass it on.
|
//! only need to pass it on.
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
sync::{atomic::AtomicU32, Arc},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::task_mgr::TaskKind;
|
use crate::task_mgr::TaskKind;
|
||||||
|
|
||||||
pub(crate) mod optional_counter;
|
pub(crate) mod optional_counter;
|
||||||
@@ -98,6 +103,73 @@ pub struct RequestContext {
|
|||||||
access_stats_behavior: AccessStatsBehavior,
|
access_stats_behavior: AccessStatsBehavior,
|
||||||
page_content_kind: PageContentKind,
|
page_content_kind: PageContentKind,
|
||||||
pub micros_spent_throttled: optional_counter::MicroSecondsCounterU32,
|
pub micros_spent_throttled: optional_counter::MicroSecondsCounterU32,
|
||||||
|
pub read_path_stats: ReadPathStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct ReadPathStats {
|
||||||
|
pub inner: Arc<ReadPathStatsInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct ReadPathStatsInner {
|
||||||
|
pub get_reconstruct_data_time: AtomicU32,
|
||||||
|
pub plan_read_time: AtomicU32,
|
||||||
|
pub read_time: AtomicU32,
|
||||||
|
pub sort_reconstruct_data_time: AtomicU32,
|
||||||
|
pub layers_visited: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ReadPathStatsInner {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"get_reconstruct_data_time={} plan_read_time={} read_time={} sort_time={} layers_visited={}",
|
||||||
|
self.get_reconstruct_data_time.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
self.plan_read_time
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
self.read_time.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
self.sort_reconstruct_data_time
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed),
|
||||||
|
self.layers_visited
|
||||||
|
.load(std::sync::atomic::Ordering::Relaxed)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadPathStatsInner {
|
||||||
|
pub fn add_get_reconstruct_data_time(&self, dur: Duration) {
|
||||||
|
self.get_reconstruct_data_time.fetch_add(
|
||||||
|
dur.as_micros().try_into().unwrap(),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_plan_read_time(&self, dur: Duration) {
|
||||||
|
self.plan_read_time.fetch_add(
|
||||||
|
dur.as_micros().try_into().unwrap(),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_read_time(&self, dur: Duration) {
|
||||||
|
self.plan_read_time.fetch_add(
|
||||||
|
dur.as_micros().try_into().unwrap(),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_sort_reconstruct_data_time(&self, dur: Duration) {
|
||||||
|
self.sort_reconstruct_data_time.fetch_add(
|
||||||
|
dur.as_micros().try_into().unwrap(),
|
||||||
|
std::sync::atomic::Ordering::Relaxed,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inc_layer_visited(&self) {
|
||||||
|
self.layers_visited
|
||||||
|
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The kind of access to the page cache.
|
/// The kind of access to the page cache.
|
||||||
@@ -154,6 +226,7 @@ impl RequestContextBuilder {
|
|||||||
access_stats_behavior: AccessStatsBehavior::Update,
|
access_stats_behavior: AccessStatsBehavior::Update,
|
||||||
page_content_kind: PageContentKind::Unknown,
|
page_content_kind: PageContentKind::Unknown,
|
||||||
micros_spent_throttled: Default::default(),
|
micros_spent_throttled: Default::default(),
|
||||||
|
read_path_stats: Default::default(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,6 +241,7 @@ impl RequestContextBuilder {
|
|||||||
access_stats_behavior: original.access_stats_behavior,
|
access_stats_behavior: original.access_stats_behavior,
|
||||||
page_content_kind: original.page_content_kind,
|
page_content_kind: original.page_content_kind,
|
||||||
micros_spent_throttled: Default::default(),
|
micros_spent_throttled: Default::default(),
|
||||||
|
read_path_stats: original.read_path_stats.clone(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,4 +365,8 @@ impl RequestContext {
|
|||||||
pub(crate) fn page_content_kind(&self) -> PageContentKind {
|
pub(crate) fn page_content_kind(&self) -> PageContentKind {
|
||||||
self.page_content_kind
|
self.page_content_kind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn report_stats(&self) {
|
||||||
|
tracing::info!("Read path stats: {}", *self.read_path_stats.inner)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ impl MicroSecondsCounterU32 {
|
|||||||
Err(_) => Err("add(): duration conversion error"),
|
Err(_) => Err("add(): duration conversion error"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_and_checked_sub_from(&self, from: Duration) -> Result<Duration, &'static str> {
|
pub fn close_and_checked_sub_from(&self, from: Duration) -> Result<Duration, &'static str> {
|
||||||
let val = self.inner.close()?;
|
let val = self.inner.close()?;
|
||||||
let val = Duration::from_micros(val as u64);
|
let val = Duration::from_micros(val as u64);
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ use std::io::SeekFrom;
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::os::unix::fs::FileExt;
|
use std::os::unix::fs::FileExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
|
|
||||||
@@ -755,6 +756,9 @@ impl DeltaLayerInner {
|
|||||||
reconstruct_state: &mut ValueReconstructState,
|
reconstruct_state: &mut ValueReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> anyhow::Result<ValueReconstructResult> {
|
) -> anyhow::Result<ValueReconstructResult> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let plan_timer = Instant::now();
|
||||||
|
|
||||||
let mut need_image = true;
|
let mut need_image = true;
|
||||||
// Scan the page versions backwards, starting from `lsn`.
|
// Scan the page versions backwards, starting from `lsn`.
|
||||||
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
||||||
@@ -790,6 +794,12 @@ impl DeltaLayerInner {
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_plan_read_time(plan_timer.elapsed());
|
||||||
|
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
let ctx = &RequestContextBuilder::extend(ctx)
|
let ctx = &RequestContextBuilder::extend(ctx)
|
||||||
.page_content_kind(PageContentKind::DeltaLayerValue)
|
.page_content_kind(PageContentKind::DeltaLayerValue)
|
||||||
.build();
|
.build();
|
||||||
@@ -828,6 +838,10 @@ impl DeltaLayerInner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
// If an older page image is needed to reconstruct the page, let the
|
// If an older page image is needed to reconstruct the page, let the
|
||||||
// caller know.
|
// caller know.
|
||||||
if need_image {
|
if need_image {
|
||||||
@@ -851,6 +865,9 @@ impl DeltaLayerInner {
|
|||||||
reconstruct_state: &mut ValuesReconstructState,
|
reconstruct_state: &mut ValuesReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> Result<(), GetVectoredError> {
|
) -> Result<(), GetVectoredError> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let plan_timer = Instant::now();
|
||||||
|
|
||||||
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
||||||
let index_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
|
let index_reader = DiskBtreeReader::<_, DELTA_KEY_SIZE>::new(
|
||||||
self.index_start_blk,
|
self.index_start_blk,
|
||||||
@@ -879,11 +896,21 @@ impl DeltaLayerInner {
|
|||||||
.await
|
.await
|
||||||
.map_err(GetVectoredError::Other)?;
|
.map_err(GetVectoredError::Other)?;
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_plan_read_time(plan_timer.elapsed());
|
||||||
|
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
self.do_reads_and_update_state(reads, reconstruct_state)
|
self.do_reads_and_update_state(reads, reconstruct_state)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
reconstruct_state.on_lsn_advanced(&keyspace, self.lsn_range.start);
|
reconstruct_state.on_lsn_advanced(&keyspace, self.lsn_range.start);
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ use std::io::SeekFrom;
|
|||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::os::unix::prelude::FileExt;
|
use std::os::unix::prelude::FileExt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Instant;
|
||||||
use tokio::sync::OnceCell;
|
use tokio::sync::OnceCell;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use tracing::*;
|
use tracing::*;
|
||||||
@@ -422,6 +423,9 @@ impl ImageLayerInner {
|
|||||||
reconstruct_state: &mut ValueReconstructState,
|
reconstruct_state: &mut ValueReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> anyhow::Result<ValueReconstructResult> {
|
) -> anyhow::Result<ValueReconstructResult> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let plan_timer = Instant::now();
|
||||||
|
|
||||||
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
let block_reader = FileBlockReader::new(&self.file, self.file_id);
|
||||||
let tree_reader =
|
let tree_reader =
|
||||||
DiskBtreeReader::new(self.index_start_blk, self.index_root_blk, &block_reader);
|
DiskBtreeReader::new(self.index_start_blk, self.index_root_blk, &block_reader);
|
||||||
@@ -437,6 +441,12 @@ impl ImageLayerInner {
|
|||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_plan_read_time(plan_timer.elapsed());
|
||||||
|
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
let blob = block_reader
|
let blob = block_reader
|
||||||
.block_cursor()
|
.block_cursor()
|
||||||
.read_blob(
|
.read_blob(
|
||||||
@@ -450,6 +460,11 @@ impl ImageLayerInner {
|
|||||||
let value = Bytes::from(blob);
|
let value = Bytes::from(blob);
|
||||||
|
|
||||||
reconstruct_state.img = Some((self.lsn, value));
|
reconstruct_state.img = Some((self.lsn, value));
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
Ok(ValueReconstructResult::Complete)
|
Ok(ValueReconstructResult::Complete)
|
||||||
} else {
|
} else {
|
||||||
Ok(ValueReconstructResult::Missing)
|
Ok(ValueReconstructResult::Missing)
|
||||||
@@ -464,14 +479,27 @@ impl ImageLayerInner {
|
|||||||
reconstruct_state: &mut ValuesReconstructState,
|
reconstruct_state: &mut ValuesReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> Result<(), GetVectoredError> {
|
) -> Result<(), GetVectoredError> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let plan_timer = Instant::now();
|
||||||
|
|
||||||
let reads = self
|
let reads = self
|
||||||
.plan_reads(keyspace, ctx)
|
.plan_reads(keyspace, ctx)
|
||||||
.await
|
.await
|
||||||
.map_err(GetVectoredError::Other)?;
|
.map_err(GetVectoredError::Other)?;
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_plan_read_time(plan_timer.elapsed());
|
||||||
|
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
self.do_reads_and_update_state(reads, reconstruct_state)
|
self.do_reads_and_update_state(reads, reconstruct_state)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -298,6 +298,9 @@ impl InMemoryLayer {
|
|||||||
reconstruct_state: &mut ValueReconstructState,
|
reconstruct_state: &mut ValueReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> anyhow::Result<ValueReconstructResult> {
|
) -> anyhow::Result<ValueReconstructResult> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
ensure!(lsn_range.start >= self.start_lsn);
|
ensure!(lsn_range.start >= self.start_lsn);
|
||||||
let mut need_image = true;
|
let mut need_image = true;
|
||||||
|
|
||||||
@@ -333,6 +336,10 @@ impl InMemoryLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
// release lock on 'inner'
|
// release lock on 'inner'
|
||||||
|
|
||||||
// If an older page image is needed to reconstruct the page, let the
|
// If an older page image is needed to reconstruct the page, let the
|
||||||
@@ -355,6 +362,9 @@ impl InMemoryLayer {
|
|||||||
reconstruct_state: &mut ValuesReconstructState,
|
reconstruct_state: &mut ValuesReconstructState,
|
||||||
ctx: &RequestContext,
|
ctx: &RequestContext,
|
||||||
) -> Result<(), GetVectoredError> {
|
) -> Result<(), GetVectoredError> {
|
||||||
|
ctx.read_path_stats.inner.inc_layer_visited();
|
||||||
|
let plan_timer = Instant::now();
|
||||||
|
|
||||||
let ctx = RequestContextBuilder::extend(ctx)
|
let ctx = RequestContextBuilder::extend(ctx)
|
||||||
.page_content_kind(PageContentKind::InMemoryLayer)
|
.page_content_kind(PageContentKind::InMemoryLayer)
|
||||||
.build();
|
.build();
|
||||||
@@ -394,6 +404,12 @@ impl InMemoryLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_plan_read_time(plan_timer.elapsed());
|
||||||
|
|
||||||
|
let read_timer = Instant::now();
|
||||||
|
|
||||||
let keyspace_size = keyspace.total_size();
|
let keyspace_size = keyspace.total_size();
|
||||||
|
|
||||||
let mut completed_keys = HashSet::new();
|
let mut completed_keys = HashSet::new();
|
||||||
@@ -428,6 +444,10 @@ impl InMemoryLayer {
|
|||||||
|
|
||||||
reconstruct_state.on_lsn_advanced(&keyspace, self.start_lsn);
|
reconstruct_state.on_lsn_advanced(&keyspace, self.start_lsn);
|
||||||
|
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_read_time(read_timer.elapsed());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -739,7 +739,7 @@ impl Timeline {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.conf.get_impl {
|
let res = match self.conf.get_impl {
|
||||||
GetImpl::Legacy => {
|
GetImpl::Legacy => {
|
||||||
let reconstruct_state = ValueReconstructState {
|
let reconstruct_state = ValueReconstructState {
|
||||||
records: Vec::new(),
|
records: Vec::new(),
|
||||||
@@ -796,7 +796,13 @@ impl Timeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if key.to_i128() % 100 < 10 {
|
||||||
|
ctx.report_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not subject to [`Self::timeline_get_throttle`].
|
/// Not subject to [`Self::timeline_get_throttle`].
|
||||||
@@ -818,9 +824,13 @@ impl Timeline {
|
|||||||
let timer = crate::metrics::GET_RECONSTRUCT_DATA_TIME
|
let timer = crate::metrics::GET_RECONSTRUCT_DATA_TIME
|
||||||
.for_get_kind(crate::metrics::GetKind::Singular)
|
.for_get_kind(crate::metrics::GetKind::Singular)
|
||||||
.start_timer();
|
.start_timer();
|
||||||
|
let get_reconstruct_data_timer = Instant::now();
|
||||||
let path = self
|
let path = self
|
||||||
.get_reconstruct_data(key, lsn, &mut reconstruct_state, ctx)
|
.get_reconstruct_data(key, lsn, &mut reconstruct_state, ctx)
|
||||||
.await?;
|
.await?;
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_get_reconstruct_data_time(get_reconstruct_data_timer.elapsed());
|
||||||
timer.stop_and_record();
|
timer.stop_and_record();
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
@@ -1015,8 +1025,12 @@ impl Timeline {
|
|||||||
let get_data_timer = crate::metrics::GET_RECONSTRUCT_DATA_TIME
|
let get_data_timer = crate::metrics::GET_RECONSTRUCT_DATA_TIME
|
||||||
.for_get_kind(get_kind)
|
.for_get_kind(get_kind)
|
||||||
.start_timer();
|
.start_timer();
|
||||||
|
let timer = Instant::now();
|
||||||
self.get_vectored_reconstruct_data(keyspace, lsn, &mut reconstruct_state, ctx)
|
self.get_vectored_reconstruct_data(keyspace, lsn, &mut reconstruct_state, ctx)
|
||||||
.await?;
|
.await?;
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_get_reconstruct_data_time(timer.elapsed());
|
||||||
get_data_timer.stop_and_record();
|
get_data_timer.stop_and_record();
|
||||||
|
|
||||||
let reconstruct_timer = crate::metrics::RECONSTRUCT_TIME
|
let reconstruct_timer = crate::metrics::RECONSTRUCT_TIME
|
||||||
@@ -1029,7 +1043,11 @@ impl Timeline {
|
|||||||
results.insert(key, Err(err));
|
results.insert(key, Err(err));
|
||||||
}
|
}
|
||||||
Ok(state) => {
|
Ok(state) => {
|
||||||
|
let timer = Instant::now();
|
||||||
let state = ValueReconstructState::from(state);
|
let state = ValueReconstructState::from(state);
|
||||||
|
ctx.read_path_stats
|
||||||
|
.inner
|
||||||
|
.add_sort_reconstruct_data_time(timer.elapsed());
|
||||||
|
|
||||||
let reconstruct_res = self.reconstruct_value(key, lsn, state).await;
|
let reconstruct_res = self.reconstruct_value(key, lsn, state).await;
|
||||||
results.insert(key, reconstruct_res);
|
results.insert(key, reconstruct_res);
|
||||||
@@ -1072,10 +1090,10 @@ impl Timeline {
|
|||||||
panic!(concat!("Sequential get failed with {}, but vectored get did not",
|
panic!(concat!("Sequential get failed with {}, but vectored get did not",
|
||||||
" - keyspace={:?} lsn={}"),
|
" - keyspace={:?} lsn={}"),
|
||||||
seq_err, keyspace, lsn) },
|
seq_err, keyspace, lsn) },
|
||||||
(Ok(_), Err(vec_err)) => {
|
(Ok(seq_ok), Err(vec_err)) => {
|
||||||
panic!(concat!("Vectored get failed with {}, but sequential get did not",
|
panic!(concat!("Vectored get failed with {}, but sequential get did not",
|
||||||
" - keyspace={:?} lsn={}"),
|
" - keyspace={:?} lsn={} seq_ok={:?}"),
|
||||||
vec_err, keyspace, lsn) },
|
vec_err, keyspace, lsn, seq_ok) },
|
||||||
(Err(seq_err), Err(vec_err)) => {
|
(Err(seq_err), Err(vec_err)) => {
|
||||||
assert!(errors_match(seq_err, vec_err),
|
assert!(errors_match(seq_err, vec_err),
|
||||||
"Mismatched errors: {seq_err} != {vec_err} - keyspace={keyspace:?} lsn={lsn}")},
|
"Mismatched errors: {seq_err} != {vec_err} - keyspace={keyspace:?} lsn={lsn}")},
|
||||||
|
|||||||
Reference in New Issue
Block a user