Durable handles, namespace links and reclamation
This describes the current durable-handle and namespace-link implementation. The local CSI backing filesystem remains the storage authority for physical durability; Raft orders logical namespace and handle state. This change introduces no quota or separate allocation metadata.
An open regular file receives a random 128-bit handle identity. File creation
and its first handle are one committed operation. Existing-file open, lease
renewal, close and expiry are quorum-ordered commands. Reads, writes, metadata
changes, flush and fsync issued through an open descriptor carry that handle and
its stable object identity. An expired, unknown or mismatched handle returns
ESTALE; endpoint switching cannot create a replacement lease implicitly.
A handle lease lasts 90 seconds from the coordinator's committed proposal time.
Each mounted volume renews its active handles every 20 seconds, in at most four
concurrent batches of 128. Each renewal has a 15-second complete-operation
budget. There is one scheduling goroutine per active mount, no goroutine per
open descriptor, at most 512 local open descriptors per mounted volume, and
100,000 durable handle records per volume. Reaching the local bound returns
EMFILE; reaching the server metadata bound returns a capacity error. These are
implementation resource bounds, not filesystem quotas. Normal close removes its
local handle even when its bounded server request fails; the server lease then
expires safely. Successful unmount stops further renewal.
The elected worker checks every 10 seconds for pending handle maintenance and submits through the ordinary quorum path. A mount-owner crash therefore leaves unlinked data protected until its last committed lease expires and a subsequent maintenance command commits. No quorum means no expiry-based physical deletion. A minority never uses its wall clock to remove files independently. Close and reap are intrinsically idempotent and do not consume result-cache slots; ordinary mutations retain the existing immutable retry identity rules. Journal and backing-filesystem failure still prevent acknowledgement of cleanup.
Lease time uses the coordinator's wall clock, clamped by the durable monotonic command-time floor; replay and a regressing coordinator clock cannot resurrect an expired lease. The nodes must have synchronized clocks. A forward clock jump or a mount isolated longer than its lease can make existing descriptors stale, even if the process remains alive. Reopening an existing linked pathname then acquires a new descriptor. An unlinked file cannot be reopened after its final lease expires. Indefinite descriptor survival through a partition is not part of this bounded lease contract.
Unlink and replacement detach the namespace reference. A detached primary object
and its bytes remain while any durable handle or hardlink alias references it.
The final committed close, expiry or namespace unlink removes the retained local
file and object metadata on each applying member. Reclamation is independent of
volume deletion. Derived reference-count indexes make individual reclamation
constant-time and maintenance linear in bounded handle/object state. They are
rebuilt from validated checkpoint state and are never independent authority.
V2 checkpoints preserve handles, symlink targets and hardlink relationships.
Older V2 checkpoints without those optional fields remain readable. New journal
commands carry an optional lifetimeV1 marker; old commands omit it without
changing their checksum. Old-command replay preserves the former unlink
retention rule, including later acknowledged writes made without handle leases.
Only after the authoritative prefix is recovered can a new ordered maintenance
command reclaim those obsolete unlinked objects. Upgrade requires clients to be
quiesced and their old descriptors closed; downgrade and mixed-version active
mounts are not supported.
Relative and absolute symlinks store their target as replicated metadata. The
worker materializes an inert ordinary file, never a host symlink, and rejects
file-data reads/writes/truncation of the symlink object. readlink returns the
stored target and the workload's kernel resolves it within the workload mount
namespace. Names and parent identities still use the ordinary validated
namespace path rules. A target containing .. does not let the worker traverse
its backing filesystem; it is data returned to the workload kernel.
Hardlinks are limited to regular files within one volume. Each alias refers to
one stable primary object and uses an ordinary backing hardlink. Reads, writes,
metadata, handles and inode numbers refer to that same primary object. Logical
nlink counts visible namespace entries, excluding the private retained backing
name. Renaming one name onto another name for the same inode is a no-op, retaining
both names. Directory links, symlink hardlinks and cross-volume links are
rejected. Checkpoints stream primary data once and rebuild aliases afterward.
Metrics replicated_csi_durable_handles, replicated_csi_unlinked_objects and
replicated_csi_reclaimed_objects_total expose current retained state and local
reclamation. Labels contain neither paths nor handle identities. The existing
structured operation logging covers lease operations and cleanup outcomes.
Historical handle-lifetime observations are summarized in the 3.2 staging record. They do not establish a different build's runtime behavior or an availability guarantee. For current mount-owner recovery, follow CSI sessions and the operator runbook.
