From 8e467d5447d5fdcd19e7589d7b3a56fde5b78414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=83=AA=E3=82=AD=E8=90=8C?= Date: Fri, 5 Sep 2025 20:20:45 +0200 Subject: [PATCH] fix chunk images not being populated when the first client joins the room --- crates/rkgk/src/api/wall.rs | 12 +++++++---- crates/rkgk/src/wall/broker.rs | 8 ++++++- crates/rkgk/src/wall/chunk_images.rs | 32 ++++++++++++++++++---------- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/crates/rkgk/src/api/wall.rs b/crates/rkgk/src/api/wall.rs index d069911..16f88b2 100644 --- a/crates/rkgk/src/api/wall.rs +++ b/crates/rkgk/src/api/wall.rs @@ -25,7 +25,7 @@ use tokio::{ select, sync::{mpsc, oneshot}, }; -use tracing::{error, info, info_span, instrument}; +use tracing::{debug, error, info, info_span, instrument}; use crate::{ login::{self, database::LoginStatus}, @@ -370,6 +370,7 @@ impl SessionLoop { top_left, bottom_right, } => { + debug!(?top_left, ?bottom_right, "Request::Viewport"); self.viewport_chunks = ChunkIterator::new(top_left, bottom_right); self.send_chunks(ws).await?; } @@ -391,11 +392,12 @@ impl SessionLoop { // Number of chunks iterated is limited per packet, so as not to let the client // stall the server by sending in a huge viewport. + debug!(?self.viewport_chunks, ?self.sent_chunks); for _ in 0..9000 { if let Some(position) = self.viewport_chunks.next() { - if !self.sent_chunks.insert(position) - || !self.chunk_images.chunk_exists(position) - { + let sent = !self.sent_chunks.insert(position); + if sent || !self.chunk_images.chunk_exists(position) { + debug!(?position, "skipping chunk"); continue; } positions.push(position); @@ -404,6 +406,8 @@ impl SessionLoop { } } + debug!(num = positions.len(), "pending chunk images"); + self.pending_images .extend(self.chunk_images.encoded(positions).await.data); } diff --git a/crates/rkgk/src/wall/broker.rs b/crates/rkgk/src/wall/broker.rs index 96bfe8f..46ad53d 100644 --- a/crates/rkgk/src/wall/broker.rs +++ b/crates/rkgk/src/wall/broker.rs @@ -68,7 +68,13 @@ impl Broker { default_wall_settings: self.settings.default_wall_settings, })?); let wall = Arc::new(Wall::new(*db.wall_settings())); - let chunk_images = Arc::new(ChunkImages::new(Arc::clone(&wall), Arc::clone(&db))); + let chunk_images = Arc::new(ChunkImages::new( + Arc::clone(&wall), + Arc::clone(&db), + // NOTE: Upon initial loading, this will stall until the query finishes. + // This is probably very sub-optimal on walls with a lot of chunks. + ChunkImages::populate(&db).await, + )); let auto_save = Arc::new(AutoSave::new( Arc::clone(&wall), Arc::clone(&chunk_images), diff --git a/crates/rkgk/src/wall/chunk_images.rs b/crates/rkgk/src/wall/chunk_images.rs index 0e73d9b..7b6f31d 100644 --- a/crates/rkgk/src/wall/chunk_images.rs +++ b/crates/rkgk/src/wall/chunk_images.rs @@ -5,10 +5,16 @@ use eyre::Context; use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; use tiny_skia::{IntSize, Pixmap}; use tokio::sync::{mpsc, oneshot, Mutex}; -use tracing::{error, info, instrument}; +use tracing::{debug, error, info, instrument}; use super::{database::ChunkDataPair, Chunk, ChunkPosition, Database, Wall}; +/// Initial population of `ChunkImages`'s cache. +/// Created as part of an async process before `new`. +pub struct Population { + chunks_in_db: DashSet, +} + /// Chunk image encoding, caching, and storage service. pub struct ChunkImages { wall: Arc, @@ -48,13 +54,13 @@ enum Command { } impl ChunkImages { - pub fn new(wall: Arc, db: Arc) -> Self { + pub fn new(wall: Arc, db: Arc, population: Population) -> Self { let (commands_tx, commands_rx) = mpsc::channel(32); let async_loop = Arc::new(ChunkImageLoop { wall: Arc::clone(&wall), db, - chunks_in_db: DashSet::new(), + chunks_in_db: population.chunks_in_db, }); tokio::spawn(Arc::clone(&async_loop).enter(commands_rx)); @@ -65,6 +71,17 @@ impl ChunkImages { } } + pub async fn populate(db: &Database) -> Population { + Population { + chunks_in_db: db + .get_all_chunks() + .await + .expect("could not list chunks in the database") + .into_iter() + .collect(), + } + } + pub async fn encoded(&self, chunks: Vec) -> EncodeResult { let (tx, rx) = oneshot::channel(); _ = self @@ -233,14 +250,7 @@ impl ChunkImageLoop { } async fn enter(self: Arc, mut commands_rx: mpsc::Receiver) { - let all_chunks = self - .db - .get_all_chunks() - .await - .expect("could not list chunks in the database"); - for position in all_chunks { - self.chunks_in_db.insert(position); - } + debug!(num = ?self.chunks_in_db.len(), "chunks in database"); while let Some(command) = commands_rx.recv().await { match command {