mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add SaveDataFileSystemCacheManager
This commit is contained in:
parent
d06731f464
commit
f1caabf82b
3 changed files with 177 additions and 3 deletions
|
@ -55,6 +55,11 @@ namespace LibHac.FsSystem
|
||||||
private ISaveDataCommitTimeStampGetter _timeStampGetter;
|
private ISaveDataCommitTimeStampGetter _timeStampGetter;
|
||||||
private RandomDataGenerator _randomGenerator;
|
private RandomDataGenerator _randomGenerator;
|
||||||
|
|
||||||
|
// Additions to support caching
|
||||||
|
private ISaveDataExtraDataAccessorCacheObserver _cacheObserver;
|
||||||
|
private SaveDataSpaceId _spaceId;
|
||||||
|
private ulong _saveDataId;
|
||||||
|
|
||||||
private class DirectorySaveDataFile : IFile
|
private class DirectorySaveDataFile : IFile
|
||||||
{
|
{
|
||||||
private IFile _baseFile;
|
private IFile _baseFile;
|
||||||
|
@ -171,6 +176,7 @@ namespace LibHac.FsSystem
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
_cacheObserver?.Unregister(_spaceId, _saveDataId);
|
||||||
_baseFs?.Dispose();
|
_baseFs?.Dispose();
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
}
|
}
|
||||||
|
@ -797,7 +803,12 @@ namespace LibHac.FsSystem
|
||||||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
||||||
ulong saveDataId)
|
ulong saveDataId)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
_cacheObserver = observer;
|
||||||
}
|
_spaceId = spaceId;
|
||||||
|
_saveDataId = saveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaveDataSpaceId GetSaveDataSpaceId() => _spaceId;
|
||||||
|
public ulong GetSaveDataId() => _saveDataId;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Fsa;
|
||||||
using LibHac.FsSystem.Save;
|
using LibHac.FsSystem.Save;
|
||||||
|
|
||||||
namespace LibHac.FsSystem
|
namespace LibHac.FsSystem
|
||||||
{
|
{
|
||||||
public interface ISaveDataFileSystemCacheManager : IDisposable
|
public interface ISaveDataFileSystemCacheManager : IDisposable
|
||||||
{
|
{
|
||||||
bool GetCache(out ReferenceCountedDisposable<SaveDataFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId);
|
bool GetCache(out ReferenceCountedDisposable<IFileSystem> fileSystem, SaveDataSpaceId spaceId, ulong saveDataId);
|
||||||
void Register(ReferenceCountedDisposable<ApplicationTemporaryFileSystem> fileSystem);
|
void Register(ReferenceCountedDisposable<ApplicationTemporaryFileSystem> fileSystem);
|
||||||
void Register(ReferenceCountedDisposable<SaveDataFileSystem> fileSystem);
|
void Register(ReferenceCountedDisposable<SaveDataFileSystem> fileSystem);
|
||||||
void Unregister(SaveDataSpaceId spaceId, ulong saveDataId);
|
void Unregister(SaveDataSpaceId spaceId, ulong saveDataId);
|
||||||
|
|
||||||
|
// LibHac addition
|
||||||
|
void Register(ReferenceCountedDisposable<DirectorySaveDataFileSystem> fileSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
159
src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs
Normal file
159
src/LibHac/FsSystem/SaveDataFileSystemCacheManager.cs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Diag;
|
||||||
|
using LibHac.Fs;
|
||||||
|
using LibHac.Fs.Fsa;
|
||||||
|
using LibHac.FsSystem.Save;
|
||||||
|
using LibHac.Os;
|
||||||
|
|
||||||
|
namespace LibHac.FsSystem
|
||||||
|
{
|
||||||
|
public class SaveDataFileSystemCacheManager : ISaveDataFileSystemCacheManager
|
||||||
|
{
|
||||||
|
private struct Cache
|
||||||
|
{
|
||||||
|
private ReferenceCountedDisposable<IFileSystem> _fileSystem;
|
||||||
|
private ulong _saveDataId;
|
||||||
|
private SaveDataSpaceId _spaceId;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_fileSystem?.Dispose();
|
||||||
|
_fileSystem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCached(SaveDataSpaceId spaceId, ulong saveDataId)
|
||||||
|
{
|
||||||
|
return _fileSystem is not null && _spaceId == spaceId && _saveDataId == saveDataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReferenceCountedDisposable<IFileSystem> Move()
|
||||||
|
{
|
||||||
|
return Shared.Move(ref _fileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: Nintendo only supports caching SaveDataFileSystem. We support DirectorySaveDataFileSystem too,
|
||||||
|
// so instead of calling methods on SaveDataFileSystem to get the save data info,
|
||||||
|
// we pass them in as parameters.
|
||||||
|
// Todo: Create a new interface for those methods?
|
||||||
|
public void Register(ReferenceCountedDisposable<IFileSystem> fileSystem, SaveDataSpaceId spaceId,
|
||||||
|
ulong saveDataId)
|
||||||
|
{
|
||||||
|
_spaceId = spaceId;
|
||||||
|
_saveDataId = saveDataId;
|
||||||
|
|
||||||
|
_fileSystem?.Dispose();
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Unregister()
|
||||||
|
{
|
||||||
|
_fileSystem?.Dispose();
|
||||||
|
_fileSystem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private SdkRecursiveMutexType _mutex;
|
||||||
|
private Cache[] _cachedFileSystems;
|
||||||
|
private int _maxCachedFileSystemCount;
|
||||||
|
private int _nextCacheIndex;
|
||||||
|
|
||||||
|
public SaveDataFileSystemCacheManager()
|
||||||
|
{
|
||||||
|
_mutex.Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Cache[] caches = _cachedFileSystems;
|
||||||
|
|
||||||
|
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)
|
||||||
|
return Result.Success;
|
||||||
|
|
||||||
|
// Note: The original checks for overflow here
|
||||||
|
_cachedFileSystems = new Cache[maxCacheCount];
|
||||||
|
return Result.Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetCache(out ReferenceCountedDisposable<IFileSystem> fileSystem, 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))
|
||||||
|
{
|
||||||
|
fileSystem = _cachedFileSystems[i].Move();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSystem = default;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register(ReferenceCountedDisposable<ApplicationTemporaryFileSystem> fileSystem)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register(ReferenceCountedDisposable<SaveDataFileSystem> fileSystem)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Register(ReferenceCountedDisposable<DirectorySaveDataFileSystem> fileSystem)
|
||||||
|
{
|
||||||
|
if (_maxCachedFileSystemCount <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Assert.SdkRequiresGreaterEqual(_nextCacheIndex, 0);
|
||||||
|
Assert.SdkRequiresGreater(_maxCachedFileSystemCount, _nextCacheIndex);
|
||||||
|
|
||||||
|
if (fileSystem.Target.GetSaveDataSpaceId() == SaveDataSpaceId.SdSystem)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Result rc = fileSystem.Target.Rollback();
|
||||||
|
if (rc.IsFailure()) return;
|
||||||
|
|
||||||
|
using ScopedLock<SdkRecursiveMutexType> scopedLock = ScopedLock.Lock(ref _mutex);
|
||||||
|
|
||||||
|
_cachedFileSystems[_nextCacheIndex].Register(fileSystem.AddReference<IFileSystem>(),
|
||||||
|
fileSystem.Target.GetSaveDataSpaceId(), fileSystem.Target.GetSaveDataId());
|
||||||
|
|
||||||
|
_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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue