SharedFileJournal 0.1.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package SharedFileJournal --version 0.1.5
                    
NuGet\Install-Package SharedFileJournal -Version 0.1.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SharedFileJournal" Version="0.1.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SharedFileJournal" Version="0.1.5" />
                    
Directory.Packages.props
<PackageReference Include="SharedFileJournal" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SharedFileJournal --version 0.1.5
                    
#r "nuget: SharedFileJournal, 0.1.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SharedFileJournal@0.1.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SharedFileJournal&version=0.1.5
                    
Install as a Cake Addin
#tool nuget:?package=SharedFileJournal&version=0.1.5
                    
Install as a Cake Tool

SharedFileJournal

A cross-platform .NET library for high-speed concurrent multi-process append to a shared journal file — without per-write file locking.

Key Features

  • Multi-process safe: Multiple processes can append concurrently via atomic offset reservation
  • No file locks on writes: Uses Interlocked.Add on a memory-mapped metadata region for lock-free space reservation, then RandomAccess.Write at the reserved offset
  • Recoverable format: Self-validating records (header with xxHash3 checksum, aligned to 16-byte boundaries) let readers detect and recover from partial/crashed writes
  • Cross-platform: Works on Windows, Linux, and macOS with .NET 10+

Architecture

Single-file design

The journal is a single file containing a 4 KB metadata header followed by sequential record data. The first 4096 bytes are memory-mapped for atomic coordination; records start at offset 4096.

Atomic reservation strategy

The metadata file is mapped via MemoryMappedFile.CreateFromFile. A raw pointer to the NextWriteOffset field (at cache-line-aligned offset 64 within the file header) is used with Interlocked.Add for atomic fetch-add semantics. This works across processes because the mapping is backed by the same physical pages, and Interlocked compiles to hardware atomics (lock xadd on x86-64) that are coherent across all sharers.

Record format (16 bytes overhead)

Header (16 bytes): Magic "SFJR" (4B) | PayloadLength (4B) | Checksum (8B)
Payload:           Variable-length byte data
Padding:           0–15 bytes to align total record size to 16-byte boundary

Records are aligned to 16-byte boundaries so that recovery scanning can step by alignment instead of byte-by-byte, eliminating chunk-overlap logic.

Skip markers

When ReadAll encounters a gap (from a crashed writer) and scans forward to find the next valid record, it writes a skip marker at the gap start using an atomic 8-byte CAS via a memory-mapped pointer. Skip markers have the same 16-byte header layout with magic "SFJS" and PayloadLength set to the gap body size. Future readers see the skip marker and jump over the gap in O(1) instead of re-scanning.

Specification

See SPEC.md for the full file format specification, including byte-level header layouts, the read/write algorithms, corruption recovery, and the concurrency model.

Quick Start

using SharedFileJournal;

// Open (or create) a journal — safe for multiple processes
using var journal = new SharedJournal("/path/to/myjournal");

// Append records (thread-safe, process-safe)
journal.Append("hello"u8);
journal.Append(myPayloadBytes);

// Read all valid records
// Note: record.Payload is only valid until the next iteration.
// Copy with .ToArray() if you need to keep it.
foreach (var record in journal.ReadAll())
    Console.WriteLine($"offset={record.Offset} len={record.Payload.Length}");

// Compact: reclaim space from gaps and corrupted records (requires exclusive access)
SharedJournal.Compact("/path/to/myjournal");

API

Type Description
SharedJournal Main entry point — Append, ReadAll, Flush, Compact (static), Dispose
SharedJournalOptions Configuration (FlushMode)
FlushMode None (default) or WriteThrough
JournalAppendResult Offset and total length of appended record
JournalRecord Offset and payload of a read record

Durability

FlushMode Behavior
None Concurrent correctness only; durability depends on OS page cache
WriteThrough Data file opened with FileOptions.WriteThrough

Guarantees (V1)

  • ✅ No two writers write to the same byte range
  • ✅ Readers detect incomplete/corrupt tail records
  • ✅ Multiple processes can append concurrently
  • ✅ Compaction reclaims space from gaps left by crashed writers
  • ✅ Readers automatically fix up gaps with skip markers for faster subsequent reads

Non-guarantees (V1)

  • ❌ No stable global commit order beyond reservation order
  • ❌ No indexing or deletion of individual records
  • ❌ Not a transactional database or queue

Demo

# Run the stress test (4 threads × 10,000 records)
dotnet run --project SharedFileJournal.Demo -- stress

# Other commands
dotnet run --project SharedFileJournal.Demo -- init /tmp/myjournal
dotnet run --project SharedFileJournal.Demo -- write /tmp/myjournal "hello world"
dotnet run --project SharedFileJournal.Demo -- read /tmp/myjournal
dotnet run --project SharedFileJournal.Demo -- compact /tmp/myjournal
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.7 122 3/15/2026
0.1.6 104 3/1/2026
0.1.5 103 3/1/2026
0.1.4 111 3/1/2026
0.1.3 105 3/1/2026
0.1.2 102 3/1/2026
0.1.1 104 3/1/2026
0.1.0 99 3/1/2026