@@ -85,66 +85,30 @@ impl SharedMemorySnapshot {
8585 }
8686
8787 let mut pages_to_restore = HashSet :: new ( ) ;
88+
89+ // Unconditionally restore all current dirty pages
8890 for page_num in bit_index_iterator ( current_dirty_pages) {
8991 pages_to_restore. insert ( page_num) ;
9092 }
9193
9294 if let Some ( most_recent) = most_recent_snapshot {
93- // Check if we're restoring to the same snapshot state the sandbox was most recently in
9495 if Arc :: ptr_eq ( self , most_recent) {
95- // No need to collect additional pages - just use current dirty pages
96- }
97- // Check if we're "rolling back" to a previous state, i.e. `self` is older than `most_recent` (`self` is ancestor of `most_recent`)
98- // We need to restore all pages that exist in `most_recent` and its ancestors up to `self` (exclusive)
99- else if self . is_ancestor_of ( most_recent) {
100- let mut current_snapshot = Some ( most_recent) ;
101-
102- while let Some ( snapshot) = current_snapshot {
103- if Arc :: ptr_eq ( snapshot, self ) {
104- break ;
105- }
106-
107- for page_num in snapshot. data . keys ( ) {
108- pages_to_restore. insert ( * page_num) ;
109- }
110-
111- current_snapshot = snapshot. parent . as_ref ( ) ;
112- }
113- // Check if we're "fast forwarding" to a "newer" state, i.e. `self` is newer than `most_recent` (`most_recent` is ancestor of `self`)
114- // We need to restore all pages that exist in `self` and its ancestors up to `most_recent` (exclusive)
96+ // Restoring to same snapshot sandbox was most recently in: only restore current dirty pages
97+ } else if self . is_ancestor_of ( most_recent) {
98+ // Rolling back: collect pages from most_recent back to self (exclusive)
99+ Self :: collect_pages_from_chain ( most_recent, Some ( self ) , & mut pages_to_restore) ;
115100 } else if most_recent. is_ancestor_of ( self ) {
116- let mut current_snapshot = Some ( self ) ;
117-
118- while let Some ( snapshot) = current_snapshot {
119- if Arc :: ptr_eq ( snapshot, most_recent) {
120- break ;
121- }
122-
123- for page_num in snapshot. data . keys ( ) {
124- pages_to_restore. insert ( * page_num) ;
125- }
126-
127- current_snapshot = snapshot. parent . as_ref ( ) ;
128- }
101+ // Fast-forwarding: collect pages from self back to most_recent (exclusive)
102+ Self :: collect_pages_from_chain ( self , Some ( most_recent) , & mut pages_to_restore) ;
129103 } else {
130- // Neither is ancestor of the other - they're on different branches
131- // This is not supported for now
104+ // Different branches not supported for now
132105 return Err ( crate :: new_error!(
133106 "Cannot restore between snapshots on different branches"
134107 ) ) ;
135108 }
136109 } else {
137- // No previous snapshots exist, meaning we're restoring a fresh sandbox to this snapshot.
138- // We need to restore pages that exist in this snapshot and all its ancestors.
139- let mut current_snapshot = Some ( self ) ;
140-
141- while let Some ( snapshot) = current_snapshot {
142- for page_num in snapshot. data . keys ( ) {
143- pages_to_restore. insert ( * page_num) ;
144- }
145-
146- current_snapshot = snapshot. parent . as_ref ( ) ;
147- }
110+ // Sandbox has no previous snapshots: restore all pages from this snapshot and its ancestors
111+ Self :: collect_pages_from_chain ( self , None , & mut pages_to_restore) ;
148112 }
149113
150114 // Restore all collected pages
@@ -156,11 +120,11 @@ impl SharedMemorySnapshot {
156120 if let Some ( page_data) = self . find_page_in_snapshots ( page_num) {
157121 // Restore from snapshot
158122 // # Safety: We don't want to dirty the pages we restore
159- unsafe { e. restore_copy_from_slice ( page_data, offset) ? } ;
123+ unsafe { e. copy_from_slice_no_dirty ( page_data, offset) ? } ;
160124 } else {
161125 // Zero the page (return to initial state)
162126 // # Safety: We don't want to dirty the pages we restore
163- unsafe { e. restore_zero_fill ( offset, PAGE_SIZE_USIZE ) ? } ;
127+ unsafe { e. zero_fill_no_dirty ( offset, PAGE_SIZE_USIZE ) ? } ;
164128 }
165129 }
166130 Ok ( ( ) )
@@ -170,7 +134,7 @@ impl SharedMemorySnapshot {
170134 }
171135
172136 /// Check if this snapshot is an ancestor of the other snapshot
173- /// (i.e., the other snapshot was taken after this one in the same chain)
137+ /// (i.e. the other snapshot was taken after this one in the same chain)
174138 fn is_ancestor_of ( self : & Arc < Self > , other : & Arc < SharedMemorySnapshot > ) -> bool {
175139 let mut current = other. parent . as_ref ( ) ;
176140
@@ -204,6 +168,30 @@ impl SharedMemorySnapshot {
204168 pub ( super ) fn sandbox_size ( & self ) -> usize {
205169 self . sandbox_size
206170 }
171+
172+ /// Collect all page numbers from snapshots in a chain, starting from `start_snapshot`
173+ /// and stopping when `stop_snapshot` is reached (exclusive) or when the chain ends.
174+ fn collect_pages_from_chain (
175+ start_snapshot : & Arc < SharedMemorySnapshot > ,
176+ stop_snapshot : Option < & Arc < SharedMemorySnapshot > > ,
177+ pages_to_restore : & mut HashSet < usize > ,
178+ ) {
179+ let mut current_snapshot = Some ( start_snapshot) ;
180+
181+ while let Some ( snapshot) = current_snapshot {
182+ if let Some ( stop) = stop_snapshot {
183+ if Arc :: ptr_eq ( snapshot, stop) {
184+ break ;
185+ }
186+ }
187+
188+ for page_num in snapshot. data . keys ( ) {
189+ pages_to_restore. insert ( * page_num) ;
190+ }
191+
192+ current_snapshot = snapshot. parent . as_ref ( ) ;
193+ }
194+ }
207195}
208196
209197#[ cfg( test) ]
0 commit comments