handle-lifetime

Durable handles, namespace links and reclamation

Documentation home

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.