1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 12:33:01 +08:00

Merge branch 'master' into realm-integration/stable-export-flow

This commit is contained in:
Dan Balasescu 2021-11-25 19:06:18 +09:00 committed by GitHub
commit d3a4890c31
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 46 additions and 52 deletions

View File

@ -1050,7 +1050,7 @@ namespace osu.Game.Tests.Beatmaps.IO
private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected) private static void checkSingleReferencedFileCount(OsuGameBase osu, int expected)
{ {
Assert.AreEqual(expected, osu.Dependencies.Get<FileStore>().QueryFiles(f => f.ReferenceCount == 1).Count()); Assert.AreEqual(expected, osu.Dependencies.Get<DatabaseContextFactory>().Get().FileInfo.Count(f => f.ReferenceCount == 1));
} }
private static void ensureLoaded(OsuGameBase osu, int timeout = 60000) private static void ensureLoaded(OsuGameBase osu, int timeout = 60000)

View File

@ -572,7 +572,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddStep("add mixed ruleset beatmapset", () => AddStep("add mixed ruleset beatmapset", () =>
{ {
testMixed = TestResources.CreateTestBeatmapSetInfo(); testMixed = TestResources.CreateTestBeatmapSetInfo(3);
for (int i = 0; i <= 2; i++) for (int i = 0; i <= 2; i++)
{ {
@ -595,7 +595,7 @@ namespace osu.Game.Tests.Visual.SongSelect
BeatmapSetInfo testSingle = null; BeatmapSetInfo testSingle = null;
AddStep("add single ruleset beatmapset", () => AddStep("add single ruleset beatmapset", () =>
{ {
testSingle = TestResources.CreateTestBeatmapSetInfo(); testSingle = TestResources.CreateTestBeatmapSetInfo(3);
testSingle.Beatmaps.ForEach(b => testSingle.Beatmaps.ForEach(b =>
{ {
b.Ruleset = rulesets.AvailableRulesets.ElementAt(1); b.Ruleset = rulesets.AvailableRulesets.ElementAt(1);
@ -615,7 +615,7 @@ namespace osu.Game.Tests.Visual.SongSelect
List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>(); List<BeatmapSetInfo> manySets = new List<BeatmapSetInfo>();
for (int i = 1; i <= 50; i++) for (int i = 1; i <= 50; i++)
manySets.Add(TestResources.CreateTestBeatmapSetInfo(i)); manySets.Add(TestResources.CreateTestBeatmapSetInfo(3));
loadBeatmaps(manySets); loadBeatmaps(manySets);

View File

@ -19,7 +19,7 @@ namespace osu.Game.Database
/// <param name="obj">The object to use as a reference when negotiating a local instance.</param> /// <param name="obj">The object to use as a reference when negotiating a local instance.</param>
/// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param> /// <param name="lookupSource">An optional lookup source which will be used to query and populate a freshly retrieved replacement. If not provided, the refreshed object will still be returned but will not have any includes.</param>
/// <typeparam name="T">A valid EF-stored type.</typeparam> /// <typeparam name="T">A valid EF-stored type.</typeparam>
protected virtual void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey protected void Refresh<T>(ref T obj, IQueryable<T> lookupSource = null) where T : class, IHasPrimaryKey
{ {
using (var usage = ContextFactory.GetForWrite()) using (var usage = ContextFactory.GetForWrite())
{ {

View File

@ -1,3 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.IO; using osu.Game.IO;

View File

@ -22,7 +22,7 @@ namespace osu.Game.Database
/// <summary> /// <summary>
/// Handles migration of legacy user data from osu-stable. /// Handles migration of legacy user data from osu-stable.
/// </summary> /// </summary>
public class LeagcyImportManager : Component public class LegacyImportManager : Component
{ {
[Resolved] [Resolved]
private SkinManager skins { get; set; } private SkinManager skins { get; set; }

View File

@ -1,3 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;

View File

@ -1,3 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Skinning; using osu.Game.Skinning;
namespace osu.Game.Database namespace osu.Game.Database

View File

@ -14,6 +14,7 @@ using osu.Framework.Statistics;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Input.Bindings; using osu.Game.Input.Bindings;
using osu.Game.Models; using osu.Game.Models;
using osu.Game.Stores;
using Realms; using Realms;
#nullable enable #nullable enable
@ -121,6 +122,10 @@ namespace osu.Game.Database
transaction.Commit(); transaction.Commit();
} }
// clean up files after dropping any pending deletions.
// in the future we may want to only do this when the game is idle, rather than on every startup.
new RealmFileStore(this, storage).Cleanup();
} }
/// <summary> /// <summary>

View File

@ -2,11 +2,8 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.IO.Stores; using osu.Framework.IO.Stores;
using osu.Framework.Logging; using osu.Framework.Logging;
@ -31,13 +28,6 @@ namespace osu.Game.IO
Store = new StorageBackedResourceStore(Storage); Store = new StorageBackedResourceStore(Storage);
} }
/// <summary>
/// Perform a lookup query on available <see cref="FileInfo"/>s.
/// </summary>
/// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns>
public IEnumerable<FileInfo> QueryFiles(Expression<Func<FileInfo, bool>> query) => ContextFactory.Get().Set<FileInfo>().AsNoTracking().Where(f => f.ReferenceCount > 0).Where(query);
public FileInfo Add(Stream data, bool reference = true) public FileInfo Add(Stream data, bool reference = true)
{ {
using (var usage = ContextFactory.GetForWrite()) using (var usage = ContextFactory.GetForWrite())

View File

@ -116,7 +116,7 @@ namespace osu.Game
private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender(); private readonly DifficultyRecommender difficultyRecommender = new DifficultyRecommender();
[Cached] [Cached]
private readonly LeagcyImportManager leagcyImportManager = new LeagcyImportManager(); private readonly LegacyImportManager legacyImportManager = new LegacyImportManager();
[Cached] [Cached]
private readonly ScreenshotManager screenshotManager = new ScreenshotManager(); private readonly ScreenshotManager screenshotManager = new ScreenshotManager();
@ -782,7 +782,7 @@ namespace osu.Game
PostNotification = n => Notifications.Post(n), PostNotification = n => Notifications.Post(n),
}, Add, true); }, Add, true);
loadComponentSingleFile(leagcyImportManager, Add); loadComponentSingleFile(legacyImportManager, Add);
loadComponentSingleFile(screenshotManager, Add); loadComponentSingleFile(screenshotManager, Add);

View File

@ -31,9 +31,9 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
private SettingsButton undeleteButton; private SettingsButton undeleteButton;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LeagcyImportManager leagcyImportManager, DialogOverlay dialogOverlay) private void load(BeatmapManager beatmaps, ScoreManager scores, SkinManager skins, [CanBeNull] CollectionManager collectionManager, [CanBeNull] LegacyImportManager legacyImportManager, DialogOverlay dialogOverlay)
{ {
if (leagcyImportManager?.SupportsImportFromStable == true) if (legacyImportManager?.SupportsImportFromStable == true)
{ {
Add(importBeatmapsButton = new SettingsButton Add(importBeatmapsButton = new SettingsButton
{ {
@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Action = () => Action = () =>
{ {
importBeatmapsButton.Enabled.Value = false; importBeatmapsButton.Enabled.Value = false;
leagcyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true)); legacyImportManager.ImportFromStableAsync(StableContent.Beatmaps).ContinueWith(t => Schedule(() => importBeatmapsButton.Enabled.Value = true));
} }
}); });
} }
@ -59,7 +59,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
} }
}); });
if (leagcyImportManager?.SupportsImportFromStable == true) if (legacyImportManager?.SupportsImportFromStable == true)
{ {
Add(importScoresButton = new SettingsButton Add(importScoresButton = new SettingsButton
{ {
@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Action = () => Action = () =>
{ {
importScoresButton.Enabled.Value = false; importScoresButton.Enabled.Value = false;
leagcyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true)); legacyImportManager.ImportFromStableAsync(StableContent.Scores).ContinueWith(t => Schedule(() => importScoresButton.Enabled.Value = true));
} }
}); });
} }
@ -85,7 +85,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
} }
}); });
if (leagcyImportManager?.SupportsImportFromStable == true) if (legacyImportManager?.SupportsImportFromStable == true)
{ {
Add(importSkinsButton = new SettingsButton Add(importSkinsButton = new SettingsButton
{ {
@ -93,7 +93,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Action = () => Action = () =>
{ {
importSkinsButton.Enabled.Value = false; importSkinsButton.Enabled.Value = false;
leagcyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true)); legacyImportManager.ImportFromStableAsync(StableContent.Skins).ContinueWith(t => Schedule(() => importSkinsButton.Enabled.Value = true));
} }
}); });
} }
@ -113,7 +113,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
if (collectionManager != null) if (collectionManager != null)
{ {
if (leagcyImportManager?.SupportsImportFromStable == true) if (legacyImportManager?.SupportsImportFromStable == true)
{ {
Add(importCollectionsButton = new SettingsButton Add(importCollectionsButton = new SettingsButton
{ {
@ -121,7 +121,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
Action = () => Action = () =>
{ {
importCollectionsButton.Enabled.Value = false; importCollectionsButton.Enabled.Value = false;
leagcyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true)); legacyImportManager.ImportFromStableAsync(StableContent.Collections).ContinueWith(t => Schedule(() => importCollectionsButton.Enabled.Value = true));
} }
}); });
} }

View File

@ -24,7 +24,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Scoring namespace osu.Game.Scoring
{ {
public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelFileManager<ScoreInfo, ScoreFileInfo>, IModelDownloader<IScoreInfo> public class ScoreManager : IModelManager<ScoreInfo>, IModelImporter<ScoreInfo>, IModelDownloader<IScoreInfo>
{ {
private readonly Scheduler scheduler; private readonly Scheduler scheduler;
private readonly Func<BeatmapDifficultyCache> difficulties; private readonly Func<BeatmapDifficultyCache> difficulties;
@ -326,25 +326,6 @@ namespace osu.Game.Scoring
#endregion #endregion
#region Implementation of IModelFileManager<in ScoreInfo,in ScoreFileInfo>
public void ReplaceFile(ScoreInfo model, ScoreFileInfo file, Stream contents, string filename = null)
{
scoreModelManager.ReplaceFile(model, file, contents, filename);
}
public void DeleteFile(ScoreInfo model, ScoreFileInfo file)
{
scoreModelManager.DeleteFile(model, file);
}
public void AddFile(ScoreInfo model, Stream contents, string filename)
{
scoreModelManager.AddFile(model, contents, filename);
}
#endregion
#region Implementation of IModelDownloader<IScoreInfo> #region Implementation of IModelDownloader<IScoreInfo>
public event Action<ArchiveDownloadRequest<IScoreInfo>> DownloadBegan public event Action<ArchiveDownloadRequest<IScoreInfo>> DownloadBegan

View File

@ -51,7 +51,7 @@ namespace osu.Game.Screens.Select
protected virtual bool ShowFooter => true; protected virtual bool ShowFooter => true;
protected virtual bool DisplayStableImportPrompt => leagcyImportManager?.SupportsImportFromStable == true; protected virtual bool DisplayStableImportPrompt => legacyImportManager?.SupportsImportFromStable == true;
public override bool? AllowTrackAdjustments => true; public override bool? AllowTrackAdjustments => true;
@ -90,7 +90,7 @@ namespace osu.Game.Screens.Select
private BeatmapManager beatmaps { get; set; } private BeatmapManager beatmaps { get; set; }
[Resolved(CanBeNull = true)] [Resolved(CanBeNull = true)]
private LeagcyImportManager leagcyImportManager { get; set; } private LegacyImportManager legacyImportManager { get; set; }
protected ModSelectOverlay ModSelect { get; private set; } protected ModSelectOverlay ModSelect { get; private set; }
@ -297,7 +297,7 @@ namespace osu.Game.Screens.Select
{ {
dialogOverlay.Push(new ImportFromStablePopup(() => dialogOverlay.Push(new ImportFromStablePopup(() =>
{ {
Task.Run(() => leagcyImportManager.ImportFromStableAsync(StableContent.All)); Task.Run(() => legacyImportManager.ImportFromStableAsync(StableContent.All));
})); }));
} }
}); });

View File

@ -86,9 +86,13 @@ namespace osu.Game.Stores
public void Cleanup() public void Cleanup()
{ {
var realm = realmFactory.Context; Logger.Log(@"Beginning realm file store cleanup");
int totalFiles = 0;
int removedFiles = 0;
// can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal. // can potentially be run asynchronously, although we will need to consider operation order for disk deletion vs realm removal.
using (var realm = realmFactory.CreateContext())
using (var transaction = realm.BeginWrite()) using (var transaction = realm.BeginWrite())
{ {
// TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707) // TODO: consider using a realm native query to avoid iterating all files (https://github.com/realm/realm-dotnet/issues/2659#issuecomment-927823707)
@ -96,11 +100,14 @@ namespace osu.Game.Stores
foreach (var file in files) foreach (var file in files)
{ {
totalFiles++;
if (file.BacklinksCount > 0) if (file.BacklinksCount > 0)
continue; continue;
try try
{ {
removedFiles++;
Storage.Delete(file.GetStoragePath()); Storage.Delete(file.GetStoragePath());
realm.Remove(file); realm.Remove(file);
} }
@ -112,6 +119,8 @@ namespace osu.Game.Stores
transaction.Commit(); transaction.Commit();
} }
Logger.Log($@"Finished realm file store cleanup ({removedFiles} of {totalFiles} deleted)");
} }
} }
} }