2022-02-25 18:20:15 -08:00
|
|
|
use log::{error, info};
|
|
|
|
|
use once_cell::sync::OnceCell;
|
2022-02-14 10:00:55 -08:00
|
|
|
use statsd::Client;
|
2022-02-21 17:28:50 -08:00
|
|
|
/// Events collector and publisher.
|
2022-02-14 10:00:55 -08:00
|
|
|
use tokio::sync::mpsc::{Receiver, Sender};
|
|
|
|
|
|
|
|
|
|
use std::collections::HashMap;
|
2022-02-25 18:20:15 -08:00
|
|
|
use std::sync::{Arc, Mutex};
|
2022-02-14 10:00:55 -08:00
|
|
|
|
2022-02-19 13:57:35 -08:00
|
|
|
use crate::config::get_config;
|
|
|
|
|
|
2022-02-25 18:20:15 -08:00
|
|
|
static LATEST_STATS: OnceCell<Arc<Mutex<HashMap<String, i64>>>> = OnceCell::new();
|
|
|
|
|
|
2022-02-20 12:40:09 -08:00
|
|
|
#[derive(Debug, Clone, Copy)]
|
2022-02-21 17:28:50 -08:00
|
|
|
enum EventName {
|
2022-02-14 10:00:55 -08:00
|
|
|
CheckoutTime,
|
2022-02-21 17:28:50 -08:00
|
|
|
Query,
|
|
|
|
|
Transaction,
|
2022-02-14 10:00:55 -08:00
|
|
|
DataSent,
|
|
|
|
|
DataReceived,
|
2022-02-20 12:40:09 -08:00
|
|
|
ClientWaiting,
|
|
|
|
|
ClientActive,
|
|
|
|
|
ClientIdle,
|
|
|
|
|
ClientDisconnecting,
|
2022-02-20 22:47:08 -08:00
|
|
|
ServerActive,
|
|
|
|
|
ServerIdle,
|
|
|
|
|
ServerTested,
|
|
|
|
|
ServerLogin,
|
|
|
|
|
ServerDisconnecting,
|
2022-02-22 18:10:30 -08:00
|
|
|
FlushStatsToStatsD,
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2022-02-21 17:28:50 -08:00
|
|
|
pub struct Event {
|
|
|
|
|
name: EventName,
|
|
|
|
|
value: i64,
|
|
|
|
|
process_id: Option<i32>,
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
|
pub struct Reporter {
|
2022-02-21 17:28:50 -08:00
|
|
|
tx: Sender<Event>,
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Reporter {
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn new(tx: Sender<Event>) -> Reporter {
|
2022-02-14 10:00:55 -08:00
|
|
|
Reporter { tx: tx }
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn query(&self) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::Query,
|
2022-02-14 10:00:55 -08:00
|
|
|
value: 1,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: None,
|
2022-02-14 10:00:55 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn transaction(&self) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::Transaction,
|
2022-02-14 10:00:55 -08:00
|
|
|
value: 1,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: None,
|
2022-02-14 10:00:55 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn data_sent(&self, amount: usize) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::DataSent,
|
2022-02-14 10:00:55 -08:00
|
|
|
value: amount as i64,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: None,
|
2022-02-14 10:00:55 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn data_received(&self, amount: usize) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::DataReceived,
|
2022-02-14 10:00:55 -08:00
|
|
|
value: amount as i64,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: None,
|
2022-02-14 10:00:55 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn checkout_time(&self, ms: u128) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::CheckoutTime,
|
2022-02-14 10:00:55 -08:00
|
|
|
value: ms as i64,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: None,
|
2022-02-14 10:00:55 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
2022-02-15 08:18:01 -08:00
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn client_waiting(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ClientWaiting,
|
2022-02-15 08:18:01 -08:00
|
|
|
value: 1,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: Some(process_id),
|
2022-02-15 08:18:01 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-15 08:18:01 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn client_active(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ClientActive,
|
2022-02-15 08:18:01 -08:00
|
|
|
value: 1,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: Some(process_id),
|
2022-02-15 08:18:01 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-15 08:18:01 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn client_idle(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ClientIdle,
|
2022-02-20 12:40:09 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
2022-02-15 08:18:01 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 12:40:09 -08:00
|
|
|
}
|
2022-02-15 08:18:01 -08:00
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn client_disconnecting(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ClientDisconnecting,
|
2022-02-15 08:18:01 -08:00
|
|
|
value: 1,
|
2022-02-20 12:40:09 -08:00
|
|
|
process_id: Some(process_id),
|
2022-02-15 08:18:01 -08:00
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-15 08:18:01 -08:00
|
|
|
}
|
2022-02-20 22:47:08 -08:00
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn server_active(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ServerActive,
|
2022-02-20 22:47:08 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 22:47:08 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn server_idle(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ServerIdle,
|
2022-02-20 22:47:08 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 22:47:08 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn server_login(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ServerLogin,
|
2022-02-20 22:47:08 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 22:47:08 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn server_tested(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ServerTested,
|
2022-02-20 22:47:08 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 22:47:08 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
pub fn server_disconnecting(&self, process_id: i32) {
|
2022-02-22 18:10:30 -08:00
|
|
|
let event = Event {
|
2022-02-21 17:28:50 -08:00
|
|
|
name: EventName::ServerDisconnecting,
|
2022-02-20 22:47:08 -08:00
|
|
|
value: 1,
|
|
|
|
|
process_id: Some(process_id),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let _ = self.tx.try_send(event);
|
2022-02-20 22:47:08 -08:00
|
|
|
}
|
2022-02-22 18:10:30 -08:00
|
|
|
|
|
|
|
|
// pub fn flush_to_statsd(&self) {
|
|
|
|
|
// let event = Event {
|
|
|
|
|
// name: EventName::FlushStatsToStatsD,
|
|
|
|
|
// value: 0,
|
|
|
|
|
// process_id: None,
|
|
|
|
|
// };
|
|
|
|
|
|
|
|
|
|
// let _ = self.tx.try_send(event);
|
|
|
|
|
// }
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Collector {
|
2022-02-21 17:28:50 -08:00
|
|
|
rx: Receiver<Event>,
|
2022-02-22 18:10:30 -08:00
|
|
|
tx: Sender<Event>,
|
2022-02-14 10:00:55 -08:00
|
|
|
client: Client,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Collector {
|
2022-02-22 18:10:30 -08:00
|
|
|
pub fn new(rx: Receiver<Event>, tx: Sender<Event>) -> Collector {
|
2022-02-14 10:00:55 -08:00
|
|
|
Collector {
|
2022-02-22 18:10:30 -08:00
|
|
|
rx,
|
|
|
|
|
tx,
|
2022-02-19 13:57:35 -08:00
|
|
|
client: Client::new(&get_config().general.statsd_address, "pgcat").unwrap(),
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn collect(&mut self) {
|
2022-02-21 17:28:50 -08:00
|
|
|
info!("Events reporter started");
|
2022-02-20 22:47:08 -08:00
|
|
|
|
2022-02-25 18:20:15 -08:00
|
|
|
match LATEST_STATS.set(Arc::new(Mutex::new(HashMap::new()))) {
|
|
|
|
|
Ok(_) => (),
|
|
|
|
|
Err(_) => {
|
|
|
|
|
error!("Latest stats will not be available");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-14 10:00:55 -08:00
|
|
|
let mut stats = HashMap::from([
|
2022-02-15 08:18:01 -08:00
|
|
|
("total_query_count", 0),
|
|
|
|
|
("total_xact_count", 0),
|
|
|
|
|
("total_sent", 0),
|
|
|
|
|
("total_received", 0),
|
|
|
|
|
("total_wait_time", 0),
|
|
|
|
|
("maxwait_us", 0),
|
|
|
|
|
("maxwait", 0),
|
|
|
|
|
("cl_waiting", 0),
|
|
|
|
|
("cl_active", 0),
|
|
|
|
|
("cl_idle", 0),
|
2022-02-20 22:47:08 -08:00
|
|
|
("sv_idle", 0),
|
|
|
|
|
("sv_active", 0),
|
|
|
|
|
("sv_login", 0),
|
|
|
|
|
("sv_tested", 0),
|
2022-02-14 10:00:55 -08:00
|
|
|
]);
|
2022-02-15 08:18:01 -08:00
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
let mut client_server_states: HashMap<i32, EventName> = HashMap::new();
|
2022-02-22 18:10:30 -08:00
|
|
|
let tx = self.tx.clone();
|
|
|
|
|
|
|
|
|
|
tokio::task::spawn(async move {
|
|
|
|
|
let mut interval = tokio::time::interval(tokio::time::Duration::from_millis(15000));
|
|
|
|
|
loop {
|
|
|
|
|
interval.tick().await;
|
|
|
|
|
let _ = tx.try_send(Event {
|
|
|
|
|
name: EventName::FlushStatsToStatsD,
|
|
|
|
|
value: 0,
|
|
|
|
|
process_id: None,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-02-14 10:00:55 -08:00
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
let stat = match self.rx.recv().await {
|
|
|
|
|
Some(stat) => stat,
|
|
|
|
|
None => {
|
2022-02-21 17:28:50 -08:00
|
|
|
info!("Events collector is shutting down");
|
2022-02-14 10:00:55 -08:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Some are counters, some are gauges...
|
|
|
|
|
match stat.name {
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::Query => {
|
2022-02-15 08:18:01 -08:00
|
|
|
let counter = stats.entry("total_query_count").or_insert(0);
|
2022-02-14 10:00:55 -08:00
|
|
|
*counter += stat.value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::Transaction => {
|
2022-02-15 08:18:01 -08:00
|
|
|
let counter = stats.entry("total_xact_count").or_insert(0);
|
2022-02-14 10:00:55 -08:00
|
|
|
*counter += stat.value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::DataSent => {
|
2022-02-15 08:18:01 -08:00
|
|
|
let counter = stats.entry("total_sent").or_insert(0);
|
2022-02-14 10:00:55 -08:00
|
|
|
*counter += stat.value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::DataReceived => {
|
2022-02-15 08:18:01 -08:00
|
|
|
let counter = stats.entry("total_received").or_insert(0);
|
2022-02-14 10:00:55 -08:00
|
|
|
*counter += stat.value;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::CheckoutTime => {
|
2022-02-15 08:18:01 -08:00
|
|
|
let counter = stats.entry("total_wait_time").or_insert(0);
|
|
|
|
|
*counter += stat.value;
|
|
|
|
|
|
|
|
|
|
let counter = stats.entry("maxwait_us").or_insert(0);
|
2022-02-14 10:00:55 -08:00
|
|
|
|
|
|
|
|
// Report max time here
|
|
|
|
|
if stat.value > *counter {
|
|
|
|
|
*counter = stat.value;
|
|
|
|
|
}
|
2022-02-15 08:18:01 -08:00
|
|
|
|
|
|
|
|
let counter = stats.entry("maxwait").or_insert(0);
|
|
|
|
|
let seconds = *counter / 1_000_000;
|
|
|
|
|
|
|
|
|
|
if seconds > *counter {
|
|
|
|
|
*counter = seconds;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::ClientActive
|
|
|
|
|
| EventName::ClientWaiting
|
|
|
|
|
| EventName::ClientIdle
|
|
|
|
|
| EventName::ServerActive
|
|
|
|
|
| EventName::ServerIdle
|
|
|
|
|
| EventName::ServerTested
|
|
|
|
|
| EventName::ServerLogin => {
|
2022-02-20 22:47:08 -08:00
|
|
|
client_server_states.insert(stat.process_id.unwrap(), stat.name);
|
2022-02-15 08:18:01 -08:00
|
|
|
}
|
|
|
|
|
|
2022-02-21 17:28:50 -08:00
|
|
|
EventName::ClientDisconnecting | EventName::ServerDisconnecting => {
|
2022-02-20 22:47:08 -08:00
|
|
|
client_server_states.remove(&stat.process_id.unwrap());
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
2022-02-20 12:40:09 -08:00
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
EventName::FlushStatsToStatsD => {
|
|
|
|
|
for (_, state) in &client_server_states {
|
|
|
|
|
match state {
|
|
|
|
|
EventName::ClientActive => {
|
|
|
|
|
let counter = stats.entry("cl_active").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ClientWaiting => {
|
|
|
|
|
let counter = stats.entry("cl_waiting").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ClientIdle => {
|
|
|
|
|
let counter = stats.entry("cl_idle").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ServerIdle => {
|
|
|
|
|
let counter = stats.entry("sv_idle").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ServerActive => {
|
|
|
|
|
let counter = stats.entry("sv_active").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ServerTested => {
|
|
|
|
|
let counter = stats.entry("sv_tested").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventName::ServerLogin => {
|
|
|
|
|
let counter = stats.entry("sv_login").or_insert(0);
|
|
|
|
|
*counter += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ => unreachable!(),
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-02-14 10:00:55 -08:00
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
info!("{:?}", stats);
|
2022-02-14 10:00:55 -08:00
|
|
|
|
2022-02-25 18:20:15 -08:00
|
|
|
match LATEST_STATS.get() {
|
|
|
|
|
Some(arc) => {
|
|
|
|
|
let mut guard = arc.lock().unwrap();
|
|
|
|
|
for (key, value) in &stats {
|
|
|
|
|
guard.insert(key.to_string(), value.clone());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None => (),
|
|
|
|
|
};
|
|
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
let mut pipeline = self.client.pipeline();
|
2022-02-14 10:00:55 -08:00
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
for (key, value) in stats.iter_mut() {
|
|
|
|
|
pipeline.gauge(key, *value as f64);
|
|
|
|
|
*value = 0;
|
|
|
|
|
}
|
2022-02-14 10:00:55 -08:00
|
|
|
|
2022-02-22 18:10:30 -08:00
|
|
|
pipeline.send(&self.client);
|
|
|
|
|
}
|
|
|
|
|
};
|
2022-02-14 10:00:55 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-25 18:20:15 -08:00
|
|
|
|
|
|
|
|
pub fn get_stats() -> Option<HashMap<String, i64>> {
|
|
|
|
|
match LATEST_STATS.get() {
|
|
|
|
|
Some(arc) => {
|
|
|
|
|
let guard = arc.lock().unwrap();
|
|
|
|
|
Some(guard.clone())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
None => None,
|
|
|
|
|
}
|
|
|
|
|
}
|