Skip to content

Commit 790eab9

Browse files
RUN-656: Fix PageMap::get_memory_region bug
1 parent 9320948 commit 790eab9

File tree

3 files changed

+92
-4
lines changed

3 files changed

+92
-4
lines changed

rs/replicated_state/src/page_map.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ impl std::fmt::Display for PersistenceError {
250250

251251
/// A wrapper around the raw file descriptor to be used for memory mapping the
252252
/// file into the Wasm heap while executing a canister.
253-
#[derive(Serialize, Deserialize, Clone, Debug)]
253+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
254254
pub struct FileDescriptor {
255255
pub fd: RawFd,
256256
}
@@ -266,6 +266,7 @@ pub type FileOffset = off_t;
266266
/// - The page maps to the checkpoint file.
267267
/// - The page is in the page delta of the current `PageMap`. In this case the
268268
/// range is a singleton and its contents need to be copied out.
269+
#[derive(Debug, PartialEq)]
269270
pub enum MemoryRegion<'a> {
270271
Zeros(Range<PageIndex>),
271272
BackedByFile(Range<PageIndex>, FileDescriptor),

rs/replicated_state/src/page_map/checkpoint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ impl Mapping {
130130
let num_pages = (self.mmap.len() / PAGE_SIZE) as u64;
131131
if page_index.get() >= num_pages {
132132
MemoryRegion::Zeros(Range {
133-
start: PageIndex::new(num_pages),
133+
start: PageIndex::new(std::cmp::max(num_pages, page_range.start.get())),
134134
end: page_range.end,
135135
})
136136
} else {

rs/replicated_state/src/page_map/tests.rs

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use super::{
44
Buffer, FileDescriptor, PageAllocator, PageAllocatorRegistry, PageDelta, PageIndex, PageMap,
55
PageMapSerialization,
66
};
7-
use crate::page_map::TestPageAllocatorFileDescriptorImpl;
7+
use crate::page_map::{MemoryRegion, TestPageAllocatorFileDescriptorImpl};
88
use ic_sys::PAGE_SIZE;
99
use ic_types::{Height, MAX_STABLE_MEMORY_IN_BYTES};
1010
use nix::unistd::dup;
11-
use std::fs::OpenOptions;
1211
use std::sync::Arc;
12+
use std::{fs::OpenOptions, ops::Range};
1313

1414
fn assert_equal_page_maps(page_map1: &PageMap, page_map2: &PageMap) {
1515
assert_eq!(page_map1.num_host_pages(), page_map2.num_host_pages());
@@ -405,3 +405,90 @@ fn calc_dirty_pages_matches_actual_change() {
405405
)
406406
.unwrap()
407407
}
408+
409+
#[test]
410+
fn zeros_region_after_delta() {
411+
let mut page_map = PageMap::new_for_testing();
412+
let tmp = tempfile::Builder::new()
413+
.prefix("checkpoints")
414+
.tempdir()
415+
.unwrap();
416+
let heap_file = tmp.path().join("heap");
417+
let pages = &[(PageIndex::new(1), &[1u8; PAGE_SIZE])];
418+
page_map.update(pages);
419+
420+
page_map.persist_delta(&heap_file).unwrap();
421+
422+
let mut page_map = PageMap::open(
423+
&heap_file,
424+
Height::new(0),
425+
Arc::new(TestPageAllocatorFileDescriptorImpl::new()),
426+
)
427+
.unwrap();
428+
429+
let zero_range = page_map.get_memory_region(PageIndex::new(5));
430+
assert_eq!(
431+
MemoryRegion::Zeros(Range {
432+
start: PageIndex::new(2),
433+
end: PageIndex::new(u64::MAX)
434+
}),
435+
zero_range
436+
);
437+
438+
let pages = &[(PageIndex::new(3), &[1u8; PAGE_SIZE])];
439+
page_map.update(pages);
440+
441+
let zero_range = page_map.get_memory_region(PageIndex::new(5));
442+
assert_eq!(
443+
MemoryRegion::Zeros(Range {
444+
start: PageIndex::new(4),
445+
end: PageIndex::new(u64::MAX)
446+
}),
447+
zero_range
448+
);
449+
}
450+
451+
#[test]
452+
fn zeros_region_within_delta() {
453+
let mut page_map = PageMap::new_for_testing();
454+
let tmp = tempfile::Builder::new()
455+
.prefix("checkpoints")
456+
.tempdir()
457+
.unwrap();
458+
let heap_file = tmp.path().join("heap");
459+
let pages = &[(PageIndex::new(1), &[1u8; PAGE_SIZE])];
460+
page_map.update(pages);
461+
462+
page_map.persist_delta(&heap_file).unwrap();
463+
464+
let mut page_map = PageMap::open(
465+
&heap_file,
466+
Height::new(0),
467+
Arc::new(TestPageAllocatorFileDescriptorImpl::new()),
468+
)
469+
.unwrap();
470+
471+
let zero_range = page_map.get_memory_region(PageIndex::new(5));
472+
assert_eq!(
473+
MemoryRegion::Zeros(Range {
474+
start: PageIndex::new(2),
475+
end: PageIndex::new(u64::MAX)
476+
}),
477+
zero_range
478+
);
479+
480+
let pages = &[
481+
(PageIndex::new(3), &[1u8; PAGE_SIZE]),
482+
(PageIndex::new(10), &[1u8; PAGE_SIZE]),
483+
];
484+
page_map.update(pages);
485+
486+
let zero_range = page_map.get_memory_region(PageIndex::new(5));
487+
assert_eq!(
488+
MemoryRegion::Zeros(Range {
489+
start: PageIndex::new(4),
490+
end: PageIndex::new(10)
491+
}),
492+
zero_range
493+
);
494+
}

0 commit comments

Comments
 (0)