Skip to content

Commit

Permalink
Use MemoryCache to allow for LRU expiration
Browse files Browse the repository at this point in the history
Set with some values which will work well for current production load /
throughput.
  • Loading branch information
peppy committed Nov 1, 2024
1 parent 81fea54 commit b356afd
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 24 deletions.
38 changes: 30 additions & 8 deletions GlobalRankLookupCache/Controllers/BeatmapItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,46 @@ public BeatmapItem(int beatmapId, string highScoresTable)
}
}

_ = Task.Run(queueRepopulationIfRequired);

Interlocked.Increment(ref RankLookupController.Hits);
int result = scores.BinarySearch(score + 1);
return (scores.Count - (result < 0 ? ~result : result), scores.Count, true);
}

private async Task queueRepopulationIfRequired()
{
// check whether last update was too long ago
if ((DateTime.Now - lastPopulation).TotalSeconds > scores.Count)
if ((DateTime.Now - lastPopulation).TotalSeconds > Scores.Count)
{
lastPopulation = DateTimeOffset.Now;

// For seldom requested beatmaps, skip re-population.
if (requestsSinceLastPopulation >= 5)
{
_ = Task.Run(repopulateScores);
// Also check whether things actually changed enough to matter.
if (Math.Abs(await getLiveScoreCount() - Scores.Count) > 10)
await repopulateScores();
else
Console.Write("0");
}
else
{
Console.Write(".");
lastPopulation = DateTimeOffset.Now;
}
}
}

Interlocked.Increment(ref RankLookupController.Hits);
int result = scores.BinarySearch(score + 1);
return (scores.Count - (result < 0 ? ~result : result), scores.Count, true);
private async Task<int> getLiveScoreCount()
{
int total;

using (var db = await Program.GetDatabaseConnection())
using (var cmd = db.CreateCommand())
{
cmd.CommandText = $"select count(*) from {highScoresTable} where beatmap_id = {beatmapId} and hidden = 0";
total = (int)(long)(await cmd.ExecuteScalarAsync())!;
}

return total;
}

private readonly SemaphoreSlim populationSemaphore = new SemaphoreSlim(1);
Expand Down
44 changes: 28 additions & 16 deletions GlobalRankLookupCache/Controllers/BeatmapRankCacheCollection.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System.Collections.Concurrent;
using System;
using System.Threading.Tasks;
using osu.Framework.Extensions;
using Microsoft.Extensions.Caching.Memory;

namespace GlobalRankLookupCache.Controllers
{
internal class BeatmapRankCacheCollection
{
private readonly string highScoresTable;

private readonly ConcurrentDictionary<int, BeatmapItem> beatmapScoresLookup = new ConcurrentDictionary<int, BeatmapItem>();
private readonly MemoryCache beatmapScoresLookup = new MemoryCache(new MemoryCacheOptions
{
SizeLimit = 192000,
});

public long Count => beatmapScoresLookup.Count;

Expand All @@ -17,23 +20,32 @@ public BeatmapRankCacheCollection(string highScoresTable)
this.highScoresTable = highScoresTable;
}

public void Update(int beatmapId, in int oldScore, in int newScore)
{
if (!beatmapScoresLookup.TryGetValue(beatmapId, out var beatmapCache))
return; // if we're not tracking this beatmap we can just ignore.
// public void Update(int beatmapId, in int oldScore, in int newScore)
// {
// if (!beatmapScoresLookup.TryGetValue(beatmapId, out var beatmapCache))
// return; // if we're not tracking this beatmap we can just ignore.
//
// lock (beatmapCache)
// {
// beatmapCache.Scores.Remove(oldScore);
// beatmapCache.Scores.AddInPlace(newScore);
// }
// }
//
// public bool Clear(in int beatmapId) => beatmapScoresLookup.TryRemove(beatmapId, out var _);

lock (beatmapCache)
public Task<(int position, int total, bool accurate)> Lookup(int beatmapId, in int score)
{
return beatmapScoresLookup.GetOrCreate(beatmapId, e =>
{
beatmapCache.Scores.Remove(oldScore);
beatmapCache.Scores.AddInPlace(newScore);
}
}
var item = new BeatmapItem(beatmapId, highScoresTable);

public bool Clear(in int beatmapId) => beatmapScoresLookup.TryRemove(beatmapId, out var _);
e.SetSlidingExpiration(TimeSpan.FromDays(1));
e.Size = 1;
e.Value = item;

public Task<(int position, int total, bool accurate)> Lookup(int beatmapId, in int score)
{
return beatmapScoresLookup.GetOrAdd(beatmapId, new BeatmapItem(beatmapId, highScoresTable)).Lookup(score);
return item;
}).Lookup(score);
}
}
}

0 comments on commit b356afd

Please sign in to comment.