mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add the new save data cache classes from 14.0.0
This commit is contained in:
parent
99ad308b84
commit
cac796ac19
10 changed files with 322 additions and 62 deletions
|
@ -10,13 +10,13 @@ namespace LibHac.FsSrv.Impl;
|
|||
/// <summary>
|
||||
/// Holds the <see cref="ISaveDataExtraDataAccessor"/>s for opened save data file systems.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorCacheObserver
|
||||
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
|
||||
public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorObserver
|
||||
{
|
||||
/// <summary>
|
||||
/// Holds a single cached extra data accessor identified by its save data ID and save data space ID.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
|
||||
[NonCopyable]
|
||||
private struct Cache : IDisposable
|
||||
{
|
||||
|
@ -77,13 +77,14 @@ public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorC
|
|||
public Result Register(in SharedRef<ISaveDataExtraDataAccessor> accessor, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId)
|
||||
{
|
||||
accessor.Get.RegisterCacheObserver(this, spaceId, saveDataId);
|
||||
|
||||
var node = new LinkedListNode<Cache>(new Cache(in accessor, spaceId, saveDataId));
|
||||
|
||||
using (ScopedLock.Lock(ref _mutex))
|
||||
{
|
||||
UnregisterImpl(spaceId, saveDataId);
|
||||
_accessorList.AddLast(node);
|
||||
}
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
UnregisterImpl(spaceId, saveDataId);
|
||||
_accessorList.AddLast(node);
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
@ -134,7 +135,7 @@ public class SaveDataExtraDataAccessorCacheManager : ISaveDataExtraDataAccessorC
|
|||
if (!accessor.HasValue)
|
||||
return ResultFs.TargetNotFound.Log();
|
||||
|
||||
outAccessor.Reset(new SaveDataExtraDataResultConvertAccessor(ref accessor.Ref()));
|
||||
outAccessor.SetByMove(ref accessor.Ref());
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
|
|
165
src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheManager.cs
Normal file
165
src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheManager.cs
Normal file
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using LibHac.Common;
|
||||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.FsSystem;
|
||||
using LibHac.Os;
|
||||
|
||||
namespace LibHac.FsSrv.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Manages a list of cached save data file systems. Each file system is registered and retrieved
|
||||
/// based on its save data ID and save data space ID.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
|
||||
public class SaveDataFileSystemCacheManager : IDisposable
|
||||
{
|
||||
[NonCopyable]
|
||||
private struct Cache
|
||||
{
|
||||
private SharedRef<ISaveDataFileSystem> _fileSystem;
|
||||
private ulong _saveDataId;
|
||||
private SaveDataSpaceId _spaceId;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_fileSystem.Destroy();
|
||||
}
|
||||
|
||||
public bool IsCached(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
return _fileSystem.HasValue && _spaceId == spaceId && _saveDataId == saveDataId;
|
||||
}
|
||||
|
||||
public SharedRef<ISaveDataFileSystem> Move()
|
||||
{
|
||||
return SharedRef<ISaveDataFileSystem>.CreateMove(ref _fileSystem);
|
||||
}
|
||||
|
||||
public void Register(ref SharedRef<ISaveDataFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
_fileSystem.SetByMove(ref fileSystem);
|
||||
_spaceId = spaceId;
|
||||
_saveDataId = saveDataId;
|
||||
}
|
||||
|
||||
public void Unregister()
|
||||
{
|
||||
_fileSystem.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
private SdkRecursiveMutexType _mutex;
|
||||
private Cache[] _cachedFileSystems;
|
||||
private int _maxCachedFileSystemCount;
|
||||
private int _nextCacheIndex;
|
||||
|
||||
public SaveDataFileSystemCacheManager()
|
||||
{
|
||||
_mutex = new SdkRecursiveMutexType();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Cache[] caches = Shared.Move(ref _cachedFileSystems);
|
||||
|
||||
if (caches is not null)
|
||||
{
|
||||
for (int i = 0; i < caches.Length; i++)
|
||||
{
|
||||
caches[i].Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Result Initialize(int maxCacheCount)
|
||||
{
|
||||
Assert.SdkRequiresGreaterEqual(maxCacheCount, 0);
|
||||
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
Assert.SdkAssert(_cachedFileSystems is null);
|
||||
|
||||
_maxCachedFileSystemCount = maxCacheCount;
|
||||
if (maxCacheCount > 0)
|
||||
{
|
||||
// Note: The original checks for overflow here
|
||||
_cachedFileSystems = new Cache[maxCacheCount];
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public UniqueLockRef<SdkRecursiveMutexType> GetScopedLock()
|
||||
{
|
||||
return new UniqueLockRef<SdkRecursiveMutexType>(ref _mutex);
|
||||
}
|
||||
|
||||
public bool GetCache(ref SharedRef<ISaveDataFileSystem> outFileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
Assert.SdkRequiresGreaterEqual(_maxCachedFileSystemCount, 0);
|
||||
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
for (int i = 0; i < _maxCachedFileSystemCount; i++)
|
||||
{
|
||||
if (_cachedFileSystems[i].IsCached(spaceId, saveDataId))
|
||||
{
|
||||
using SharedRef<ISaveDataFileSystem> cachedFs = _cachedFileSystems[i].Move();
|
||||
outFileSystem.SetByMove(ref cachedFs.Ref());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Register(ref SharedRef<ISaveDataFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
Assert.SdkRequiresNotNull(in fileSystem);
|
||||
|
||||
if (_maxCachedFileSystemCount <= 0)
|
||||
return;
|
||||
|
||||
Assert.SdkRequiresGreaterEqual(_nextCacheIndex, 0);
|
||||
Assert.SdkRequiresGreater(_maxCachedFileSystemCount, _nextCacheIndex);
|
||||
|
||||
if (!fileSystem.Get.IsSaveDataFileSystemCacheEnabled())
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
fileSystem.Reset();
|
||||
}
|
||||
else if (spaceId == SaveDataSpaceId.SdSystem)
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
fileSystem.Reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
Result rc = fileSystem.Get.RollbackOnlyModified();
|
||||
if (rc.IsSuccess())
|
||||
{
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
_cachedFileSystems[_nextCacheIndex].Register(ref fileSystem, spaceId, saveDataId);
|
||||
_nextCacheIndex = (_nextCacheIndex + 1) % _maxCachedFileSystemCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Unregister(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
Assert.SdkRequiresGreaterEqual(_maxCachedFileSystemCount, 0);
|
||||
|
||||
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||
|
||||
for (int i = 0; i < _maxCachedFileSystemCount; i++)
|
||||
{
|
||||
if (_cachedFileSystems[i].IsCached(spaceId, saveDataId))
|
||||
{
|
||||
_cachedFileSystems[i].Unregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
117
src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs
Normal file
117
src/LibHac/FsSrv/Impl/SaveDataFileSystemCacheRegister.cs
Normal file
|
@ -0,0 +1,117 @@
|
|||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.FsSrv.Impl;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="ISaveDataFileSystem"/>.
|
||||
/// Upon disposal the base file system is returned to the provided <see cref="ISaveDataFileSystemCacheManager"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
|
||||
public class SaveDataFileSystemCacheRegister : IFileSystem
|
||||
{
|
||||
private SharedRef<ISaveDataFileSystem> _baseFileSystem;
|
||||
private SaveDataFileSystemCacheManager _cacheManager;
|
||||
private SaveDataSpaceId _spaceId;
|
||||
private ulong _saveDataId;
|
||||
|
||||
public SaveDataFileSystemCacheRegister(ref SharedRef<ISaveDataFileSystem> baseFileSystem,
|
||||
SaveDataFileSystemCacheManager cacheManager, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
_baseFileSystem = SharedRef<ISaveDataFileSystem>.CreateMove(ref baseFileSystem);
|
||||
_cacheManager = cacheManager;
|
||||
_spaceId = spaceId;
|
||||
_saveDataId = saveDataId;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_cacheManager.Register(ref _baseFileSystem, _spaceId, _saveDataId);
|
||||
_baseFileSystem.Destroy();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
protected override Result DoOpenFile(ref UniqueRef<IFile> outFile, in Path path, OpenMode mode)
|
||||
{
|
||||
return _baseFileSystem.Get.OpenFile(ref outFile, in path, mode);
|
||||
}
|
||||
|
||||
protected override Result DoOpenDirectory(ref UniqueRef<IDirectory> outDirectory, in Path path,
|
||||
OpenDirectoryMode mode)
|
||||
{
|
||||
return _baseFileSystem.Get.OpenDirectory(ref outDirectory, in path, mode);
|
||||
}
|
||||
|
||||
protected override Result DoGetEntryType(out DirectoryEntryType entryType, in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetEntryType(out entryType, in path);
|
||||
}
|
||||
|
||||
protected override Result DoCreateFile(in Path path, long size, CreateFileOptions option)
|
||||
{
|
||||
return _baseFileSystem.Get.CreateFile(in path, size, option);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteFile(in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteFile(in path);
|
||||
}
|
||||
|
||||
protected override Result DoCreateDirectory(in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.CreateDirectory(in path);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectory(in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteDirectory(in path);
|
||||
}
|
||||
|
||||
protected override Result DoDeleteDirectoryRecursively(in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.DeleteDirectoryRecursively(in path);
|
||||
}
|
||||
|
||||
protected override Result DoCleanDirectoryRecursively(in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.CleanDirectoryRecursively(in path);
|
||||
}
|
||||
|
||||
protected override Result DoRenameFile(in Path currentPath, in Path newPath)
|
||||
{
|
||||
return _baseFileSystem.Get.RenameFile(in currentPath, in newPath);
|
||||
}
|
||||
|
||||
protected override Result DoRenameDirectory(in Path currentPath, in Path newPath)
|
||||
{
|
||||
return _baseFileSystem.Get.RenameDirectory(in currentPath, in newPath);
|
||||
}
|
||||
|
||||
protected override Result DoCommit()
|
||||
{
|
||||
return _baseFileSystem.Get.Commit();
|
||||
}
|
||||
|
||||
protected override Result DoCommitProvisionally(long counter)
|
||||
{
|
||||
return _baseFileSystem.Get.CommitProvisionally(counter);
|
||||
}
|
||||
|
||||
protected override Result DoRollback()
|
||||
{
|
||||
return _baseFileSystem.Get.Rollback();
|
||||
}
|
||||
|
||||
protected override Result DoGetFreeSpaceSize(out long freeSpace, in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetFreeSpaceSize(out freeSpace, in path);
|
||||
}
|
||||
|
||||
protected override Result DoGetTotalSpaceSize(out long totalSpace, in Path path)
|
||||
{
|
||||
return _baseFileSystem.Get.GetTotalSpaceSize(out totalSpace, in path);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
using LibHac.Diag;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem;
|
||||
|
||||
namespace LibHac.FsSrv.Impl;
|
||||
|
||||
|
@ -202,47 +201,3 @@ public class SaveDataResultConvertFileSystem : IResultConvertFileSystem
|
|||
return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wraps an <see cref="ISaveDataExtraDataAccessor"/>, converting its returned <see cref="Result"/>s
|
||||
/// to save-data-specific <see cref="Result"/>s.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
public class SaveDataExtraDataResultConvertAccessor : ISaveDataExtraDataAccessor
|
||||
{
|
||||
private SharedRef<ISaveDataExtraDataAccessor> _accessor;
|
||||
|
||||
public SaveDataExtraDataResultConvertAccessor(ref SharedRef<ISaveDataExtraDataAccessor> accessor)
|
||||
{
|
||||
_accessor = SharedRef<ISaveDataExtraDataAccessor>.CreateMove(ref accessor);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_accessor.Destroy();
|
||||
}
|
||||
|
||||
public Result WriteExtraData(in SaveDataExtraData extraData)
|
||||
{
|
||||
Result rc = _accessor.Get.WriteExtraData(in extraData);
|
||||
return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(rc);
|
||||
}
|
||||
|
||||
public Result CommitExtraData(bool updateTimeStamp)
|
||||
{
|
||||
Result rc = _accessor.Get.CommitExtraData(updateTimeStamp);
|
||||
return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(rc);
|
||||
}
|
||||
|
||||
public Result ReadExtraData(out SaveDataExtraData extraData)
|
||||
{
|
||||
Result rc = _accessor.Get.ReadExtraData(out extraData);
|
||||
return SaveDataResultConvert.ConvertSaveFsDriverPrivateResult(rc);
|
||||
}
|
||||
|
||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId)
|
||||
{
|
||||
_accessor.Get.RegisterCacheObserver(observer, spaceId, saveDataId);
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ public class SaveDataFileSystemServiceImpl
|
|||
private Configuration _config;
|
||||
private EncryptionSeed _encryptionSeed;
|
||||
|
||||
private SaveDataFileSystemCacheManager _saveDataFsCacheManager;
|
||||
private FsSystem.SaveDataFileSystemCacheManager _saveDataFsCacheManager;
|
||||
private SaveDataExtraDataAccessorCacheManager _extraDataCacheManager;
|
||||
// Save data porter manager
|
||||
private bool _isSdCardAccessible;
|
||||
|
@ -47,7 +47,7 @@ public class SaveDataFileSystemServiceImpl
|
|||
public SaveDataFileSystemServiceImpl(in Configuration configuration)
|
||||
{
|
||||
_config = configuration;
|
||||
_saveDataFsCacheManager = new SaveDataFileSystemCacheManager();
|
||||
_saveDataFsCacheManager = new FsSystem.SaveDataFileSystemCacheManager();
|
||||
_extraDataCacheManager = new SaveDataExtraDataAccessorCacheManager();
|
||||
|
||||
_timeStampGetter = new TimeStampGetter(this);
|
||||
|
|
|
@ -83,7 +83,7 @@ public class ApplicationTemporaryFileSystem : IFileSystem, ISaveDataExtraDataAcc
|
|||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId, ulong saveDataId)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public class DirectorySaveDataFileSystem : IFileSystem, ISaveDataExtraDataAccess
|
|||
private RandomDataGenerator _randomGenerator;
|
||||
|
||||
// Additions to support caching
|
||||
private ISaveDataExtraDataAccessorCacheObserver _cacheObserver;
|
||||
private ISaveDataExtraDataAccessorObserver _cacheObserver;
|
||||
private SaveDataSpaceId _spaceId;
|
||||
private ulong _saveDataId;
|
||||
|
||||
|
@ -1056,7 +1056,7 @@ public class DirectorySaveDataFileSystem : IFileSystem, ISaveDataExtraDataAccess
|
|||
return Result.Success;
|
||||
}
|
||||
|
||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId,
|
||||
ulong saveDataId)
|
||||
{
|
||||
_cacheObserver = observer;
|
||||
|
|
|
@ -12,5 +12,5 @@ public interface ISaveDataExtraDataAccessor : IDisposable
|
|||
Result WriteExtraData(in SaveDataExtraData extraData);
|
||||
Result CommitExtraData(bool updateTimeStamp);
|
||||
Result ReadExtraData(out SaveDataExtraData extraData);
|
||||
void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
void RegisterCacheObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
}
|
|
@ -9,8 +9,8 @@ namespace LibHac.FsSystem;
|
|||
/// <see cref="SaveDataExtraDataAccessorCacheManager"/>. When an extra data accessor is disposed, the accessor will
|
||||
/// use this interface to notify the cache manager that it should be removed from the extra data cache.
|
||||
/// </summary>
|
||||
/// <remarks>Based on FS 13.1.0 (nnSdk 13.4.0)</remarks>
|
||||
public interface ISaveDataExtraDataAccessorCacheObserver : IDisposable
|
||||
/// <remarks>Based on FS 14.1.0 (nnSdk 14.3.0)</remarks>
|
||||
public interface ISaveDataExtraDataAccessorObserver : IDisposable
|
||||
{
|
||||
void Unregister(SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
}
|
22
src/LibHac/FsSystem/ISaveDataFileSystem.cs
Normal file
22
src/LibHac/FsSystem/ISaveDataFileSystem.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
|
||||
namespace LibHac.FsSystem;
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public abstract class ISaveDataFileSystem : IFileSystem, ICacheableSaveDataFileSystem, ISaveDataExtraDataAccessor
|
||||
{
|
||||
public abstract bool IsSaveDataFileSystemCacheEnabled();
|
||||
public abstract Result RollbackOnlyModified();
|
||||
|
||||
public abstract Result WriteExtraData(in SaveDataExtraData extraData);
|
||||
public abstract Result CommitExtraData(bool updateTimeStamp);
|
||||
public abstract Result ReadExtraData(out SaveDataExtraData extraData);
|
||||
public abstract void RegisterCacheObserver(ISaveDataExtraDataAccessorObserver observer, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||
}
|
||||
|
||||
public interface ICacheableSaveDataFileSystem
|
||||
{
|
||||
bool IsSaveDataFileSystemCacheEnabled();
|
||||
Result RollbackOnlyModified();
|
||||
}
|
Loading…
Reference in a new issue