perf: make daemon more memory efficient

Use Box<str> instead of String in daemon. Because we don't need to
change names of timers in the daemon this is way more memory efficient.
man-page
Moritz Böhme 2023-07-29 10:15:46 +02:00
parent 853e735fcd
commit b3885f80dd
Signed by: moritz
GPG Key ID: 970C6E89EB0547A9
3 changed files with 20 additions and 30 deletions

View File

@ -11,8 +11,8 @@ use std::{
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub enum Command { pub enum Command {
Add(String, Duration), Add(Box<str>, Duration),
Remove(String), Remove(Box<str>),
List, List,
} }
@ -42,12 +42,11 @@ impl Display for Answer {
#[derive(Debug, thiserror::Error, Serialize, Deserialize)] #[derive(Debug, thiserror::Error, Serialize, Deserialize)]
pub enum AnswerErr { pub enum AnswerErr {
#[error("Timer with name '{}' already exists", .0)] #[error("Timer with name '{}' already exists", .0)]
TimerAlreadyExist(String), TimerAlreadyExist(Box<str>),
#[error("No timer with the name '{}' exists", .0)] #[error("No timer with the name '{}' exists", .0)]
NoSuchTimer(String), NoSuchTimer(Box<str>),
} }
pub struct Daemon { pub struct Daemon {
listener: UnixListener, listener: UnixListener,
timers: Vec<Timer>, timers: Vec<Timer>,
@ -68,14 +67,14 @@ impl Daemon {
}) })
} }
fn has_timer(&mut self, name: &String) -> bool { fn has_timer(&mut self, name: &str) -> bool {
self.timers.iter().any(|other| &other.name == name) self.timers.iter().any(|other| other.name.as_ref() == name)
} }
fn handle_command(&mut self, command: Command) -> Result<Answer, AnswerErr> { fn handle_command(&mut self, command: Command) -> Result<Answer, AnswerErr> {
println!("Received command {:?}", command); println!("Received command {:?}", command);
match command { match command {
Command::List => Ok(Answer::Timers(self.timers.to_vec())), Command::List => Ok(Answer::Timers(self.timers.clone())),
Command::Add(name, duration) => { Command::Add(name, duration) => {
if self.has_timer(&name) { if self.has_timer(&name) {
return Err(AnswerErr::TimerAlreadyExist(name)); return Err(AnswerErr::TimerAlreadyExist(name));
@ -88,12 +87,8 @@ impl Daemon {
if !self.has_timer(&name) { if !self.has_timer(&name) {
return Err(AnswerErr::NoSuchTimer(name)); return Err(AnswerErr::NoSuchTimer(name));
} }
self.timers = self self.timers
.timers .retain(|other| other.name.as_ref() != name.as_ref());
.iter()
.cloned()
.filter(|other| other.name != name)
.collect();
Ok(Answer::Ok) Ok(Answer::Ok)
} }
} }
@ -108,18 +103,13 @@ impl Daemon {
} }
fn check_timers(&mut self) { fn check_timers(&mut self) {
self.timers = self self.timers.retain(|timer| {
.timers let expired = timer.is_expired();
.iter() if expired {
.cloned() println!("Timer {} is expired!", timer.name);
.filter(|timer| { }
let expired = timer.is_expired(); !expired
if expired { });
println!("Timer {} is expired!", timer.name);
}
!expired
})
.collect();
} }
pub fn run(&mut self) -> anyhow::Result<()> { pub fn run(&mut self) -> anyhow::Result<()> {

View File

@ -16,9 +16,9 @@ fn main() -> Result<()> {
CliCommand::Add { CliCommand::Add {
name, name,
duration_seconds, duration_seconds,
} => DaemonCommand::Add(name, Duration::from_secs(duration_seconds)), } => DaemonCommand::Add(name.into_boxed_str(), Duration::from_secs(duration_seconds)),
CliCommand::List => DaemonCommand::List, CliCommand::List => DaemonCommand::List,
CliCommand::Remove { name } => DaemonCommand::Remove(name), CliCommand::Remove { name } => DaemonCommand::Remove(name.into_boxed_str()),
}; };
send_command(&args.socket, daemon_command) send_command(&args.socket, daemon_command)
} }

View File

@ -33,7 +33,7 @@ mod approx_instant {
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)] #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct Timer { pub struct Timer {
pub name: String, pub name: Box<str>,
#[serde(with = "approx_instant")] #[serde(with = "approx_instant")]
start: Instant, start: Instant,
duration: Duration, duration: Duration,
@ -51,7 +51,7 @@ impl Display for Timer {
} }
impl Timer { impl Timer {
pub fn new(name: String, duration: Duration) -> Timer { pub fn new(name: Box<str>, duration: Duration) -> Timer {
Timer { Timer {
name, name,
start: Instant::now(), start: Instant::now(),