mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
refactor: move object list helper contracts (#3546)
This commit is contained in:
Generated
+1
@@ -10069,6 +10069,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"time",
|
||||
"tokio",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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" \
|
||||
|
||||
Reference in New Issue
Block a user