Skip to content

Commit 94b7b87

Browse files
committed
roll is done externally
1 parent bdd759f commit 94b7b87

4 files changed

Lines changed: 25 additions & 38 deletions

File tree

src/mem/arena.rs

Lines changed: 15 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
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))]
103
pub const PAGE_SIZE: usize = 1 << 18;
@@ -56,44 +49,27 @@ pub struct Arena {
5649
struct 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-
6554
impl 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

7763
impl 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

src/mem/queues.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,10 @@ impl MemQueues {
160160
Some(queue.truncate_up_to_included(position, &mut self.arena))
161161
}
162162

163+
pub fn roll_and_gc(&mut self) {
164+
self.arena.roll_and_gc();
165+
}
166+
163167
/// Return a tuple of (size, capacity) of memory used by the memqueues
164168
pub fn size(&self) -> (usize, usize) {
165169
let size = self

src/mem/rolling_buffer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ impl<'a> PagesBuf<'a> {
176176
std::borrow::Cow::Owned(buf)
177177
}
178178

179-
// Contrary to Buf::chunk, this method returns a slice with a `'a` lifetime (so it can outlive 'self).
179+
// Contrary to Buf::chunk, this method returns a slice with a `'a` lifetime (so it can outlive
180+
// 'self).
180181
fn chunk_with_lifetime(&self) -> &'a [u8] {
181182
let Some(first_page_id) = self.page_ids.first().copied() else {
182183
return &[];

src/multi_record_log.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ impl MultiRecordLog {
293293
Ok(removed_count)
294294
}
295295

296+
pub fn memory_gc(&mut self) {
297+
self.in_mem_queues.roll_and_gc();
298+
}
299+
296300
fn run_gc_if_necessary(&mut self) -> io::Result<()> {
297301
debug!("run_gc_if_necessary");
298302
if self

0 commit comments

Comments
 (0)