mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-25 13:36:50 +00:00
fix(ecstore): reconcile object cleanup receipts (#6077)
* fix(s3): keep multipart completion publication owned Co-Authored-By: heihutu <heihutu@gmail.com> * fix(s3): keep put publication owned Co-Authored-By: heihutu <heihutu@gmail.com> * chore(app): route multipart context through facade Co-Authored-By: heihutu <heihutu@gmail.com> * fix(ecstore): gate object transaction fencing Co-Authored-By: heihutu <heihutu@gmail.com> * fix(ecstore): fence object transaction epochs Co-Authored-By: heihutu <heihutu@gmail.com> * fix(ecstore): reconcile old data cleanup receipts Co-Authored-By: heihutu <heihutu@gmail.com> --------- Co-authored-by: heihutu <heihutu@gmail.com>
This commit is contained in:
@@ -18,8 +18,9 @@ use rmp_serde::Serializer;
|
||||
use rustfs_utils::HashAlgorithm;
|
||||
use rustfs_utils::http::{
|
||||
AMZ_OBJECT_TAGGING, SUFFIX_COMPRESSION, SUFFIX_DATA_MOVED, SUFFIX_DATA_MOVED_TAGS, SUFFIX_FREE_VERSION, SUFFIX_HEALING,
|
||||
SUFFIX_INLINE_DATA, SUFFIX_TIER_FV_ID, SUFFIX_TIER_FV_MARKER, SUFFIX_TIER_SKIP_FV_ID, contains_key_str, get_str,
|
||||
has_internal_suffix, insert_str, is_encryption_metadata_key, starts_with_ignore_ascii_case,
|
||||
SUFFIX_INLINE_DATA, SUFFIX_OBJECT_TRANSACTION_EPOCH, SUFFIX_TIER_FV_ID, SUFFIX_TIER_FV_MARKER, SUFFIX_TIER_SKIP_FV_ID,
|
||||
contains_key_str, get_consistent_str, get_str, has_internal_suffix, insert_str, is_encryption_metadata_key,
|
||||
starts_with_ignore_ascii_case,
|
||||
};
|
||||
use s3s::dto::{RestoreStatus, Timestamp};
|
||||
use s3s::header::X_AMZ_RESTORE;
|
||||
@@ -1172,6 +1173,22 @@ impl FileInfo {
|
||||
insert_str(&mut self.metadata, SUFFIX_DATA_MOVED, String::new());
|
||||
}
|
||||
|
||||
pub fn set_object_transaction_epoch(&mut self, epoch: Uuid) {
|
||||
insert_str(&mut self.metadata, SUFFIX_OBJECT_TRANSACTION_EPOCH, epoch.to_string());
|
||||
}
|
||||
|
||||
pub fn object_transaction_epoch(&self) -> Result<Option<Uuid>> {
|
||||
if !contains_key_str(&self.metadata, SUFFIX_OBJECT_TRANSACTION_EPOCH) {
|
||||
return Ok(None);
|
||||
}
|
||||
let value = get_consistent_str(&self.metadata, SUFFIX_OBJECT_TRANSACTION_EPOCH).ok_or(Error::FileCorrupt)?;
|
||||
let epoch = Uuid::parse_str(value).map_err(|_| Error::FileCorrupt)?;
|
||||
if epoch.is_nil() {
|
||||
return Err(Error::FileCorrupt);
|
||||
}
|
||||
Ok(Some(epoch))
|
||||
}
|
||||
|
||||
pub fn inline_data(&self) -> bool {
|
||||
contains_key_str(&self.metadata, SUFFIX_INLINE_DATA) && !self.is_remote()
|
||||
}
|
||||
@@ -1484,6 +1501,46 @@ mod tests {
|
||||
assert_eq!(ei.get_checksum_info(99).algorithm, HashAlgorithm::HighwayHash256S);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_transaction_epoch_uses_consistent_dual_internal_metadata() {
|
||||
let mut fi = validation_test_fileinfo();
|
||||
assert_eq!(fi.object_transaction_epoch().expect("absent epoch should decode"), None);
|
||||
|
||||
let epoch = Uuid::new_v4();
|
||||
let epoch_text = epoch.to_string();
|
||||
fi.set_object_transaction_epoch(epoch);
|
||||
assert_eq!(fi.object_transaction_epoch().expect("written epoch should decode"), Some(epoch));
|
||||
assert_eq!(fi.metadata.get("x-rustfs-internal-object-transaction-epoch"), Some(&epoch_text));
|
||||
assert_eq!(fi.metadata.get("x-minio-internal-object-transaction-epoch"), Some(&epoch_text));
|
||||
|
||||
let mut rustfs_only = validation_test_fileinfo();
|
||||
rustfs_only
|
||||
.metadata
|
||||
.insert("x-rustfs-internal-object-transaction-epoch".to_string(), epoch_text);
|
||||
assert_eq!(
|
||||
rustfs_only
|
||||
.object_transaction_epoch()
|
||||
.expect("single compatibility key should decode"),
|
||||
Some(epoch)
|
||||
);
|
||||
|
||||
let mut conflicting = fi.clone();
|
||||
conflicting
|
||||
.metadata
|
||||
.insert("x-minio-internal-object-transaction-epoch".to_string(), Uuid::new_v4().to_string());
|
||||
assert_eq!(conflicting.object_transaction_epoch(), Err(Error::FileCorrupt));
|
||||
|
||||
let mut malformed = validation_test_fileinfo();
|
||||
malformed
|
||||
.metadata
|
||||
.insert("x-rustfs-internal-object-transaction-epoch".to_string(), "not-a-uuid".to_string());
|
||||
assert_eq!(malformed.object_transaction_epoch(), Err(Error::FileCorrupt));
|
||||
|
||||
let mut nil = validation_test_fileinfo();
|
||||
nil.set_object_transaction_epoch(Uuid::nil());
|
||||
assert_eq!(nil.object_transaction_epoch(), Err(Error::FileCorrupt));
|
||||
}
|
||||
|
||||
// backlog#949: distribution range/permutation validation.
|
||||
#[test]
|
||||
fn is_valid_distribution_accepts_permutation() {
|
||||
|
||||
Reference in New Issue
Block a user