mmap_io/flush.rs
1#![allow(dead_code)]
2//! Flush policy configuration for MemoryMappedFile.
3//!
4//! Controls when writes to a RW mapping should be flushed to disk.
5
6use parking_lot::RwLock;
7use std::sync::Arc;
8use std::thread;
9use std::time::{Duration, Instant};
10
11/// Policy controlling when to flush dirty pages to disk.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
13pub enum FlushPolicy {
14 /// Never flush implicitly; flush() must be called by the user.
15 #[default]
16 Never,
17 /// Alias of Never for semantic clarity when using the builder API.
18 Manual,
19 /// Flush after every write/update_region call.
20 Always,
21 /// Flush when at least N bytes have been written since the last flush.
22 EveryBytes(usize),
23 /// Flush after every W writes (calls to update_region).
24 EveryWrites(usize),
25 /// Flush automatically every N milliseconds when there are pending writes.
26 EveryMillis(u64),
27}
28
29/// Time-based flush manager that handles automatic flushing at regular intervals.
30/// This is used internally when FlushPolicy::EveryMillis is configured.
31pub struct TimeBasedFlusher {
32 interval: Duration,
33 last_flush: Arc<RwLock<Option<Instant>>>,
34 _handle: Option<thread::JoinHandle<()>>,
35}
36
37impl TimeBasedFlusher {
38 /// Create a new time-based flusher with the given interval.
39 /// Returns None if interval_ms is 0.
40 pub fn new<F>(interval_ms: u64, flush_callback: F) -> Option<Self>
41 where
42 F: Fn() -> bool + Send + 'static,
43 {
44 if interval_ms == 0 {
45 return None;
46 }
47
48 let interval = Duration::from_millis(interval_ms);
49 let last_flush = Arc::new(RwLock::new(Some(Instant::now())));
50 let last_flush_clone = Arc::clone(&last_flush);
51
52 let handle = thread::spawn(move || {
53 loop {
54 thread::sleep(interval);
55
56 // Check if we should flush
57 let should_flush = {
58 let last = last_flush_clone.read();
59 if let Some(last_time) = *last {
60 last_time.elapsed() >= interval
61 } else {
62 false
63 }
64 };
65
66 if should_flush {
67 // Attempt flush via callback
68 let flushed = flush_callback();
69 if flushed {
70 // Update last flush time
71 *last_flush_clone.write() = Some(Instant::now());
72 }
73 }
74 }
75 });
76
77 Some(Self {
78 interval,
79 last_flush,
80 _handle: Some(handle),
81 })
82 }
83
84 /// Manually trigger an immediate flush and update the last flush time.
85 pub fn manual_flush(&self) {
86 *self.last_flush.write() = Some(Instant::now());
87 }
88
89 /// Check if it's time for a flush based on the interval.
90 pub fn should_flush(&self) -> bool {
91 let last = self.last_flush.read();
92 if let Some(last_time) = *last {
93 last_time.elapsed() >= self.interval
94 } else {
95 true // First flush
96 }
97 }
98}
99
100impl Drop for TimeBasedFlusher {
101 fn drop(&mut self) {
102 // The background thread will naturally exit when the handle is dropped
103 // We don't join here to avoid blocking the drop
104 }
105}