1- use std:: time:: Duration ;
2- #[ cfg( not( test) ) ]
3- use std:: time:: Instant ;
4-
5- #[ cfg( test) ]
6- use mock_instant:: Instant ;
7-
81/// 256 KiB.
92#[ cfg( not( test) ) ]
103pub const PAGE_SIZE : usize = 1 << 18 ;
@@ -56,44 +49,27 @@ pub struct Arena {
5649struct ArenaStats {
5750 max_num_used_pages_former : usize ,
5851 max_num_used_pages_current : usize ,
59- call_counter : u8 ,
60- next_window_start : Instant ,
6152}
6253
63- const WINDOW : Duration = Duration :: from_secs ( 60 ) ;
64-
6554impl Default for ArenaStats {
6655 fn default ( ) -> ArenaStats {
6756 ArenaStats {
68- // We arbitrarily initialize num used pages former to 100.
6957 max_num_used_pages_former : 0 ,
7058 max_num_used_pages_current : 0 ,
71- call_counter : 0u8 ,
72- next_window_start : Instant :: now ( ) ,
7359 }
7460 }
7561}
7662
7763impl ArenaStats {
7864 /// This method happens when we are changing time window.
79- fn roll ( & mut self , now : Instant ) {
65+ fn roll ( & mut self ) {
8066 self . max_num_used_pages_former = self . max_num_used_pages_current ;
8167 self . max_num_used_pages_current = 0 ;
82- self . next_window_start = now + WINDOW ;
8368 }
8469
8570 /// Records the number of used pages, and returns an estimation of the maximum number of pages
8671 /// in the last 5 minutes.
8772 pub fn record_num_used_page ( & mut self , num_used_pages : usize ) -> usize {
88- // The only function of the call counter is to avoid calling `Instant::now()`
89- // at every single call.
90- self . call_counter = ( self . call_counter + 1 ) % 64 ;
91- if self . call_counter == 0u8 {
92- let now = Instant :: now ( ) ;
93- if now > self . next_window_start {
94- self . roll ( now) ;
95- }
96- }
9773 self . max_num_used_pages_current = self . max_num_used_pages_current . max ( num_used_pages) ;
9874 self . max_num_used_pages_former
9975 . max ( self . max_num_used_pages_current )
@@ -105,20 +81,17 @@ impl Arena {
10581 pub fn acquire_page ( & mut self ) -> PageId {
10682 if let Some ( page_id) = self . free_page_ids . pop ( ) {
10783 assert ! ( self . pages[ page_id. 0 ] . is_some( ) ) ;
108- self . gc ( ) ;
10984 return page_id;
11085 }
11186 let page: Page = vec ! [ 0u8 ; PAGE_SIZE ] . into_boxed_slice ( ) ;
11287 if let Some ( free_slot) = self . free_slots . pop ( ) {
11388 let slot = & mut self . pages [ free_slot. 0 ] ;
11489 assert ! ( slot. is_none( ) ) ;
11590 * slot = Some ( page) ;
116- self . gc ( ) ;
11791 free_slot
11892 } else {
11993 let new_page_id = self . pages . len ( ) ;
12094 self . pages . push ( Some ( page) ) ;
121- self . gc ( ) ;
12295 PageId ( new_page_id)
12396 }
12497 }
@@ -139,20 +112,25 @@ impl Arena {
139112 self . gc ( ) ;
140113 }
141114
142- /// `gc` releases memory by deallocating ALL of the free pages.
143- pub fn gc ( & mut self ) {
115+ /// Clients are expected roll the stats regularly.
116+ pub fn roll_and_gc ( & mut self ) {
117+ self . stats . roll ( ) ;
118+ self . gc ( ) ;
119+ }
120+
121+ /// `gc` releases memory by some of the free pages.
122+ fn gc ( & mut self ) {
144123 let num_used_pages = self . num_used_pages ( ) ;
145124 let max_used_num_pages_in_last_5_min = self . stats . record_num_used_page ( num_used_pages) ;
146- // We pick a target slightly higher than the maximum number of pages used in the last 5
147- // minutes to avoid needless allocations when we are experience a general increase
125+ // We pick a target slightly higher than the maximum number of pages to avoid needless
126+ // allocations when we are experience a general increase
148127 // in memory usage.
149128 let target_num_pages = max_used_num_pages_in_last_5_min + 10 ;
150129 let num_pages_to_free = self . num_allocated_pages ( ) . saturating_sub ( target_num_pages) ;
151- assert ! ( num_pages_to_free <= self . free_page_ids. len( ) ) ;
152- for _ in 0 ..num_pages_to_free {
153- let page_id = self . free_page_ids . pop ( ) . unwrap ( ) ;
154- self . pages [ page_id. 0 ] = None ;
155- self . free_slots . push ( page_id) ;
130+ let num_free_pages_to_keep = self . free_page_ids . len ( ) - num_pages_to_free;
131+ for free_page_id in self . free_page_ids . drain ( num_free_pages_to_keep..) {
132+ self . pages [ free_page_id. 0 ] = None ;
133+ self . free_slots . push ( free_page_id) ;
156134 }
157135 }
158136
0 commit comments