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)]
35pub(super) fn acquire(server: &Server) -> Result<Arc<Self>> {
36 let mut slot = ENV.lock().expect("environment slot locked");
37
38 if let Some(env) = slot.upgrade() {
39 return Ok(env);
40 }
41
42 let config = &server.config;
43 let mut env = rocksdb::Env::new().or_else(or_else)?;
44
45 if config.rocksdb_compaction_prio_idle {
46 env.lower_thread_pool_cpu_priority();
47 }
48
49 if config.rocksdb_compaction_ioprio_idle {
50 env.lower_thread_pool_io_priority();
51 }
52
53 let env = Arc::new(Self(env.into()));
54 *slot = Arc::downgrade(&env);
55
56 Ok(env)
57}
58
59#[implement(Env)]
60#[inline]
61pub(super) fn lock(&self) -> LockResult<MutexGuard<'_, rocksdb::Env>> { self.0.lock() }
62
63impl Drop for Env {
64 #[cold]
65 fn drop(&mut self) {
66 let mut slot = ENV.lock().expect("environment slot locked");
67
68 if !ptr_eq(slot.as_ptr(), self) {
71 return;
72 }
73
74 *slot = Weak::new();
75
76 let env = self
77 .0
78 .get_mut()
79 .unwrap_or_else(PoisonError::into_inner);
80
81 debug!("Shutting down background threads");
82 env.set_high_priority_background_threads(0);
83 env.set_low_priority_background_threads(0);
84 env.set_bottom_priority_background_threads(0);
85 env.set_background_threads(0);
86
87 debug!("Joining background threads...");
88 env.join_all_threads();
89 }
90}