mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-11-02 02:10:45 +01:00
Rust volume: stamp ExpireAtSec into the live volume_info on .vif persist (#11813)
The worker fix reads the source's TTL destroy time through ReadVolumeFileStatus, which returns the in-memory volume_info. Go's SaveVolumeInfo stamps volumeInfo.ExpireAtSec before writing; Rust's save_vif wrote it only to the serialized file, so a Rust source kept reporting the stale creation-time value and the EC .vif would carry a wrong expiry. Stamp the live volume_info first, mirroring Go and save_volume_info.
This commit is contained in:
1 parent
8c55425d55
commit
ab39e3a51b
2 files changed
+53
-3
No files matched your search
@@ -10408,6 +10408,55 @@ mod tests {
|
||||
assert!(vif.expire_at_sec <= before + ttl.to_seconds() + 5);
|
||||
}
|
||||
|
||||
/// The worker EC encode reads ExpireAtSec out of ReadVolumeFileStatus, so
|
||||
/// persisting a readonly mark must stamp it into the live volume_info too,
|
||||
/// not only into the written .vif. A creation-time stamp would sit a full
|
||||
/// last-write interval early.
|
||||
#[tokio::test]
|
||||
async fn test_mark_readonly_persist_reports_expire_at_sec() {
|
||||
let ttl = crate::storage::needle::ttl::TTL::read("3m").unwrap();
|
||||
let (service, _tmp) = make_local_service_with_volume("ttl", Some(ttl));
|
||||
|
||||
// A later write must move the expiry: pin it ahead of the setup write
|
||||
// so the stale creation-time stamp cannot collide on the same second.
|
||||
let last_write = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs()
|
||||
+ 60;
|
||||
service
|
||||
.state
|
||||
.store
|
||||
.write()
|
||||
.unwrap()
|
||||
.find_volume_mut(VolumeId(1))
|
||||
.unwrap()
|
||||
.1
|
||||
.set_last_modified_ts_for_test(last_write);
|
||||
service
|
||||
.state
|
||||
.store
|
||||
.write()
|
||||
.unwrap()
|
||||
.find_volume_mut(VolumeId(1))
|
||||
.unwrap()
|
||||
.1
|
||||
.set_read_only_persist(false, true)
|
||||
.unwrap();
|
||||
|
||||
let status = service
|
||||
.read_volume_file_status(Request::new(
|
||||
volume_server_pb::ReadVolumeFileStatusRequest { volume_id: 1 },
|
||||
))
|
||||
.await
|
||||
.unwrap()
|
||||
.into_inner();
|
||||
assert_eq!(
|
||||
status.volume_info.unwrap().expire_at_sec,
|
||||
last_write + ttl.to_seconds()
|
||||
);
|
||||
}
|
||||
|
||||
/// A re-encode must not mix artifacts from a previous run. Generate used to
|
||||
/// go straight into the encode, truncating only the `.ecNN` files on the
|
||||
/// encoding disk; a stale shard on a sibling disk survived and was later
|
||||
|
||||
@@ -3969,13 +3969,14 @@ impl Volume {
|
||||
self.no_write_can_delete && !self.has_remote_file() && !self.no_write_or_delete;
|
||||
self.volume_info.read_only = self.no_write_or_delete || marked_can_delete;
|
||||
self.volume_info.read_only_can_delete = marked_can_delete;
|
||||
let mut vif = VifVolumeInfo::from_pb(&self.volume_info);
|
||||
|
||||
// Match Go's SaveVolumeInfo: compute ExpireAtSec from TTL
|
||||
// Match Go's SaveVolumeInfo: stamp ExpireAtSec into the live volume_info
|
||||
// so read_volume_file_status returns it, not only into the written file.
|
||||
let expire_at_sec = self.expire_at_sec();
|
||||
if expire_at_sec > 0 {
|
||||
vif.expire_at_sec = expire_at_sec;
|
||||
self.volume_info.expire_at_sec = expire_at_sec;
|
||||
}
|
||||
let vif = VifVolumeInfo::from_pb(&self.volume_info);
|
||||
|
||||
let content = serde_json::to_string_pretty(&vif)
|
||||
.map_err(|e| VolumeError::Io(io::Error::other(e.to_string())))?;
|
||||
|
||||
Reference in new issue
Block a user