Skip to content

Commit 42ec47a

Browse files
committed
roll is done externally
1 parent bdd759f commit 42ec47a

3 files changed

Lines changed: 29 additions & 35 deletions

File tree

src/mem/arena.rs

Lines changed: 20 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1+
use std::sync::atomic::AtomicUsize;
2+
use std::sync::atomic::Ordering;
13
use std::time::Duration;
2-
#[cfg(not(test))]
3-
use std::time::Instant;
4-
5-
#[cfg(test)]
6-
use mock_instant::Instant;
74

85
/// 256 KiB.
96
#[cfg(not(test))]
@@ -54,49 +51,34 @@ pub struct Arena {
5451
// Pitfall: If pages are requests way less often than 256 times per minutes,
5552
// this arena may take way too much time to release its memory.
5653
struct ArenaStats {
57-
max_num_used_pages_former: usize,
58-
max_num_used_pages_current: usize,
59-
call_counter: u8,
60-
next_window_start: Instant,
54+
max_num_used_pages_former: AtomicUsize,
55+
max_num_used_pages_current: AtomicUsize,
6156
}
6257

63-
const WINDOW: Duration = Duration::from_secs(60);
64-
6558
impl Default for ArenaStats {
6659
fn default() -> ArenaStats {
6760
ArenaStats {
6861
// We arbitrarily initialize num used pages former to 100.
69-
max_num_used_pages_former: 0,
70-
max_num_used_pages_current: 0,
71-
call_counter: 0u8,
72-
next_window_start: Instant::now(),
62+
max_num_used_pages_former: AtomicUsize::new(0),
63+
max_num_used_pages_current: AtomicUsize::new(0),
7364
}
7465
}
7566
}
7667

7768
impl ArenaStats {
7869
/// This method happens when we are changing time window.
79-
fn roll(&mut self, now: Instant) {
80-
self.max_num_used_pages_former = self.max_num_used_pages_current;
81-
self.max_num_used_pages_current = 0;
82-
self.next_window_start = now + WINDOW;
70+
fn roll(&mut self,) {
71+
let max_num_used_page_former = self.max_num_used_pages_current.load(Ordering::Relaxed);
72+
self.max_num_used_pages_former.store(max_num_used_page_former, Ordering::Relaxed);
73+
self.max_num_used_pages_current.store(0, Ordering::Relaxed);
8374
}
8475

8576
/// Records the number of used pages, and returns an estimation of the maximum number of pages
8677
/// in the last 5 minutes.
8778
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-
}
97-
self.max_num_used_pages_current = self.max_num_used_pages_current.max(num_used_pages);
98-
self.max_num_used_pages_former
99-
.max(self.max_num_used_pages_current)
79+
let max_num_used_pages = self.max_num_used_pages_current.load(Ordering::Relaxed).max(num_used_pages);
80+
self.max_num_used_pages_current.store(max_num_used_pages, Ordering::Relaxed);
81+
self.max_num_used_pages_former.load(Ordering::Relaxed).max(max_num_used_pages)
10082
}
10183
}
10284

@@ -105,20 +87,17 @@ impl Arena {
10587
pub fn acquire_page(&mut self) -> PageId {
10688
if let Some(page_id) = self.free_page_ids.pop() {
10789
assert!(self.pages[page_id.0].is_some());
108-
self.gc();
10990
return page_id;
11091
}
11192
let page: Page = vec![0u8; PAGE_SIZE].into_boxed_slice();
11293
if let Some(free_slot) = self.free_slots.pop() {
11394
let slot = &mut self.pages[free_slot.0];
11495
assert!(slot.is_none());
11596
*slot = Some(page);
116-
self.gc();
11797
free_slot
11898
} else {
11999
let new_page_id = self.pages.len();
120100
self.pages.push(Some(page));
121-
self.gc();
122101
PageId(new_page_id)
123102
}
124103
}
@@ -139,7 +118,13 @@ impl Arena {
139118
self.gc();
140119
}
141120

142-
/// `gc` releases memory by deallocating ALL of the free pages.
121+
/// Clients are expected roll the stats regularly.
122+
pub fn roll(&mut self,) {
123+
self.stats.roll();
124+
self.gc();
125+
}
126+
127+
/// `gc` releases memory by some of the free pages.
143128
pub fn gc(&mut self) {
144129
let num_used_pages = self.num_used_pages();
145130
let max_used_num_pages_in_last_5_min = self.stats.record_num_used_page(num_used_pages);

src/mem/queues.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ 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();
165+
self.arena.gc();
166+
}
167+
163168
/// Return a tuple of (size, capacity) of memory used by the memqueues
164169
pub fn size(&self) -> (usize, usize) {
165170
let size = self

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)