brane_drv/
gc.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//  GC.rs
//    by Lut99
//
//  Created:
//    12 Jul 2023, 16:31:40
//  Last edited:
//    13 Jul 2023, 10:26:03
//  Auto updated?
//    Yes
//
//  Description:
//!   Implements a small function that can be used as a "garbage
//!   collector" for `brane-drv` sessions.
//

use std::sync::Weak;
use std::time::{Duration, Instant};

use brane_tsk::spec::AppId;
use dashmap::DashMap;
use log::{debug, info, warn};

use crate::vm::InstanceVm;


/***** CONSTANTS *****/
/// The timeout between garbage collector polls.
const GC_POLL_TIMEOUT: u64 = 3600;

/// The timeout for sessions.
const SESSION_TIMEOUT: u64 = 24 * 3600;





/***** LIBRARY *****/
/// Can be run as a `tokio` background task to periodically clean the list of active sessions.
///
/// Is really quite cancellation-safe.
///
/// # Arguments
/// - `sessions`: The [`DashMap`] of weak sessions. Note that, to avoid memory leaks because its destructor would not be run when this task is cancelled, we assume a [`Weak`] reference.
///
/// # Returns
/// Never, unless the referred `sessions` is free'd.
pub async fn sessions(sessions: Weak<DashMap<AppId, (InstanceVm, Instant)>>) {
    // Loop indefinitely
    debug!("Starting sessions garbage collector");
    loop {
        // Wait indefinitely (like an hour or so)
        tokio::time::sleep(Duration::from_secs(GC_POLL_TIMEOUT)).await;
        debug!("Running sessions garbage collector");

        // Attempt to get the sessions
        // (We assume this gap is small enough not to run into serious memory leaks)
        if let Some(sessions) = sessions.upgrade() {
            // Remove the required things
            sessions.retain(|k, v| {
                // Only keep those with recent enough usage
                if v.1.elapsed() < Duration::from_secs(SESSION_TIMEOUT) {
                    true
                } else {
                    info!(
                        "Removing session '{}' because it has not been used for {} seconds (last use {} seconds ago)",
                        k,
                        SESSION_TIMEOUT,
                        v.1.elapsed().as_secs()
                    );
                    false
                }
            });
        } else {
            warn!("Garbage collector attempted to run after `sessions` has been deallocated; quitting garbage collector");
            break;
        }
    }
}