Skip to main content

level_runtime/
builder.rs

1use std::sync::atomic::AtomicUsize;
2
3use crate::{runtime::LevelRuntime, worker::LevelWorker};
4
5/// A setup builder for your level runtime.
6///
7/// See `tokio::runtime::Builder` for more detailed documentation.
8/// A level runtime is a collection of tokio current-thread runtimes.
9pub struct Builder {
10    builder: tokio::runtime::Builder,
11    worker_threads: usize,
12    thread_name: std::sync::Arc<dyn Fn() -> String + Send + Sync + 'static>,
13}
14
15impl Default for Builder {
16    fn default() -> Self {
17        Self {
18            worker_threads: 1,
19            builder: tokio::runtime::Builder::new_current_thread(),
20            thread_name: std::sync::Arc::new(|| {
21                static I: AtomicUsize = AtomicUsize::new(0);
22                let i = I.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
23                format!("level-{i:02}")
24            }),
25        }
26    }
27}
28
29impl Builder {
30    /// Build a new level runtime
31    pub fn build(&mut self) -> LevelRuntime {
32        LevelRuntime::from_workers(
33            self.thread_name.clone(),
34            (0..self.worker_threads)
35                .map(|_i| {
36                    self.builder
37                        .build()
38                        .expect("must be able to build tokio runtime")
39                })
40                .map(LevelWorker::from_runtime)
41                .collect(),
42        )
43    }
44
45    /// How many thread-local worker threads do you want?
46    pub fn worker_threads(&mut self, threads: usize) -> &mut Self {
47        self.worker_threads = threads;
48        self
49    }
50
51    /// Set a thread name prefix for level threads.
52    pub fn thread_name_prefix(&mut self, name: impl Into<String>) -> &mut Self {
53        let mut name = name.into();
54        if 12 < name.len() {
55            name.truncate(12);
56            // htop and other unix tools can see the indices. They traditionally
57            // can only handle 16 byte C strings. The 16th byte is \0, so 15
58            // characters is the limit. -01 takes 3 characters, so you get 12 to
59            // name your prefix. (if you are using 100+ threads, please feel free
60            // to pr)
61            log::warn!("truncating thread name prefix to 12 characters: {name}")
62        }
63        let name_i: AtomicUsize = AtomicUsize::new(0);
64        self.thread_name = std::sync::Arc::new(move || {
65            let i = name_i.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
66            format!("{name}-{i:02}")
67        });
68        self
69    }
70
71    /// Do you want to use IO and time?
72    pub fn enable_all(&mut self) -> &mut Self {
73        self.builder.enable_all();
74        self
75    }
76
77    /// How frequently should you epoll? (Default is 61)
78    pub fn event_interval(&mut self, interval: u32) -> &mut Self {
79        self.builder.event_interval(interval);
80        self
81    }
82
83    /// How frequently should you check for off-runtime task submission? (Default is 31)
84    pub fn global_queue_interval(&mut self, interval: u32) -> &mut Self {
85        self.builder.global_queue_interval(interval);
86        self
87    }
88
89    /// How many file descriptors should you epoll at a time? (Default is 1024)
90    pub fn max_io_events_per_tick(&mut self, capacity: usize) -> &mut Self {
91        self.builder.max_io_events_per_tick(capacity);
92        self
93    }
94
95    /// How many blocking threads should each local runtime be able to create? (Devault is 512)
96    pub fn max_blocking_threads(&mut self, capacity: usize) -> &mut Self {
97        self.builder.max_blocking_threads(capacity);
98        self
99    }
100
101    /// Notification of thread park
102    pub fn on_thread_park(&mut self, f: impl Fn() + Send + Sync + 'static) -> &mut Self {
103        self.builder.on_thread_park(f);
104        self
105    }
106
107    /// Notification of thread unpark
108    pub fn on_thread_unpark(&mut self, f: impl Fn() + Send + Sync + 'static) -> &mut Self {
109        self.builder.on_thread_unpark(f);
110        self
111    }
112}