Class OfflineBundlePageSource
Reads a .typhon bundle directly as bytes: no DatabaseEngine, no page cache, no lock acquisition, no WAL
replay. The page source the checker uses when it matters most — when the database will not open.
public sealed class OfflineBundlePageSource : IPageSource, IDisposable
- Inheritance
-
OfflineBundlePageSource
- Implements
- Inherited Members
Remarks
Booting the engine to inspect a database is self-defeating three ways. It destroys the evidence (on the crash path the rebuild net clears and re-derives indexes, chains, entity maps and occupancy before a caller gets a handle, so a post-open check can only ever verify that rebuild worked). It cannot reach the cases that matter most (an open that fails loudly by design leaves no handle to ask questions through). And it mutates — acquiring the lock, clearing the clean-shutdown flag, replaying the log, checkpointing on close.
Opened FileAccess.Read with FileShare.ReadWrite so a live database can still be scanned; a scan of a
live database yields Suspected cross-structure findings, never
Confirmed ones.
Constructors
OfflineBundlePageSource(string)
Opens a bundle for reading.
public OfflineBundlePageSource(string bundlePath)
Parameters
bundlePathstringPath to the
{name}.typhonbundle directory, or to thedatafile inside one. A path whose extension is missing gets.typhonappended when that directory exists.
Exceptions
- ArgumentNullException
bundlePathisnull.- DirectoryNotFoundException
No bundle directory could be resolved from
bundlePath.- FileNotFoundException
The bundle has no
datafile.
Properties
BundlePath
Absolute path to the bundle directory.
public string BundlePath { get; }
Property Value
LockFilePresent
Whether a db.lock file exists in the bundle.
public bool LockFilePresent { get; }
Property Value
LockHeld
Whether db.lock is held by another process — i.e. a live engine has this database open.
public bool LockHeld { get; }
Property Value
PageCount
Number of pages addressable in this source. Indices [0, PageCount) are in range.
public int PageCount { get; }
Property Value
PagesRead
Pages actually read from disk since this source was opened.
public long PagesRead { get; }
Property Value
Remarks
Exists so a test can assert what a scan costs rather than what it claims to cost. The open-time Spine tier is only affordable as a default because it is bounded by the number of segments rather than the size of the database; that is a property of the I/O it performs, so it has to be measured at the I/O boundary. Asserting it any further up measures the wrong thing.
SizeBytes
Size of the data file in bytes.
public long SizeBytes { get; }
Property Value
TrailingBytes
Bytes past the last whole page. Non-zero means the data file is truncated mid-page — itself a finding, because every write the engine performs is whole-page.
public int TrailingBytes { get; }
Property Value
WalSegments
WAL segment files found in the bundle's wal/ directory, unparsed, ordered by name.
public IReadOnlyList<WalSegmentRef> WalSegments { get; }
Property Value
Methods
Describe()
Human-readable identity of the source, used to anchor findings: a bundle path, a backup id, or "live".
public string Describe()
Returns
Dispose()
public void Dispose()
ResolveBundleDirectory(string)
Resolves a user-supplied path to a bundle directory. Accepts the directory itself, the data file inside it,
or a stem with no extension.
public static string ResolveBundleDirectory(string path)
Parameters
pathstringThe user-supplied path.
Returns
Exceptions
- DirectoryNotFoundException
Nothing resolvable was found.
TryReadPage(int, Span<byte>)
Reads page index into destination.
public bool TryReadPage(int index, Span<byte> destination)
Parameters
Returns
- bool
truewhen the page was read in full;falsewhen it does not exist in this source (out of range, or a hole in a sparse source such as an incremental backup). Afalsereturn is not an error — the caller decides whether an absent page is a finding.