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 RandomDataGenerator _randomGenerator;
|
||||
|
||||
// Additions to support caching
|
||||
private ISaveDataExtraDataAccessorCacheObserver _cacheObserver;
|
||||
private SaveDataSpaceId _spaceId;
|
||||
private ulong _saveDataId;
|
||||
|
||||
private class DirectorySaveDataFile : IFile
|
||||
{
|
||||
private IFile _baseFile;
|
||||
|
@ -171,6 +176,7 @@ namespace LibHac.FsSystem
|
|||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_cacheObserver?.Unregister(_spaceId, _saveDataId);
|
||||
_baseFs?.Dispose();
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
@ -797,7 +803,12 @@ namespace LibHac.FsSystem
|
|||
public void RegisterCacheObserver(ISaveDataExtraDataAccessorCacheObserver observer, SaveDataSpaceId spaceId,
|
||||
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 LibHac.Fs;
|
||||
using LibHac.Fs.Fsa;
|
||||
using LibHac.FsSystem.Save;
|
||||
|
||||
namespace LibHac.FsSystem
|
||||
{
|
||||
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<SaveDataFileSystem> fileSystem);
|
||||
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