Documentation
¶
Overview ¶
Package storelayout is the single authority for xolu's on-disk directory layout. Every database file, timeseries directory, and blob directory is derived from one configurable input — the base directory — by fixed invariants, in the same spirit as the per-tenant table-naming invariants one level up. No other package composes data paths by hand.
The layout is tenant-first: everything belonging to one tenant lives under that tenant's own directory, subdivided by role.
<base>/
t0000/ tenant 0 (unscoped / single-tenant mode)
store/xolu.db primary entity store (SQLite today)
ts/ timeseries store (Pebble today)
blobs/ blob store
t0001/ first registered tenant
store/xolu.db
ts/
blobs/
...
shared/ shared-tenancy mode (all tenants in one store file)
store/xolu.db
ts/
blobs/
dynconfig.json server-level config (not tenant data)
schema/ server-level entity schemas
Design rules:
- The base directory is the ONLY configurable path. Everything below it is derived; there are no per-file or per-role path overrides.
- Role directory names ("store", "ts", "blobs") describe the role, not the engine, so a future backend change does not change the layout contract.
- Tenant 0 is a tenant like any other: it gets the directory "t0000". It is never special-cased to the base root.
- Shared-tenancy mode is not a tenant; it gets its own segment, "shared", with the same internal shape as a tenant directory.
Index ¶
- Constants
- func BlobsDir(base string) stringdeprecated
- func DynConfigPath(base string) string
- func ParseTenantSegment(name string) (tenantID tenant.TenantID, ok bool)
- func SchemaDir(base string) string
- func SharedBlobDir(base string) string
- func SharedCalDir(base string) string
- func SharedRoot(base string) string
- func SharedStoreDir(base string) string
- func SharedStorePath(base string) string
- func SharedTSDir(base string) string
- func TenantBalRollupDir(base string, tenantID tenant.TenantID) string
- func TenantBlobDir(base string, tenantID tenant.TenantID) string
- func TenantCalDir(base string, tenantID tenant.TenantID) string
- func TenantLocDir(base string, tenantID tenant.TenantID) string
- func TenantObjDir(base string, tenantID tenant.TenantID) string
- func TenantRoot(base string, tenantID tenant.TenantID) string
- func TenantSegment(tenantID tenant.TenantID) string
- func TenantStoreDir(base string, tenantID tenant.TenantID) string
- func TenantStorePath(base string, tenantID tenant.TenantID) string
- func TenantTSDir(base string, tenantID tenant.TenantID) string
- type Issue
- type LegacyFinding
- type Model
- type RoleDir
- type Severity
- type TenantDir
Constants ¶
const ( // StoreFile is the SQLite database filename within a store/ directory. // It is the same in every tenant and in shared mode; tenants are // distinguished by their directory, not by the filename. StoreFile = "xolu.db" // DynConfigFileName is the server-level dynamic-config file, at the base root. DynConfigFileName = "dynconfig.json" // SchemaDirName is the server-level schema directory, at the base root. SchemaDirName = "schema" // BlobsDirName is the role-directory name for blobs. Blobs are a per-tenant // role (see TenantBlobDir: <base>/tXXXX/blobs); this constant names that // role directory. It is the same string as roleBlobs and retained for any // external reference to the blob directory name. BlobsDirName = "blobs" )
Fixed filenames within a role directory.
Variables ¶
This section is empty.
Functions ¶
func DynConfigPath ¶
DynConfigPath returns the server-level dynamic-config file: <base>/dynconfig.json. This is server data, not tenant data, so it lives at the base root, a sibling of the tenant directories.
func ParseTenantSegment ¶
ParseTenantSegment parses a directory name of the form "tXXXX" (uppercase hex, four digits) back into a tenant id. It returns ok=false for any name that is not a well-formed tenant segment. "shared" is not a tenant segment and returns ok=false. Note that "t0000" parses to tenant 0 with ok=true — callers that scan tenant directories must decide for themselves whether to include tenant 0.
func SchemaDir ¶
SchemaDir returns the server-level schema directory: <base>/schema. This is server data, not tenant data, so it lives at the base root.
func SharedBlobDir ¶
SharedBlobDir returns the shared-segment blob directory: <base>/shared/blobs. Defined for symmetry with SharedStoreDir/SharedTSDir; the blob plane, like the timeseries plane, uses per-tenant directories (TenantBlobDir) and does not consume this.
func SharedCalDir ¶
SharedCalDir returns the shared-mode scheduling (cal) directory: <base>/shared/cal.
func SharedRoot ¶
SharedRoot returns the directory holding the shared-tenancy store: <base>/shared. It has the same internal shape as a tenant root.
func SharedStoreDir ¶
SharedStoreDir returns the shared-mode primary-store directory: <base>/shared/store.
func SharedStorePath ¶
SharedStorePath returns the shared-mode SQLite database file: <base>/shared/store/xolu.db.
func SharedTSDir ¶
SharedTSDir returns the shared-mode timeseries directory: <base>/shared/ts.
func TenantBalRollupDir ¶ added in v0.26.0
TenantBalRollupDir returns the per-tenant bal rollup-cascade directory: <base>/tXXXX/bal_rollup. This is bal's derived rollup plane (T-62: moved off SQLite, since no guard ever reads it — @C04a, confirmed against the admission guard's own query). The authoritative journal and the checkpoints table (which the write path updates in-transaction, T-58) remain in the tenant's primary store. Analogous to TenantCalDir's H1/H3 split.
func TenantBlobDir ¶
TenantBlobDir returns the per-tenant blob directory: <base>/tXXXX/blobs. This is the tenant-first blob layout, analogous to TenantTSDir: one blob directory per tenant, keyed by ID, tenant 0 included.
func TenantCalDir ¶
TenantCalDir returns the per-tenant scheduling (cal) directory: <base>/tXXXX/cal. This is the cal occupancy index (the derived Pebble bitmap, H3); the authoritative booking record (H1) lives in the tenant's primary store (TenantStorePath). Analogous to TenantTSDir.
func TenantLocDir ¶ added in v0.26.0
TenantLocDir returns the per-tenant loc directory: <base>/tXXXX/loc. loc's own tables (locations, fences, capacity, journal) live here as their own SQLite file, not folded into the tenant's primary store — the same reasoning ts already applies with its own directory (T-115, wave 9, loc-02-implementation.md Stage 0). Unlike TenantBalRollupDir, this is not a derived plane: loc has no Pebble-plane source of truth at all, canonical state is SQL throughout (loc-00-design.md §6a), mirroring bal's own shape, not cal's or ts's.
func TenantObjDir ¶ added in v0.26.0
TenantObjDir returns the per-tenant obj directory: <base>/tXXXX/obj. obj's own tables (subjects, position, containment edges, journal) live here as their own SQLite file, the identical reasoning TenantLocDir already documents — canonical state is SQL throughout (obj-00-design.md §4, mirroring bal's shape per obj-02-implementation.md's own Principles section), no Pebble-plane source of truth to derive from.
func TenantRoot ¶
TenantRoot returns the directory holding all of one tenant's data: <base>/tXXXX. Every role directory (store, ts, blobs) lives beneath it.
func TenantSegment ¶
TenantSegment returns the directory-name segment for a tenant.
Unlike the older tenant.StorageDirSegment, tenant 0 is NOT special-cased to an empty segment: it returns "t0000", so tenant 0 gets its own directory like any other tenant. The format is "tXXXX" with uppercase hex, four digits, matching the historical format so that directory scans that parse the segment back (see ParseTenantSegment) continue to work.
Delegates to tenant.TenantDirName (added 2026-07-28) rather than reimplementing the encoding here — this package's own doc comment already named the intent ("in the same spirit as" pkg/tenant's invariants); this makes that literal rather than aspirational.
func TenantStoreDir ¶
TenantStoreDir returns the per-tenant primary-store directory: <base>/tXXXX/store.
func TenantStorePath ¶
TenantStorePath returns the per-tenant SQLite database file: <base>/tXXXX/store/xolu.db.
Types ¶
type Issue ¶
type Issue struct {
Severity Severity
Path string // the offending path, relative to BaseDir where meaningful
Message string
}
Issue is a single conformance problem found by Check.
func Check ¶
Check validates a scanned Model against the invariant directory structure and returns every conformance problem found. The policy is strict: anything that is not exactly what the invariant permits is a Violation. An empty result means the structure conforms.
Check is "pass 1": it validates the directory structure that storelayout owns, which is universal across all storage backends — the tree from the base down to and including each role directory. It deliberately renders NO verdict on the contents of a role directory. Everything beneath store/ and ts/ — files, nested subdirectories, and the backend's anchor file — is owned by the storage backend that occupies that role, not by storelayout. File-level conformance is "pass 2", delegated to the backend (which, holding its own configuration, is the only component that can say what files it expects).
The structural rules enforced:
- Immediate children of the base may only be: tenant directories ("tXXXX"), the shared directory ("shared"), the schema directory, and the dynconfig file. Anything else (a stray file — including a misplaced store file — or a stray directory such as a leftover "sql"/"ts") is a violation.
- Within a tenant or shared directory, only the role directories store, ts, blobs may appear, and only as directories. Any other entry is a violation.
- The contents of a role directory are out of scope here (see pass 2).
type LegacyFinding ¶
type LegacyFinding struct {
Path string // path relative to the base directory
Message string // what it is and why it blocks startup
}
LegacyFinding describes one detected pre-normalization data location.
func DetectLegacy ¶
func DetectLegacy(m Model) []LegacyFinding
DetectLegacy returns findings for any pre-normalization data locations present in the model. An empty result means no legacy layout was detected (the directory is either empty, freshly created, or already conforms). A non-empty result means the caller is looking at data written by an older xolu and should refuse to start rather than create fresh stores alongside it.
Detection is conservative: it reports a legacy location only when the old directory/file is actually present, so a clean or new-layout directory never trips it.
func (LegacyFinding) String ¶
func (f LegacyFinding) String() string
type Model ¶
type Model struct {
BaseDir string
// Tenants holds every immediate subdirectory of BaseDir that looks like it
// is meant to be a tenant or shared directory (i.e. is itself a directory),
// whether or not its name is valid. Check decides validity.
Tenants []TenantDir
// RootFiles holds immediate non-directory entries directly under BaseDir
// (e.g. "dynconfig.json", or an out-of-place "xolu.db").
RootFiles []string
// RootDirs holds immediate subdirectory names directly under BaseDir that
// are NOT tenant/shared directories captured in Tenants — e.g. "schema",
// or an out-of-place "sql"/"ts". (schema is valid; others are violations.)
RootDirs []string
}
Model is the complete in-memory description of a scanned base directory.
type RoleDir ¶
type RoleDir struct {
Name string // the role directory name as found on disk
Entries []string // immediate child entry names (files and dirs)
}
RoleDir describes one role subdirectory (store or ts) found within a tenant or shared directory.
type Severity ¶
type Severity int
Severity is the classification of an Issue. The current policy is strict and binary: every problem is a Violation. The type exists so that callers can branch on severity without assuming there is only one kind.
type TenantDir ¶
type TenantDir struct {
Segment string // directory name as found on disk, e.g. "t0001", "shared", or something invalid
Roles []RoleDir // role subdirectories found within
Extra []string // non-directory or unexpected immediate entries directly under the segment
}
TenantDir describes one tenant (or shared) directory found under the base.