From 29b93ca0d779082e7bbfcc6914b529c04f82b853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 12 Aug 2025 09:10:14 +0200 Subject: [PATCH] Reduce number of realm subscription triggers from song select online lookups --- .../RealmPopulatingOnlineLookupSource.cs | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs index a5a2aabcca..486dfbe255 100644 --- a/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs +++ b/osu.Game/Screens/SelectV2/RealmPopulatingOnlineLookupSource.cs @@ -75,29 +75,39 @@ namespace osu.Game.Screens.SelectV2 foreach (var dbBeatmapSet in dbBeatmapSets) { - dbBeatmapSet.Status = onlineBeatmapSet.Status; + // note that every single write to realm models is preceded by a guard, even if it technically would write the same value back. + // the reason this matters is that doing so avoids triggering realm subscription callbacks. + // unfortunately in terms of subscriptions realm treats *every* write to any realm object as a modification, + // even if the write was redundant and had no observable effect. + + if (dbBeatmapSet.Status != onlineBeatmapSet.Status) + dbBeatmapSet.Status = onlineBeatmapSet.Status; foreach (var dbBeatmap in dbBeatmapSet.Beatmaps) { if (onlineBeatmaps.TryGetValue(dbBeatmap.OnlineID, out var onlineBeatmap)) { // compare `BeatmapUpdaterMetadataLookup` - dbBeatmap.OnlineMD5Hash = onlineBeatmap.MD5Hash; - dbBeatmap.LastOnlineUpdate = onlineBeatmap.LastUpdated; + if (dbBeatmap.OnlineMD5Hash != onlineBeatmap.MD5Hash) + dbBeatmap.OnlineMD5Hash = onlineBeatmap.MD5Hash; - if (dbBeatmap.MatchesOnlineVersion) + if (dbBeatmap.LastOnlineUpdate != onlineBeatmap.LastUpdated) + dbBeatmap.LastOnlineUpdate = onlineBeatmap.LastUpdated; + + if (dbBeatmap.MatchesOnlineVersion && dbBeatmap.Status != onlineBeatmap.Status) dbBeatmap.Status = onlineBeatmap.Status; - string[] userTagsArray = onlineBeatmap.TopTags? - .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) - .Where(t => t.relatedTag != null) - // see https://github.com/ppy/osu-web/blob/bb3bd2e7c6f84f26066df5ea20a81c77ec9bb60a/resources/js/beatmapsets-show/controller.ts#L103-L106 for sort criteria - .OrderByDescending(t => t.topTag.VoteCount) - .ThenBy(t => t.relatedTag!.Name) - .Select(t => t.relatedTag!.Name) - .ToArray() ?? []; - dbBeatmap.Metadata.UserTags.Clear(); - dbBeatmap.Metadata.UserTags.AddRange(userTagsArray); + HashSet userTags = onlineBeatmap.TopTags? + .Select(t => (topTag: t, relatedTag: tagsById.GetValueOrDefault(t.TagId))) + .Where(t => t.relatedTag != null) + .Select(t => t.relatedTag!.Name) + .ToHashSet() ?? []; + + if (!userTags.SetEquals(dbBeatmap.Metadata.UserTags)) + { + dbBeatmap.Metadata.UserTags.Clear(); + dbBeatmap.Metadata.UserTags.AddRange(userTags); + } } } }