FulcrumFS FulcrumFS
FulcrumFS FulcrumFS
DocFX + Singulink = ♥

Search Results for

    Read-Only Repositories

    A FileRepo opened read-only reads files from a repository without ever writing to it, while another process uses the same repository as its writer. This guide covers when to use read-only mode, what it allows, and what a reader has to expect from files that the writer deletes.

    When to use read-only mode

    Only one FileRepo with full access can use a repository at a time: it holds the repository lock for as long as it is in use. Read-only mode takes no lock, so it suits three situations:

    • Reading a live repository from another process. A static file host or download service can serve the files that the main application stores, without going through the application and without stopping it.
    • Reading a repository without changing it. A read-only instance never creates or upgrades a repository, whatever MinimumFormatVersion is configured, so a newer library can read repositories that older processes still write to, without moving them to a format those processes cannot open.
    • Reading a repository whose format is newer than the library supports for full access. A library refuses full access to a repository with a newer format version, but a format change that only adds new kinds of entries keeps reading compatible. A read-only instance opens any repository whose read-compat-version the library supports.

    Opening a Repository Read-Only

    Set ReadOnly when constructing the repository:

    var baseDir = DirectoryPath.ParseAbsolute(@"C:\AppData\PhotoApp\Files");
    
    var repo = new FileRepo(baseDir, RepoFormatVersion.Version2, options => {
        options.ReadOnly = true;
    });
    
    repo.EnsureCreated();
    

    The minimum format version is required as for any repository, but it has no effect here: a read-only instance never creates or upgrades a repository. EnsureCreated behaves exactly as EnsureInitialized does and only verifies and opens the existing repository. Both throw a DirectoryNotFoundException if there is no repository at the base directory or the repository is incomplete, since only an instance with full access can create or repair it.

    Opening the repository reads its info file and checks that the directories exist, once. A read-only instance takes no lock, does not touch the temp directory that the writer works in, and runs no health checks, because those write to the lock file. If the storage goes away while the instance is open, fetches fail or report files as not found until it is back.

    FileRepo.FormatVersion reports the format version the repository had when it was opened. It is not updated if the writer later upgrades the repository.

    What Works and What Throws

    Reading

    Everything that only reads works as it does with full access:

    • GetAsync, GetGroupAsync and GetVariantAsync.
    • OpenAsync and OpenVariantAsync.
    • EnumerateFilesAsync.
    • GetOrAddVariantAsync when every variant it asks for already exists, which it returns.
    • The CorruptionDetected event, which fetches raise as usual. Fetches never repair anything on disk, so nothing is skipped in read-only mode.

    Writing

    Every member that would write throws an InvalidOperationException:

    • BeginTransactionAsync and BeginStagedTransactionAsync.
    • AddVariantAsync and TryAddVariantAsync, and GetOrAddVariantAsync when a variant would have to be added.
    • DeleteVariantsAsync.
    • CleanAsync. Clean the repository from the writer or with a separate FileRepoCleaner (see Repository Cleanup).

    Code that works with the IFileRepo interface can check IFileRepo.IsReadOnly before it tries to write.

    Files That Vanish Under a Reader

    The writer keeps adding and deleting files while a reader is open, and a reader sees each change as soon as it is on disk. A deleted main file stays readable until it is physically removed: in the deferred delete modes that happens when a cleanup pass runs after the delete delay, and in Immediate mode it happens when the deletion commits. A retired variant can no longer be fetched as soon as it is retired.

    Once a file has been removed, fetching it throws a RepoFileNotFoundException, and opening a RepoFileInfo that was fetched before the removal, or reading its Length, throws an IOException. A stream that was already open is not affected: repository streams allow the file to be deleted while they are open, so the reader keeps reading the file to the end.

    Tip

    A file host that runs as a reader should treat a RepoFileNotFoundException as a normal "not found" response at any time, including for a file it found moments earlier.

    Next Steps

    These articles cover the rest of what a reader interacts with:

    • Fetching Files - Fetching files and variants and opening their content.
    • Repository Layout - The format version and what each version contains.
    • Deleting Files and Variants - When deleted files are physically removed.
    © Singulink. All rights reserved.