Class DatabaseRegistry
The machine-local index of databases any Typhon process has opened — %LOCALAPPDATA%\Typhon\databases</code> (#622, design D-7).
public sealed class DatabaseRegistry
- Inheritance
-
DatabaseRegistry
- Inherited Members
Remarks
Discoverability, not correctness. D-8 bounds this deliberately: an index of paths cannot tell you which capture belongs to which database — captures live inside the bundle (D-1) and carry their own identity (D-2). Nothing in the engine or the Workbench may depend on this registry being complete, present or right. It exists so a database created by a game server three directories away can be *found*, and for nothing else.
A directory of small files, not one shared JSON. Several engines starting at once would otherwise contend on a read-modify-write of a single document; here each database owns one file, written whole and atomically. Pruning is a delete, and a file corrupted by a crash or a hand-edit costs its own row rather than the list.
Default-on, with three guards. The asymmetry decides it: a discoverability failure is *silent* — an empty list teaches the user the feature is
useless and they stop looking — while a noisy list is irritating, self-correcting, and at least proves the mechanism works. The guards are
SuppressForProcess (one line per test project), the DisableEnvironmentVariable environment variable, a
DisabledMarkerFileName file in the registry directory, and automatic suppression of anything under the OS temp directory (which covers the
whole test estate without anyone remembering to). The README.txt written beside the entries documents the switches, so whoever finds the index finds
the way to turn it off without reading source.
Every write is best-effort. Opening a database must never fail because a machine-local convenience index could not be updated — an unwritable or
redirected %LOCALAPPDATA% costs the host this feature and nothing else. Same discipline as the profiler's capture destination
(ProfilerBootstrap.ApplyDefaultCaptureDestination).
Constructors
DatabaseRegistry(string)
Creates a registry rooted at directory. Hosts and tests supply their own root; the engine uses EffectiveDirectory.
public DatabaseRegistry(string directory)
Parameters
directorystring
Fields
DisableEnvironmentVariable
Environment variable that turns registration off machine-wide for a process tree. Any of off, 0, false, no.
public const string DisableEnvironmentVariable = "TYPHON_DATABASE_REGISTRY"
Field Value
DisabledMarkerFileName
Name of a file in the registry directory whose mere presence disables registration. The most discoverable switch: it sits with the data.
public const string DisabledMarkerFileName = "disabled"
Field Value
EntryExtension
Extension of an entry file.
public const string EntryExtension = ".json"
Field Value
ReadmeFileName
Name of the self-documenting file written beside the entries.
public const string ReadmeFileName = "README.txt"
Field Value
Properties
DefaultDirectory
%LOCALAPPDATA%\Typhon\databases</code> on Windows, the XDG data-home equivalent on POSIX — the same root the Workbench's bootstrap token already uses.
public static string DefaultDirectory { get; }
Property Value
Directory
The directory this instance reads and writes.
public string Directory { get; }
Property Value
DirectoryOverride
Redirects the registry away from DefaultDirectory. Set by tests and by hosts that keep their state elsewhere.
public static string DirectoryOverride { get; set; }
Property Value
EffectiveDirectory
The directory the engine registers into: DirectoryOverride when set, otherwise DefaultDirectory.
public static string EffectiveDirectory { get; }
Property Value
SuppressForProcess
Turns registration off for this process. One line in a shared test base or [SetUpFixture], inherited by every fixture — the explicit half of
D-7's guards, for suites whose databases do not live under the OS temp directory and so are not caught automatically.
public static bool SuppressForProcess { get; set; }
Property Value
Methods
EnsureReadme()
Writes the self-documenting README.txt if it is absent. This is D-7's "findable without reading source": whoever goes looking for the index
because they are uneasy about it finds the instructions for switching it off sitting next to it.
public void EnsureReadme()
Remarks
Best-effort and atomic, for one reason: two engines starting at once would otherwise both try to write this file, and the loser's Record(string, string, Guid) would fail on a sharing violation — costing a real registration for the sake of a help file. Failing to explain the directory is never worse than failing to populate it.
Forget(string)
Removes one database from the registry. Returns false when it was not there. Never deletes the database itself.
public bool Forget(string bundleDirectory)
Parameters
bundleDirectorystring
Returns
IsEnabled(out string)
Whether this registry accepts registrations, and — when it does not — which switch stopped it.
public bool IsEnabled(out string disabledReason)
Parameters
disabledReasonstringA human-readable sentence naming the responsible switch, or
nullwhen enabled.
Returns
Remarks
The reason is produced here rather than reconstructed by a caller because a UI that renders an empty list for a disabled registry recreates exactly the failure D-7 warns about: the user concludes the feature is useless instead of learning it is switched off. "Off" and "nothing yet" must not look alike.
IsUnderTempDirectory(string)
True when bundleDirectory sits under the OS temp directory. Catches unit tests, POCs and throwaway fixtures automatically, which is
what makes the explicit per-project opt-out a backstop rather than the primary defence.
public static bool IsUnderTempDirectory(string bundleDirectory)
Parameters
bundleDirectorystring
Returns
List()
Every known database, most-recently-opened first, each carrying a freshly-computed Exists.
public IReadOnlyList<DatabaseRegistryEntry> List()
Returns
Remarks
Never throws, and a bad file costs only itself. Containing corruption to one row is the reason D-7 chose a directory of files over a single shared document, so an unparseable entry is skipped and its neighbours are still returned.
PruneMissing()
Drops every entry whose bundle is no longer on disk, returning how many went. Explicit by design — D-7 asks for validate-on-listing and an offer to prune, so List() never deletes anything on its own.
public int PruneMissing()
Returns
Record(string, string, Guid)
Records an open. Returns false when a guard declined it. Preserves FirstSeenUtc from any existing entry.
public bool Record(string bundleDirectory, string databaseName, Guid databaseId)
Parameters
bundleDirectorystringThe database's bundle directory. Normalised to an absolute path before use.
databaseNamestringThe database name.
databaseIdGuidThe database's durable identity.
Returns
Remarks
The entry is written whole, to a process-unique temporary file, then moved over the target — one atomic replace, so a concurrent open of the same database can never produce a half-written row. The two writers then race on the content, which is benign: they are describing the same database and disagree only about which millisecond it was opened.