Skip to content

Commit 775cdc0

Browse files
authored
Merge pull request #32273 from bdach/star-rating-updates-without-online-hits
Ensure that star rating reprocessing does not incur online lookup requests
2 parents 6c8b84f + 6b1472b commit 775cdc0

File tree

1 file changed

+87
-13
lines changed

1 file changed

+87
-13
lines changed

osu.Game/Database/BackgroundDataStoreProcessor.cs

+87-13
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ protected override void LoadComplete()
7676
{
7777
Logger.Log("Beginning background data store processing..");
7878

79-
checkForOutdatedStarRatings();
80-
processBeatmapSetsWithMissingMetrics();
79+
clearOutdatedStarRatings();
80+
populateMissingStarRatings();
81+
processOnlineBeatmapSetsWithNoUpdate();
8182
// Note that the previous method will also update these on a fresh run.
8283
processBeatmapsWithMissingObjectCounts();
8384
processScoresWithMissingStatistics();
@@ -100,7 +101,7 @@ protected override void LoadComplete()
100101
/// Check whether the databased difficulty calculation version matches the latest ruleset provided version.
101102
/// If it doesn't, clear out any existing difficulties so they can be incrementally recalculated.
102103
/// </summary>
103-
private void checkForOutdatedStarRatings()
104+
private void clearOutdatedStarRatings()
104105
{
105106
foreach (var ruleset in rulesetStore.AvailableRulesets)
106107
{
@@ -132,7 +133,86 @@ private void checkForOutdatedStarRatings()
132133
}
133134
}
134135

135-
private void processBeatmapSetsWithMissingMetrics()
136+
/// <remarks>
137+
/// This is split out from <see cref="processOnlineBeatmapSetsWithNoUpdate"/> as a separate process to prevent high server-side load
138+
/// from the <see cref="beatmapUpdater"/> firing online requests as part of the update.
139+
/// Star rating recalculations can be ran strictly locally.
140+
/// </remarks>
141+
private void populateMissingStarRatings()
142+
{
143+
HashSet<Guid> beatmapIds = new HashSet<Guid>();
144+
145+
Logger.Log("Querying for beatmaps with missing star ratings...");
146+
147+
realmAccess.Run(r =>
148+
{
149+
foreach (var b in r.All<BeatmapInfo>().Where(b => b.StarRating < 0 && b.BeatmapSet != null))
150+
beatmapIds.Add(b.ID);
151+
});
152+
153+
if (beatmapIds.Count == 0)
154+
return;
155+
156+
Logger.Log($"Found {beatmapIds.Count} beatmaps which require star rating reprocessing.");
157+
158+
var notification = showProgressNotification(beatmapIds.Count, "Reprocessing star rating for beatmaps", "beatmaps' star ratings have been updated");
159+
160+
int processedCount = 0;
161+
int failedCount = 0;
162+
163+
Dictionary<string, Ruleset> rulesetCache = new Dictionary<string, Ruleset>();
164+
165+
Ruleset getRuleset(RulesetInfo rulesetInfo)
166+
{
167+
if (!rulesetCache.TryGetValue(rulesetInfo.ShortName, out var ruleset))
168+
ruleset = rulesetCache[rulesetInfo.ShortName] = rulesetInfo.CreateInstance();
169+
170+
return ruleset;
171+
}
172+
173+
foreach (Guid id in beatmapIds)
174+
{
175+
if (notification?.State == ProgressNotificationState.Cancelled)
176+
break;
177+
178+
updateNotificationProgress(notification, processedCount, beatmapIds.Count);
179+
180+
sleepIfRequired();
181+
182+
var beatmap = realmAccess.Run(r => r.Find<BeatmapInfo>(id)?.Detach());
183+
184+
if (beatmap == null)
185+
return;
186+
187+
try
188+
{
189+
var working = beatmapManager.GetWorkingBeatmap(beatmap);
190+
var ruleset = getRuleset(working.BeatmapInfo.Ruleset);
191+
192+
Debug.Assert(ruleset != null);
193+
194+
var calculator = ruleset.CreateDifficultyCalculator(working);
195+
196+
double starRating = calculator.Calculate().StarRating;
197+
realmAccess.Write(r =>
198+
{
199+
if (r.Find<BeatmapInfo>(id) is BeatmapInfo liveBeatmapInfo)
200+
liveBeatmapInfo.StarRating = starRating;
201+
});
202+
((IWorkingBeatmapCache)beatmapManager).Invalidate(beatmap);
203+
++processedCount;
204+
}
205+
catch (Exception e)
206+
{
207+
Logger.Log($"Background processing failed on {beatmap}: {e}");
208+
++failedCount;
209+
}
210+
}
211+
212+
completeNotification(notification, processedCount, beatmapIds.Count, failedCount);
213+
}
214+
215+
private void processOnlineBeatmapSetsWithNoUpdate()
136216
{
137217
HashSet<Guid> beatmapSetIds = new HashSet<Guid>();
138218

@@ -148,23 +228,17 @@ private void processBeatmapSetsWithMissingMetrics()
148228
// of other possible ways), but for now avoid queueing if the user isn't logged in at startup.
149229
if (api.IsLoggedIn)
150230
{
151-
foreach (var b in r.All<BeatmapInfo>().Where(b => (b.StarRating < 0 || (b.OnlineID > 0 && b.LastOnlineUpdate == null)) && b.BeatmapSet != null))
152-
beatmapSetIds.Add(b.BeatmapSet!.ID);
153-
}
154-
else
155-
{
156-
foreach (var b in r.All<BeatmapInfo>().Where(b => b.StarRating < 0 && b.BeatmapSet != null))
231+
foreach (var b in r.All<BeatmapInfo>().Where(b => b.OnlineID > 0 && b.LastOnlineUpdate == null && b.BeatmapSet != null))
157232
beatmapSetIds.Add(b.BeatmapSet!.ID);
158233
}
159234
});
160235

161236
if (beatmapSetIds.Count == 0)
162237
return;
163238

164-
Logger.Log($"Found {beatmapSetIds.Count} beatmap sets which require reprocessing.");
239+
Logger.Log($"Found {beatmapSetIds.Count} beatmap sets which require online updates.");
165240

166-
// Technically this is doing more than just star ratings, but easier for the end user to understand.
167-
var notification = showProgressNotification(beatmapSetIds.Count, "Reprocessing star rating for beatmaps", "beatmaps' star ratings have been updated");
241+
var notification = showProgressNotification(beatmapSetIds.Count, "Updating online data for beatmaps", "beatmaps' online data have been updated");
168242

169243
int processedCount = 0;
170244
int failedCount = 0;

0 commit comments

Comments
 (0)