volume(rust): report a low-disk volume as read-only but deletable

Mirrors the Go heartbeat: readOnlyCanDelete is set whenever the volume
is read-only without no_write_or_delete, which includes low disk space.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chris LuandClaude Opus 5.5 committed 2026-11-02 04:42:33 -08:00
1 parent 1caae79f1a
commit 504230ce1e
2 files changed
+47 -2

No files matched your search

+40 -2
View File
@@ -1365,6 +1365,7 @@ fn build_heartbeat_with_ec_status(
}
let (remote_storage_name, remote_storage_key) = vol.remote_storage_name_key();
let (read_only, read_only_can_delete) = vol.reported_read_only();
let volume_message = master_pb::VolumeInformationMessage {
id: vol.id.0,
size: volume_size,
@@ -1372,8 +1373,8 @@ fn build_heartbeat_with_ec_status(
file_count: vol.file_count() as u64,
delete_count: vol.deleted_count() as u64,
deleted_byte_count: vol.deleted_size(),
read_only: vol.is_read_only(),
read_only_can_delete: vol.is_no_write_can_delete(),
read_only,
read_only_can_delete,
replica_placement: vol.super_block().replica_placement.to_byte() as u32,
version: vol.super_block().version.0 as u32,
ttl: vol.super_block().ttl.to_u32(),
@@ -1819,6 +1820,43 @@ mod tests {
);
}
#[test]
fn test_build_heartbeat_low_disk_volume_reports_can_delete() {
let temp_dir = tempfile::tempdir().unwrap();
let dir = temp_dir.path().to_str().unwrap();
let mut store = Store::new(NeedleMapKind::InMemory);
store
.add_location(
dir,
dir,
3,
DiskType::HardDrive,
MinFreeSpace::Percent(1.0),
vec![],
)
.unwrap();
store
.add_volume(VolumeId(7), DiskType::HardDrive, &VolumeSpec::default())
.unwrap();
store.locations[0]
.is_disk_space_low
.store(true, std::sync::atomic::Ordering::Relaxed);
let heartbeat = build_heartbeat(&test_config(), &mut store);
assert!(heartbeat.volumes[0].read_only);
assert!(heartbeat.volumes[0].read_only_can_delete);
store
.find_volume(VolumeId(7))
.unwrap()
.1
.set_no_write_or_delete(true);
let heartbeat = build_heartbeat(&test_config(), &mut store);
assert!(heartbeat.volumes[0].read_only);
assert!(!heartbeat.volumes[0].read_only_can_delete);
}
#[test]
fn test_build_heartbeat_marks_empty_store_as_has_no_volumes() {
let temp_dir = tempfile::tempdir().unwrap();
+7
View File
@@ -3490,6 +3490,13 @@ impl Volume {
self.no_write_flags().1
}
/// What the master is told: low disk space still lets deletes through,
/// only no_write_or_delete refuses them. Mirrors Go's reportedReadOnly.
pub fn reported_read_only(&self) -> (bool, bool) {
let (read_only, no_write_or_delete, _, _) = self.read_only_reasons();
(read_only, read_only && !no_write_or_delete)
}
pub fn last_compact_revision(&self) -> u16 {
self.io.read().unwrap().last_compact_revision
}