fix(select): pin object snapshot for query lifetime (#5835)

This commit is contained in:
GatewayJ
2026-08-09 14:08:53 +08:00
committed by GitHub
parent b9d1ca3e4d
commit 70deb3284b
28 changed files with 3806 additions and 572 deletions
+2 -1
View File
@@ -27,6 +27,7 @@ documentation = "https://docs.rs/rustfs-test-utils/latest/rustfs_test_utils/"
[features]
default = []
put-object-commit-barrier = ["rustfs-ecstore/test-util"]
hotpath = [
"hotpath/hotpath",
"hotpath/tokio",
@@ -51,7 +52,7 @@ hotpath-cpu = [
[dependencies]
hotpath.workspace = true
rustfs-ecstore = { workspace = true }
rustfs-ecstore.workspace = true
rustfs-storage-api = { workspace = true }
tokio = { workspace = true, features = ["fs", "rt-multi-thread"] }
tokio-util = { workspace = true, features = ["io", "compat"] }
+4 -1
View File
@@ -26,8 +26,11 @@ pub(crate) mod fixture {
pub(crate) use rustfs_ecstore::api::bucket::metadata_sys::init_bucket_metadata_sys;
pub(crate) use rustfs_ecstore::api::disk::endpoint::Endpoint;
pub(crate) use rustfs_ecstore::api::layout::{EndpointServerPools, Endpoints, PoolEndpoints};
pub(crate) use rustfs_ecstore::api::object::{PutObjReader, SelectObjectSnapshot};
#[cfg(feature = "put-object-commit-barrier")]
pub(crate) use rustfs_ecstore::api::set_disk as ecstore_set_disk;
pub(crate) use rustfs_ecstore::api::storage::{ECStore, init_local_disks};
pub(crate) use rustfs_storage_api::{BucketOperations, BucketOptions, MakeBucketOptions};
pub(crate) use rustfs_storage_api::{BucketOperations, BucketOptions, MakeBucketOptions, ObjectIO};
#[cfg(test)]
pub(crate) use rustfs_ecstore::api::config::com::{delete_config, read_config, save_config};
+49 -2
View File
@@ -30,14 +30,38 @@ mod ecstore_test_compat;
use std::path::PathBuf;
use std::sync::{Arc, Once};
#[cfg(feature = "put-object-commit-barrier")]
use ecstore_test_compat::fixture::ecstore_set_disk;
use ecstore_test_compat::fixture::{
BucketOperations as _, BucketOptions, ECStore, Endpoint, EndpointServerPools, Endpoints, MakeBucketOptions, PoolEndpoints,
init_bucket_metadata_sys, init_local_disks,
BucketOperations as _, BucketOptions, ECStore, Endpoint, EndpointServerPools, Endpoints, MakeBucketOptions, ObjectIO as _,
PoolEndpoints, PutObjReader, SelectObjectSnapshot, init_bucket_metadata_sys, init_local_disks,
};
use tokio_util::sync::CancellationToken;
static INIT_TRACING: Once = Once::new();
#[cfg(feature = "put-object-commit-barrier")]
pub struct PutObjectCommitBarrier(ecstore_set_disk::test_util::PutObjectCommitBarrier);
#[cfg(feature = "put-object-commit-barrier")]
impl PutObjectCommitBarrier {
pub fn before_namespace(bucket: &str, object: &str) -> Self {
Self(ecstore_set_disk::test_util::PutObjectCommitBarrier::install(
bucket,
object,
ecstore_set_disk::test_util::PutObjectCommitPause::BeforeNamespace,
))
}
pub async fn wait_until_paused(&self) {
self.0.wait_until_paused().await;
}
pub async fn release_and_wait_until_namespace_pending(&self) {
self.0.release_and_wait_until_namespace_pending().await;
}
}
/// Install the standard test tracing subscriber once per process
/// (`RUST_LOG`-driven). Safe to call from every test; later calls are no-ops.
pub fn init_tracing() {
@@ -90,6 +114,29 @@ impl TestECStoreEnv {
.await
.unwrap_or_else(|e| panic!("failed to create test bucket {bucket}: {e:?}"));
}
/// Write one complete object body through the real ECStore test backend.
pub async fn put_object_bytes(&self, bucket: &str, object: &str, bytes: Vec<u8>) {
let mut reader = PutObjReader::from_vec(bytes);
self.ecstore
.put_object(bucket, object, &mut reader, &Default::default())
.await
.unwrap_or_else(|e| panic!("failed to write test object {bucket}/{object}: {e:?}"));
}
/// Prepare the lock-backed object snapshot used by SelectObjectContent tests.
///
/// The concrete ECStore snapshot type stays behind this crate's test
/// compatibility boundary; consumers can pass the inferred value directly
/// to the S3 Select API without importing ECStore facade paths.
pub async fn prepare_select_object_snapshot(&self, bucket: &str, object: &str) -> Arc<SelectObjectSnapshot> {
Arc::new(
self.ecstore
.prepare_select_object_snapshot(bucket, object, &Default::default(), &Default::default())
.await
.unwrap_or_else(|e| panic!("failed to prepare test object snapshot {bucket}/{object}: {e:?}")),
)
}
}
/// Builder for [`TestECStoreEnv`]. Defaults reproduce the historical heal