Add documentation for SaveDataIndexer and related classes

This commit is contained in:
Alex Barney 2020-08-06 00:01:35 -07:00
parent 730167785e
commit 9e57cc174e
6 changed files with 191 additions and 2 deletions

View file

@ -3,23 +3,146 @@ using LibHac.Fs;
namespace LibHac.FsService
{
/// <summary>
/// Indexes save data metadata, holding key-value pairs of types <see cref="SaveDataAttribute"/> and
/// <see cref="SaveDataIndexerValue"/> respectively.
/// </summary>
/// <remarks>
/// Each <see cref="SaveDataIndexerValue"/> value contains information about the save data
/// including its size and current state, as well as its <see cref="SaveDataSpaceId"/> and save data
/// ID which represent the save data's storage location on disk.
/// </remarks>
public interface ISaveDataIndexer : IDisposable
{
/// <summary>
/// Commit any changes made to the save data index.
/// </summary>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Commit();
/// <summary>
/// Rollback any changes made to the save data index since the last commit.
/// </summary>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Rollback();
/// <summary>
/// Remove all entries from the save data index and set the index to its initial state.
/// </summary>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Reset();
/// <summary>
/// Adds a new key to the index and returns the save data ID assigned to it.
/// The created value will only contain the assigned save data ID.
/// Fails if the key already exists.
/// </summary>
/// <param name="saveDataId">If the method returns successfully, contains the
/// save data ID assigned to the new entry.
/// Save data IDs are assigned using a counter that is incremented for each added save.</param>
/// <param name="key">The key to add.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Publish(out ulong saveDataId, in SaveDataAttribute key);
/// <summary>
/// Retrieves the <see cref="SaveDataIndexerValue"/> for the specified <see cref="SaveDataAttribute"/> key.
/// </summary>
/// <param name="value">If the method returns successfully, contains the
/// save data ID assigned to the new entry.</param>
/// <param name="key">The key of the value to get.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Get(out SaveDataIndexerValue value, in SaveDataAttribute key);
/// <summary>
/// Adds a key with a pre-specified static save data ID to the index.
/// </summary>
/// <remarks>
/// Adding a save data ID that is already in the index is not allowed. Adding a static ID that might
/// conflict with a future dynamically-assigned ID should be avoided, otherwise there will be two saves
/// with the same ID.
/// FileSystemProxy avoids this by setting the high bit on static IDs. e.g. 0x8000000000000015
/// </remarks>
/// <param name="key">The key to add.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result PutStaticSaveDataIdIndex(in SaveDataAttribute key);
/// <summary>
/// Determines if there are any non-reserved entry slots remaining in the index.
/// </summary>
/// <remarks>If the <see cref="ISaveDataIndexer"/> has a fixed number of entries, a portion of
/// those entries may be reserved for internal use, </remarks>
/// <returns><see langword="true"/> if there are any non-reserved entries remaining,
/// otherwise <see langword="false"/>.</returns>
bool IsRemainedReservedOnly();
/// <summary>
/// Removes the save data with the specified save data ID from the index.
/// </summary>
/// <param name="saveDataId">The ID of the save to be removed.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Delete(ulong saveDataId);
/// <summary>
/// Sets the <see cref="SaveDataSpaceId"/> in the specified save data's value.
/// </summary>
/// <param name="saveDataId">The save data ID of the save data to modify.</param>
/// <param name="spaceId">The new <see cref="SaveDataSpaceId"/> for the specified save data.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result SetSpaceId(ulong saveDataId, SaveDataSpaceId spaceId);
/// <summary>
/// Sets the size in the specified save data's value.
/// </summary>
/// <param name="saveDataId">The save data ID of the save data to modify.</param>
/// <param name="size">The new size for the specified save data.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result SetSize(ulong saveDataId, long size);
/// <summary>
/// Sets the <see cref="SaveDataState"/> in the specified save data's value.
/// </summary>
/// <param name="saveDataId">The save data ID of the save data to modify.</param>
/// <param name="state">The new <see cref="SaveDataState"/> for the specified save data.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result SetState(ulong saveDataId, SaveDataState state);
/// <summary>
/// Gets the key of the specified save data ID.
/// </summary>
/// <param name="key">If the method returns successfully, contains the <see cref="SaveDataAttribute"/>
/// key of the specified save data ID.</param>
/// <param name="saveDataId">The save data ID to locate.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result GetKey(out SaveDataAttribute key, ulong saveDataId);
/// <summary>
/// Gets the value of the specified save data ID.
/// </summary>
/// <param name="value">If the method returns successfully, contains the <see cref="SaveDataIndexerValue"/>
/// value of the specified save data ID.</param>
/// <param name="saveDataId">The save data ID to locate.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result GetValue(out SaveDataIndexerValue value, ulong saveDataId);
/// <summary>
/// Sets a new value to a key that already exists in the index.
/// </summary>
/// <param name="key">The key of the value to set.</param>
/// <param name="value">The new value to associate with the specified key.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result SetValue(in SaveDataAttribute key, in SaveDataIndexerValue value);
/// <summary>
/// Gets the number of elements currently in the <see cref="SaveDataIndexer"/>.
/// </summary>
/// <returns>The current element count.</returns>
int GetIndexCount();
/// <summary>
/// Returns an <see cref="ISaveDataInfoReader"/> that iterates through the <see cref="SaveDataIndexer"/>.
/// </summary>
/// <param name="infoReader">If the method returns successfully, contains the created <see cref="ISaveDataInfoReader"/>.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result OpenSaveDataInfoReader(out ReferenceCountedDisposable<ISaveDataInfoReader> infoReader);
}
}

View file

@ -1,9 +1,24 @@
using System;
using LibHac.Fs;
namespace LibHac.FsService
{
/// <summary>
/// Iterates through the <see cref="SaveDataInfo"/> of the save data
/// in a single save data space.
/// </summary>
public interface ISaveDataInfoReader : IDisposable
{
/// <summary>
/// Returns the next <see cref="SaveDataInfo"/> entries. This method will continue writing
/// entries to <paramref name="saveDataInfoBuffer"/> until there is either no more space
/// in the buffer, or until there are no more entries to iterate.
/// </summary>
/// <param name="readCount">If the method returns successfully, contains the number
/// of <see cref="SaveDataInfo"/> written to <paramref name="saveDataInfoBuffer"/>.
/// A value of 0 indicates that there are no more entries to iterate, or the buffer is too small.</param>
/// <param name="saveDataInfoBuffer">The buffer in which to write the <see cref="SaveDataInfo"/>.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
Result Read(out long readCount, Span<byte> saveDataInfoBuffer);
}
}

View file

@ -12,6 +12,16 @@ using LibHac.Kvdb;
namespace LibHac.FsService
{
/// <summary>
/// Indexes metadata for persistent save data stored on disk, holding key-value pairs of types
/// <see cref="SaveDataAttribute"/> and <see cref="SaveDataIndexerValue"/> respectively.
/// </summary>
/// <remarks>
/// Each <see cref="SaveDataIndexer"/> manages one to two save data spaces.
/// Each save data space is identified by a <see cref="SaveDataSpaceId"/>,
/// and has its own unique storage location on disk.<br/>
/// Based on FS 10.0.0 (nnSdk 10.4.0)
/// </remarks>
public class SaveDataIndexer : ISaveDataIndexer
{
private const int KvDatabaseCapacity = 0x1080;
@ -92,6 +102,12 @@ namespace LibHac.FsService
Debug.Assert(!sb.Overflowed);
}
/// <summary>
/// Generates a <see cref="SaveDataInfo"/> from the provided <see cref="SaveDataAttribute"/> and <see cref="SaveDataIndexerValue"/>.
/// </summary>
/// <param name="info">When this method returns, contains the generated <see cref="SaveDataInfo"/>.</param>
/// <param name="key">The key used to generate the <see cref="SaveDataInfo"/>.</param>
/// <param name="value">The value used to generate the <see cref="SaveDataInfo"/>.</param>
public static void GenerateSaveDataInfo(out SaveDataInfo info, in SaveDataAttribute key, in SaveDataIndexerValue value)
{
info = new SaveDataInfo
@ -701,6 +717,10 @@ namespace LibHac.FsService
return Result.Success;
}
/// <summary>
/// Mounts the storage for a <see cref="SaveDataIndexer"/>, and unmounts the storage
/// when the <see cref="Mounter"/> is disposed;
/// </summary>
private ref struct Mounter
{
private FileSystemClient FsClient { get; set; }

View file

@ -4,6 +4,15 @@ using LibHac.Fs;
namespace LibHac.FsService
{
/// <summary>
/// Indexes metadata for temporary save data, holding a key-value pair of types
/// <see cref="SaveDataAttribute"/> and <see cref="SaveDataIndexerValue"/> respectively.
/// </summary>
/// <remarks>
/// Only one temporary save data may exist at a time. When a new
/// save data is added to the index, the existing key-value pair is replaced.<br/>
/// Based on FS 10.0.0 (nnSdk 10.4.0)
/// </remarks>
public class SaveDataIndexerLite : ISaveDataIndexer
{
private object Locker { get; } = new object();

View file

@ -7,6 +7,11 @@ using LibHac.FsService.Storage;
namespace LibHac.FsService
{
/// <summary>
/// Initializes and holds <see cref="ISaveDataIndexer"/>s for each save data space.
/// Creates accessors for individual SaveDataIndexers.
/// </summary>
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
internal class SaveDataIndexerManager : ISaveDataIndexerManager
{
private FileSystemClient FsClient { get; }
@ -37,6 +42,18 @@ namespace LibHac.FsService
_tempIndexer.Indexer = new SaveDataIndexerLite();
}
/// <summary>
/// Opens a <see cref="SaveDataIndexerAccessor"/> for the specified save data space.
/// </summary>
/// <remarks>
/// The returned <see cref="SaveDataIndexerAccessor"/> will have exclusive access to the requested indexer.
/// The accessor must be disposed after use.
/// </remarks>
/// <param name="accessor">If the method returns successfully, contains the created accessor.</param>
/// <param name="neededInit">If the method returns successfully, contains <see langword="true"/>
/// if the indexer needed to be initialized.</param>
/// <param name="spaceId">The <see cref="SaveDataSpaceId"/> of the indexer to open.</param>
/// <returns>The <see cref="Result"/> of the operation.</returns>
public Result OpenAccessor(out SaveDataIndexerAccessor accessor, out bool neededInit, SaveDataSpaceId spaceId)
{
neededInit = false;
@ -200,6 +217,11 @@ namespace LibHac.FsService
};
}
/// <summary>
/// Gives exclusive access to an <see cref="ISaveDataIndexer"/>.
/// Releases the lock to the <see cref="ISaveDataIndexer"/> upon disposal.
/// </summary>
/// <remarks>Based on FS 10.0.0 (nnSdk 10.4.0)</remarks>
public class SaveDataIndexerAccessor : IDisposable
{
public ISaveDataIndexer Indexer { get; }

View file

@ -10,8 +10,8 @@ namespace LibHac.FsSystem
/// </summary>
/// <remarks>
/// Transactional commits should be atomic as long as the <see cref="IFileSystem.RenameDirectory"/> function of the
/// underlying <see cref="IFileSystem"/> is atomic.
/// This class is based on nn::fssystem::DirectorySaveDataFileSystem in SDK 10.4.0 used in FS 10.0.0
/// underlying <see cref="IFileSystem"/> is atomic.<br/>
/// Based on FS 10.0.0 (nnSdk 10.4.0)
/// </remarks>
public class DirectorySaveDataFileSystem : IFileSystem
{