perf: use async locks

This commit is contained in:
2026-05-30 20:10:11 +02:00
parent fed9d4d8e9
commit 8bee404f80
+28 -23
View File
@@ -2,8 +2,8 @@ use std::{
collections::HashMap,
fs,
io::Write,
sync::{Arc, Mutex, mpsc},
ops::{Deref, DerefMut},
sync::Arc,
};
use axum::{
@@ -19,7 +19,10 @@ use futures::StreamExt as _;
use rand::random_bool;
use serde::{Deserialize, Serialize, de};
use serde_json::json;
use tokio::time::{Duration, sleep};
use tokio::{
sync::{Mutex, mpsc},
time::{Duration, sleep},
};
#[derive(Deserialize, Serialize, Debug, Ord, Eq, PartialEq, PartialOrd, Clone)]
struct Entry {
@@ -62,24 +65,23 @@ async fn main() {
let loscores: Arc<Mutex<Vec<Entry>>> = read_file(PATH_LOSCORES);
let pingscores: Arc<Mutex<HashMap<String, (u64, u32)>>> = read_file(PATH_PINGSCORES);
let (tx, rx) = mpsc::channel::<LeaderboardUpdate>();
let (tx, rx) = mpsc::channel::<LeaderboardUpdate>(1024);
{
let (hiscores, loscores, pingscores) =
(hiscores.clone(), loscores.clone(), pingscores.clone());
tokio::spawn(async move {
handle_hiscores(rx, &hiscores, &loscores, &pingscores);
handle_hiscores(rx, &hiscores, &loscores, &pingscores).await;
});
}
{
let pingscores = pingscores.clone();
tokio::spawn(async move {
loop
// write pingscores every 30s
{
loop {
sleep(Duration::from_millis(30000)).await;
let pingscores = pingscores.lock().unwrap();
let pingscores = pingscores.lock().await;
let file_contents: String = serde_json::to_string(&pingscores.clone()).unwrap();
drop(pingscores);
let mut file = fs::OpenOptions::new()
@@ -119,8 +121,8 @@ async fn leaderboard() -> Html<&'static str> {
Html(include_str!("../leaderboard.html"))
}
// receiver: 0 for hiscore, 1 for loscore, 2 for pingscore
fn handle_hiscores(
rx: mpsc::Receiver<LeaderboardUpdate>,
async fn handle_hiscores(
mut rx: mpsc::Receiver<LeaderboardUpdate>,
hiscores: &Mutex<Vec<Entry>>,
loscores: &Mutex<Vec<Entry>>,
pingscores: &Mutex<HashMap<String, (u64, u32)>>,
@@ -154,7 +156,7 @@ fn handle_hiscores(
}
// Panic galore
let mut hiscores_lock = hiscores.lock().unwrap();
let mut hiscores_lock = hiscores.lock().await;
hiscores_lock.sort();
hiscores_lock.reverse();
let file_contents: String = serde_json::to_string(&hiscores_lock.clone()).unwrap();
@@ -168,24 +170,23 @@ fn handle_hiscores(
drop(file);
loop {
let LeaderboardUpdate { name, update } = rx.recv().expect("channel error");
let LeaderboardUpdate { name, update } = rx.recv().await.expect("channel error");
match update {
LeaderboardUpdateType::Reset { hiscore_pingscore } => {
// Hiscore
update_scoretable(
"hiscore",
hiscores.lock().unwrap(),
hiscores.lock().await,
&name,
hiscore_pingscore,
PATH_HISCORES,
);
// Pingscore
let mut pingscores = pingscores.lock().unwrap();
if hiscore_pingscore > pingscores.get(&*name).unwrap_or(&(0, 0)).1
let mut pingscores = pingscores.lock().await;
// pb
{
if hiscore_pingscore > pingscores.get(&*name).unwrap_or(&(0, 0)).1 {
pingscores.entry(name.to_string()).or_insert((0, 0)).1 = hiscore_pingscore;
println!("{name} new PB: {hiscore_pingscore}");
};
@@ -196,7 +197,7 @@ fn handle_hiscores(
LeaderboardUpdateType::Increment { loscore } => {
update_scoretable(
"loscore",
loscores.lock().unwrap(),
loscores.lock().await,
&name,
loscore,
PATH_LOSCORES,
@@ -229,9 +230,9 @@ async fn handle_socket(
let mut value: u32 = 0;
let msg = {
let hiscores = hiscores.lock().unwrap();
let loscores = loscores.lock().unwrap();
let pingscores = pingscores.lock().unwrap();
let hiscores = hiscores.lock().await;
let loscores = loscores.lock().await;
let pingscores = pingscores.lock().await;
json!({ "hiscores": &*hiscores, "loscores": &*loscores, "pingscores": &*pingscores})
.to_string()
};
@@ -258,12 +259,14 @@ async fn handle_socket(
Ok(Message::Text(_)) => {
if random_bool(CHANCE) {
// reset
let _ = tx.send(LeaderboardUpdate {
let _ = tx
.send(LeaderboardUpdate {
name: name.clone(),
update: LeaderboardUpdateType::Reset {
hiscore_pingscore: value,
},
});
})
.await;
resets += 1;
value = 0
}
@@ -271,10 +274,12 @@ async fn handle_socket(
else {
value += 1;
if prev == 0 {
let _ = tx.send(LeaderboardUpdate {
let _ = tx
.send(LeaderboardUpdate {
name: name.clone(),
update: LeaderboardUpdateType::Increment { loscore: resets },
});
})
.await;
resets = 0;
}
}