Skip to content

Commit 392dfd1

Browse files
only clear len for old crc
1 parent 16a676d commit 392dfd1

1 file changed

Lines changed: 27 additions & 30 deletions

File tree

runtime/src/utils/buffer/paged/append.rs

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -798,9 +798,9 @@ impl<B: Blob> Append<B> {
798798
///
799799
/// Since larger valid lengths are authoritative, a shorter CRC cannot simply be written next to
800800
/// the old CRC. We first stage the shorter slot with length 0, then make its length durable,
801-
/// then clear the old slot's CRC bytes before clearing its length bytes. A crash during any
802-
/// phase recovers either the old longer page or the new shorter page, but never loses the whole
803-
/// page or fabricates a larger length.
801+
/// then clear the old slot's length bytes. A crash during any phase recovers either the old
802+
/// longer page or the new shorter page, but never loses the whole page or fabricates a larger
803+
/// length.
804804
async fn sync_partial_page_shrink(
805805
blob: &B,
806806
page: u64,
@@ -842,15 +842,8 @@ impl<B: Blob> Append<B> {
842842
.checked_add(old_slot_start as u64)
843843
.ok_or(Error::OffsetOverflow)?;
844844
let len_size = std::mem::size_of::<u16>();
845-
let crc_size = CHECKSUM_SLOT_SIZE - len_size;
846-
let old_crc_offset = old_slot_offset
847-
.checked_add(len_size as u64)
848-
.ok_or(Error::OffsetOverflow)?;
849-
850-
// Clear CRC bytes before length bytes so torn invalidation cannot create a new valid slot.
851-
blob.write_at(old_crc_offset, vec![0u8; crc_size]).await?;
852-
blob.sync().await?;
853845

846+
// A slot with length 0 is invalid regardless of its CRC.
854847
blob.write_at(old_slot_offset, vec![0u8; len_size]).await?;
855848
blob.sync().await?;
856849

@@ -3058,69 +3051,73 @@ mod tests {
30583051
}
30593052

30603053
#[test]
3061-
fn test_resize_same_page_shrink_survives_interrupted_crc_invalidation() {
3054+
fn test_resize_same_page_shrink_survives_interrupted_length_invalidation() {
30623055
let executor = deterministic::Runner::default();
30633056

30643057
executor.start(|context| async move {
3065-
let cache_ref = CacheRef::from_pooler(&context, PAGE_SIZE, NZUsize!(BUFFER_SIZE));
3066-
let data: Vec<u8> = (0..50).collect();
3058+
const LARGE_PAGE_SIZE: NonZeroU16 = NZU16!(600);
3059+
const LARGE_BUFFER_SIZE: usize = 1_200;
3060+
3061+
let cache_ref =
3062+
CacheRef::from_pooler(&context, LARGE_PAGE_SIZE, NZUsize!(LARGE_BUFFER_SIZE));
3063+
let data: Vec<u8> = (0..300).map(|i| (i % 251) as u8).collect();
30673064

30683065
let (blob, size) = context
30693066
.open(
30703067
"test_partition",
3071-
b"same_page_shrink_interrupted_invalidation",
3068+
b"same_page_shrink_interrupted_len_invalidation",
30723069
)
30733070
.await
30743071
.unwrap();
3075-
let append = Append::new(blob, size, BUFFER_SIZE, cache_ref.clone())
3072+
let append = Append::new(blob, size, LARGE_BUFFER_SIZE, cache_ref.clone())
30763073
.await
30773074
.unwrap();
30783075
// Put the old authoritative CRC in slot 1, so the shorter CRC will be staged in slot
3079-
// 0. The old slot is invalidated only after the shorter slot is durable.
3080-
append.append(&data[..40]).await.unwrap();
3076+
// 0. The old length is above 255, so a one-byte tear changes the decoded length.
3077+
append.append(&data[..255]).await.unwrap();
30813078
append.sync().await.unwrap();
3082-
append.append(&data[40..]).await.unwrap();
3079+
append.append(&data[255..]).await.unwrap();
30833080
append.sync().await.unwrap();
30843081
drop(append);
30853082

30863083
let (blob, size) = context
30873084
.open(
30883085
"test_partition",
3089-
b"same_page_shrink_interrupted_invalidation",
3086+
b"same_page_shrink_interrupted_len_invalidation",
30903087
)
30913088
.await
30923089
.unwrap();
3093-
let faulty_blob = PartialWriteBlob::new(blob, 3, 3);
3090+
let faulty_blob = PartialWriteBlob::new(blob, 3, 1);
30943091
let write_count = faulty_blob.write_count();
30953092
let failed_write_len = faulty_blob.failed_write_len();
3096-
let append = Append::new(faulty_blob, size, BUFFER_SIZE, cache_ref.clone())
3093+
let append = Append::new(faulty_blob, size, LARGE_BUFFER_SIZE, cache_ref.clone())
30973094
.await
30983095
.unwrap();
30993096

31003097
assert!(
3101-
append.resize(45).await.is_err(),
3102-
"old-slot invalidation should fail"
3098+
append.resize(40).await.is_err(),
3099+
"old-slot length invalidation should fail"
31033100
);
31043101
assert_eq!(write_count.load(Ordering::SeqCst), 3);
31053102
assert_eq!(
31063103
failed_write_len.load(Ordering::SeqCst),
3107-
CHECKSUM_SLOT_SIZE - std::mem::size_of::<u16>()
3104+
std::mem::size_of::<u16>()
31083105
);
31093106
drop(append);
31103107

31113108
let (blob, size) = context
31123109
.open(
31133110
"test_partition",
3114-
b"same_page_shrink_interrupted_invalidation",
3111+
b"same_page_shrink_interrupted_len_invalidation",
31153112
)
31163113
.await
31173114
.unwrap();
3118-
let append = Append::new(blob, size, BUFFER_SIZE, cache_ref)
3115+
let append = Append::new(blob, size, LARGE_BUFFER_SIZE, cache_ref)
31193116
.await
31203117
.unwrap();
3121-
assert_eq!(append.size().await, 45);
3122-
let read = append.read_at(0, 45).await.unwrap().coalesce();
3123-
assert_eq!(read.as_ref(), &data[..45]);
3118+
assert_eq!(append.size().await, 40);
3119+
let read = append.read_at(0, 40).await.unwrap().coalesce();
3120+
assert_eq!(read.as_ref(), &data[..40]);
31243121
});
31253122
}
31263123

0 commit comments

Comments
 (0)