tuwunel_database/engine/
env.rs1use std::{
2 ptr::eq as ptr_eq,
3 sync::{Arc, LockResult, Mutex, MutexGuard, PoisonError, Weak},
4};
5
6use tuwunel_core::{Result, Server, debug, implement};
7
8use crate::or_else;
9
10pub(super) struct Env(Mutex<rocksdb::Env>);
17
18static ENV: Mutex<Weak<Env>> = Mutex::new(Weak::new());
26
27#[implement(Env)]
33pub(super) fn acquire(server: &Server) -> Result<Arc<Self>> {
34 Self::acquire_with_priorities(
35 server.config.rocksdb_compaction_prio_idle,
36 server.config.rocksdb_compaction_ioprio_idle,
37 )
38}
39
40#[implement(Env)]
45pub(super) fn acquire_with_priorities(cpu_idle: bool, io_idle: bool) -> Result<Arc<Self>> {
46 let mut slot = ENV.lock().expect("environment slot locked");
47
48 if let Some(env) = slot.upgrade() {
49 return Ok(env);
50 }
51
52 let mut env = rocksdb::Env::new().or_else(or_else)?;
53
54 if cpu_idle {
55 env.lower_thread_pool_cpu_priority();
56 }
57
58 if io_idle {
59 env.lower_thread_pool_io_priority();
60 }
61
62 let env = Arc::new(Self(env.into()));
63 *slot = Arc::downgrade(&env);
64
65 Ok(env)
66}
67
68#[implement(Env)]
69#[inline]
70pub(super) fn lock(&self) -> LockResult<MutexGuard<'_, rocksdb::Env>> { self.0.lock() }
71
72impl Drop for Env {
73 #[cold]
74 fn drop(&mut self) {
75 let mut slot = ENV.lock().expect("environment slot locked");
76
77 if !ptr_eq(slot.as_ptr(), self) {
80 return;
81 }
82
83 *slot = Weak::new();
84
85 let env = self
86 .0
87 .get_mut()
88 .unwrap_or_else(PoisonError::into_inner);
89
90 debug!("Shutting down background threads");
91 env.set_high_priority_background_threads(0);
92 env.set_low_priority_background_threads(0);
93 env.set_bottom_priority_background_threads(0);
94 env.set_background_threads(0);
95
96 debug!("Joining background threads...");
97 env.join_all_threads();
98 }
99}