Skip to content

Commit 8d62033

Browse files
authored
perf: prepare maps concurrently (#966)
1 parent fa098d7 commit 8d62033

File tree

1 file changed

+23
-26
lines changed

1 file changed

+23
-26
lines changed

bathbot/src/manager/osu_map.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use bathbot_client::ClientError;
44
use bathbot_psql::model::osu::{ArtistTitle, DbBeatmap, DbBeatmapset, DbMapContent, MapVersion};
55
use bathbot_util::{ExponentialBackoff, IntHasher};
66
use eyre::{ContextCompat, Report, WrapErr};
7+
use futures::{TryStreamExt, stream::FuturesUnordered};
78
use rosu_pp::{
89
Beatmap,
910
any::DifficultyAttributes,
@@ -117,34 +118,30 @@ impl MapManager {
117118
.await
118119
.wrap_err("Failed to get maps")?;
119120

120-
let iter = maps_id_checksum
121+
maps_id_checksum
121122
.keys()
122-
.map(|map_id| (*map_id as u32, db_maps.remove(map_id)));
123-
124-
let mut maps = HashMap::with_capacity_and_hasher(maps_id_checksum.len(), IntHasher);
125-
126-
// Having this non-async is pretty sad but the many I/O operations appear
127-
// to cause thread-limitation issues when collected into a FuturesUnordered.
128-
for (map_id, map_opt) in iter {
129-
let map = if let Some((map, mapset, filename)) = map_opt {
130-
let (pp_map, map_opt) = self.prepare_map(map_id, filename).await?;
131-
132-
match map_opt {
133-
Some(map) => OsuMap::new(map, pp_map),
134-
None => OsuMap::new(OsuMapSlim::new(map, mapset), pp_map),
135-
}
136-
} else {
137-
let map_fut = self.retrieve_map(map_id);
138-
let prepare_fut = self.prepare_map(map_id, DbMapContent::Missing);
139-
let (map, (pp_map, _)) = tokio::try_join!(map_fut, prepare_fut)?;
140-
141-
OsuMap::new(map, pp_map)
142-
};
123+
.map(|map_id| (*map_id as u32, db_maps.remove(map_id)))
124+
.map(|(map_id, map_opt)| async move {
125+
let map = if let Some((map, mapset, filepath)) = map_opt {
126+
let (pp_map, map_opt) = self.prepare_map(map_id, filepath).await?;
127+
128+
match map_opt {
129+
Some(map) => OsuMap::new(map, pp_map),
130+
None => OsuMap::new(OsuMapSlim::new(map, mapset), pp_map),
131+
}
132+
} else {
133+
let map_fut = self.retrieve_map(map_id);
134+
let prepare_fut = self.prepare_map(map_id, DbMapContent::Missing);
135+
let (map, (pp_map, _)) = tokio::try_join!(map_fut, prepare_fut)?;
143136

144-
maps.insert(map_id, map);
145-
}
137+
OsuMap::new(map, pp_map)
138+
};
146139

147-
Ok(maps)
140+
Ok((map_id, map))
141+
})
142+
.collect::<FuturesUnordered<_>>()
143+
.try_collect()
144+
.await
148145
}
149146

150147
pub async fn artist_title(self, mapset_id: u32) -> Result<ArtistTitle> {
@@ -346,7 +343,7 @@ impl MapManager {
346343
let db_fut = Context::psql().insert_beatmap_file_content(map_id, &bytes);
347344

348345
if let Err(err) = db_fut.await {
349-
warn!(?err, "Failed to insert map file");
346+
warn!(map_id, ?err, "Failed to insert file content");
350347
} else {
351348
info!("Downloaded {map_id}.osu successfully");
352349
}

0 commit comments

Comments
 (0)