refactor: move object list helper contracts (#3546)

This commit is contained in:
安正超
2026-06-18 06:09:33 +08:00
committed by GitHub
parent 87a3d107d6
commit 54bbd05b25
9 changed files with 113 additions and 43 deletions
Generated
+1
View File
@@ -10069,6 +10069,7 @@ dependencies = [
"serde_json",
"time",
"tokio",
"uuid",
]
[[package]]
+1 -14
View File
@@ -1,5 +1,5 @@
use super::*;
use rustfs_storage_api::{HTTPPreconditions, ObjectLockRetentionOptions};
use rustfs_storage_api::{HTTPPreconditions, ObjectLockRetentionOptions, VersionMarker, WalkVersionsSortOrder};
#[derive(Debug, Default, Clone)]
pub struct ObjectOptions {
@@ -740,12 +740,6 @@ impl ObjectInfo {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VersionMarker {
Null,
Version(Uuid),
}
fn versions_after_marker(file_infos: &rustfs_filemeta::FileInfoVersions, marker: VersionMarker) -> &[FileInfo] {
let marker_idx = match marker {
VersionMarker::Null => file_infos.versions.iter().position(|version| version.version_id.is_none()),
@@ -876,13 +870,6 @@ pub struct WalkOptions {
pub include_free_versions: bool, // include persisted tier free-version cleanup records
}
#[derive(Clone, Default, PartialEq, Eq)]
pub enum WalkVersionsSortOrder {
#[default]
Ascending,
Descending,
}
#[derive(Debug)]
pub struct ObjectInfoOrErr {
pub item: Option<ObjectInfo>,
+3 -7
View File
@@ -23,8 +23,7 @@ use crate::error::{
};
use crate::set_disk::SetDisks;
use crate::store_api::{
ListObjectVersionsInfo, ListObjectsInfo, ObjectInfo, ObjectInfoOrErr, ObjectOperations, ObjectOptions, VersionMarker,
WalkOptions, WalkVersionsSortOrder,
ListObjectVersionsInfo, ListObjectsInfo, ObjectInfo, ObjectInfoOrErr, ObjectOperations, ObjectOptions, WalkOptions,
};
use crate::store_utils::is_reserved_or_invalid_bucket;
use crate::{store::ECStore, store_api::ListObjectsV2Info};
@@ -34,6 +33,7 @@ use rustfs_filemeta::{
MetaCacheEntries, MetaCacheEntriesSorted, MetaCacheEntriesSortedResult, MetaCacheEntry, MetadataResolutionParams,
merge_file_meta_versions,
};
use rustfs_storage_api::{VersionMarker, WalkVersionsSortOrder};
use rustfs_utils::path::{self, SLASH_SEPARATOR, base_dir_from_prefix};
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
@@ -201,11 +201,7 @@ fn list_metadata_resolution_params(bucket: String, listing_quorum: usize, versio
}
fn parse_version_marker(marker: String) -> Result<VersionMarker> {
if marker == "null" {
Ok(VersionMarker::Null)
} else {
Ok(VersionMarker::Version(Uuid::parse_str(&marker)?))
}
Ok(VersionMarker::parse(marker)?)
}
fn version_marker_for_entries(
+1
View File
@@ -31,6 +31,7 @@ doctest = false
async-trait.workspace = true
serde.workspace = true
time.workspace = true
uuid.workspace = true
[dev-dependencies]
serde_json.workspace = true
+1
View File
@@ -25,3 +25,4 @@ pub use bucket::{BucketInfo, BucketOperations, BucketOptions, DeleteBucketOption
pub use error::{StorageErrorCode, StorageResult};
pub use multipart::{CompletePart, ListMultipartsInfo, ListPartsInfo, MultipartInfo, MultipartUploadResult, PartInfo};
pub use object::{HTTPPreconditions, HTTPRangeError, HTTPRangeSpec, ObjectLockRetentionOptions};
pub use object::{VersionMarker, WalkVersionsSortOrder};
+43
View File
@@ -14,6 +14,9 @@
use std::fmt;
use time::OffsetDateTime;
use uuid::Uuid;
const NULL_VERSION_MARKER: &str = "null";
#[derive(Debug, Default, Clone)]
pub struct HTTPPreconditions {
@@ -40,6 +43,30 @@ pub struct ObjectLockRetentionOptions {
pub bypass_governance: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VersionMarker {
Null,
Version(Uuid),
}
impl VersionMarker {
pub fn parse(marker: impl AsRef<str>) -> Result<Self, uuid::Error> {
let marker = marker.as_ref();
if marker == NULL_VERSION_MARKER {
Ok(Self::Null)
} else {
Ok(Self::Version(Uuid::parse_str(marker)?))
}
}
}
#[derive(Clone, Default, PartialEq, Eq)]
pub enum WalkVersionsSortOrder {
#[default]
Ascending,
Descending,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HTTPRangeError {
InvalidRangeSpec(String),
@@ -183,6 +210,22 @@ mod tests {
assert!(!opts.bypass_governance);
}
#[test]
fn version_marker_parses_null_and_uuid_markers() {
assert_eq!(VersionMarker::parse("null").expect("null marker should parse"), VersionMarker::Null);
let marker = "550e8400-e29b-41d4-a716-446655440000";
assert_eq!(
VersionMarker::parse(marker).expect("uuid marker should parse"),
VersionMarker::Version(Uuid::parse_str(marker).expect("test uuid should parse"))
);
}
#[test]
fn walk_versions_sort_order_defaults_to_ascending() {
assert!(matches!(WalkVersionsSortOrder::default(), WalkVersionsSortOrder::Ascending));
}
#[test]
fn http_range_spec_offset_length_handles_suffix_and_bounds() {
let range = HTTPRangeSpec {
+1
View File
@@ -95,6 +95,7 @@ Required `rustfs-storage-api` public re-exports:
- `pub use error::{StorageErrorCode, StorageResult};`
- `pub use multipart::{CompletePart, ListMultipartsInfo, ListPartsInfo, MultipartInfo, MultipartUploadResult, PartInfo};`
- `pub use object::{HTTPPreconditions, HTTPRangeError, HTTPRangeSpec, ObjectLockRetentionOptions};`
- `pub use object::{VersionMarker, WalkVersionsSortOrder};`
ECStore must keep compile-time coverage for both `StorageAdminApi` and the
separate `NamespaceLocking` operation group.
+47 -22
View File
@@ -5,17 +5,19 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
## Current Context
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
- Branch: `overtrue/arch-range-contracts`
- Baseline: `overtrue/arch-object-option-contracts` at `5328e10a0f0cdda9cc17089956e17432f2875962`
- Branch: `overtrue/arch-object-list-helper-contracts`
- Baseline: `overtrue/arch-range-contracts` at `829bc62095f0fd853747cd6d7d77f8558baf24a2`
over `origin/main` at `a9aba323c6512e6b99c3137258b97b6058075ce9`
- PR type for this branch: `api-extraction`
- Runtime behavior changes: no external behavior change expected.
- Rust code changes: move the pure `HTTPRangeSpec` range contract and
`HTTPRangeError` into `rustfs-storage-api`, then keep ECStore object-info
adaptation at the ECStore boundary.
- CI/script changes: extend migration guards for range helper public re-exports
and reject restoring the old ECStore-owned range helper definitions.
- Docs changes: record the range contract extraction slice.
- Rust code changes: move the pure `VersionMarker` and
`WalkVersionsSortOrder` list helper contracts into `rustfs-storage-api`,
then keep ECStore list/walk implementations and filemeta adaptation at the
ECStore boundary.
- CI/script changes: extend migration guards for list helper public re-exports
and reject restoring the old ECStore-owned list helper definitions or
public re-exports.
- Docs changes: record the list helper contract extraction slice.
## Phase 0 Tasks
@@ -577,6 +579,26 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
migration/layer guards, formatting, diff hygiene, Rust risk scan, and
required three-expert review passed.
- [x] `API-017` Move object list helper contracts.
- Completed slice: move `VersionMarker` and `WalkVersionsSortOrder` from
ECStore `store_api/types.rs` into `rustfs-storage-api`; keep
`versions_after_marker`, `WalkOptions`, `ObjectInfo`, list result DTOs,
readers, and storage list/walk implementations in ECStore.
- Acceptance: `rustfs-storage-api` exports the list helper contracts,
in-repo production code no longer imports them from
`rustfs_ecstore::store_api`, and migration guards reject restoring old
ECStore definitions or public re-exports.
- Must preserve: list-object-versions marker parsing, null version markers,
version marker application only to the first matching entry, walk sort
default, and ECStore-owned filemeta/list implementation behavior.
- Risk defense: only pure marker/sort contracts cross into
`rustfs-storage-api`; ECStore keeps filemeta conversion, list result DTOs,
walk options with filemeta filters, readers, lifecycle/replication coupling,
and storage implementation bodies.
- Verification: focused storage-api/ECStore/RustFS/downstream compile checks,
migration/layer guards, formatting, diff hygiene, Rust risk scan, and
required three-expert review passed.
## Phase 8 Background Controller Tasks
- [x] `BGC-001` Inventory background services.
@@ -853,36 +875,39 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Expert | Status | Notes |
|---|---|---|
| Quality/architecture | passed | Pure multipart/object helper contracts now live in `rustfs-storage-api`; implementation-heavy object contracts and ECStore behavior stay in ECStore. |
| Migration preservation | passed | The slice changes helper type ownership and import paths only; multipart completion mapping, HTTP precondition values, object-lock retention fields, and storage hot paths are unchanged. |
| Quality/architecture | passed | Pure object list helper contracts now live in `rustfs-storage-api`; implementation-heavy list/walk contracts and ECStore behavior stay in ECStore. |
| Migration preservation | passed | The slice changes helper type ownership and import paths only; null version marker parsing, first-entry version marker behavior, walk sort default, and ECStore filemeta/list behavior are unchanged. |
| Testing/verification | passed | Focused storage-api/ECStore/RustFS/downstream compile checks, migration/layer guards, formatting, diff hygiene, Rust risk scan, and full `make pre-commit` passed. |
## Verification Notes
Passed on `8d24d9133b31c0ca0de0fcd16ad06cd2fdc6f7ae`:
Passed before push:
- `cargo check -p rustfs-storage-api -p rustfs-ecstore -p rustfs-iam -p rustfs-scanner -p rustfs`: passed.
- `cargo test -p rustfs-storage-api`: passed.
- `cargo check --tests -p rustfs-storage-api -p rustfs-ecstore -p rustfs -p rustfs-iam -p rustfs-scanner`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_layer_dependencies.sh`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- Rust risk scan: no new production `unwrap`/`expect`, panic/todo markers,
`unsafe`, or process-spawning calls in added Rust lines.
`unsafe`, process-spawning calls, lossy casts, println/eprintln, or relaxed
ordering in added Rust lines; new `expect` calls are test-only assertions.
- `make pre-commit`: passed.
Notes:
- This slice follows `rustfs/rustfs#3507` and keeps the old aggregate facade,
bucket DTO, multipart DTO, bucket operation contract, and object helper
contract guards active.
- The shared object helper contracts are now owned by `rustfs-storage-api`;
ECStore keeps implementation-heavy object, list, reader, lock, lifecycle,
replication, rio, filemeta, and storage error contracts.
- The slice does not alter object, multipart, or bucket runtime behavior.
- This slice follows the range helper contract branch and keeps the old
aggregate facade, bucket DTO, multipart DTO, bucket operation contract, object
helper, range helper, and list helper contract guards active.
- The shared list marker/sort helper contracts are now owned by
`rustfs-storage-api`; ECStore keeps implementation-heavy object/list result
DTOs, walk options with filemeta filters, readers, lifecycle/replication, rio,
filemeta, and storage error contracts.
- The slice does not alter list, walk, object, multipart, or bucket runtime
behavior.
## Handoff Notes
- Object helper contract cleanup is in progress on a branch current with
`origin/main`.
- List helper contract cleanup is stacked on the range helper contract branch.
- After this lands, remaining storage work can continue by extracting larger
low-coupling DTO slices or by narrowing remaining operation-group consumers.
@@ -55,6 +55,7 @@ STORE_API_BUCKET_OPERATION_HITS_FILE="${TMP_DIR}/store_api_bucket_operation_hits
STORE_API_MULTIPART_DTO_REEXPORTS_FILE="${TMP_DIR}/store_api_multipart_dto_reexports.txt"
STORE_API_OBJECT_HELPER_REEXPORTS_FILE="${TMP_DIR}/store_api_object_helper_reexports.txt"
STORE_API_RANGE_HELPER_REEXPORTS_FILE="${TMP_DIR}/store_api_range_helper_reexports.txt"
STORE_API_LIST_HELPER_REEXPORTS_FILE="${TMP_DIR}/store_api_list_helper_reexports.txt"
awk '
/^## PR Types$/ {
@@ -195,6 +196,10 @@ require_source_line \
"crates/storage-api/src/lib.rs" \
"pub use object::{HTTPPreconditions, HTTPRangeError, HTTPRangeSpec, ObjectLockRetentionOptions};" \
"storage-api public object helper contract re-export"
require_source_line \
"crates/storage-api/src/lib.rs" \
"pub use object::{VersionMarker, WalkVersionsSortOrder};" \
"storage-api public list helper contract re-export"
require_source_line \
"crates/storage-api/src/lib.rs" \
"pub use error::{StorageErrorCode, StorageResult};" \
@@ -259,6 +264,16 @@ if [[ -s "$STORE_API_RANGE_HELPER_REEXPORTS_FILE" ]]; then
report_failure "old ecstore store_api range helper path reintroduced: $(paste -sd '; ' "$STORE_API_RANGE_HELPER_REEXPORTS_FILE")"
fi
(
cd "$ROOT_DIR"
rg -n --no-heading 'pub(?:\(crate\))? use rustfs_storage_api(?:::\{[^}]*\b(?:VersionMarker|WalkVersionsSortOrder)\b|::(?:VersionMarker|WalkVersionsSortOrder)\b)|pub enum (?:VersionMarker|WalkVersionsSortOrder)\b' \
crates/ecstore/src/store_api.rs crates/ecstore/src/store_api/types.rs || true
) >"$STORE_API_LIST_HELPER_REEXPORTS_FILE"
if [[ -s "$STORE_API_LIST_HELPER_REEXPORTS_FILE" ]]; then
report_failure "old ecstore store_api list helper path reintroduced: $(paste -sd '; ' "$STORE_API_LIST_HELPER_REEXPORTS_FILE")"
fi
require_source_contains \
"crates/ecstore/src/store_api/traits.rs" \
"pub trait NamespaceLocking: Send + Sync + Debug + 'static" \