Documentation
¶
Overview ¶
Package lock is the spec fabric slice for advisory file locking — a host primitive a plugin physically cannot hold (a syscall.Flock over an on-disk lock file). RELOCATED from sdk/kit (#55 fabric-primitive extraction). It carries the heavy syscall dependency in its OWN slice (Rule 2: minimal imports) so a consumer that needs a lock never drags anything else, and a consumer that needs nothing else never drags syscall. charly core inlines from here; sdk/kit re-exports the same symbols so the compiled-in candy/plugin-preempt and other plugin call sites are untouched.
Index ¶
- Variables
- func AcquireFileLock(path string, blocking bool) (release func() error, err error)
- func AcquireFileLockWithin(path string, blocking bool, timeout time.Duration) (release func() error, err error)
- func AcquireImageBuildLock(fullTag string) (func() error, error)
- func AcquireLocalPkgBuildLock(srcDir string) (func() error, error)
- func AcquireVmDomainLock(domain string) (func() error, error)
- func BedVmDomains(name string, node spec.DeployNode) []string
- func ImageBuildLockPath(fullTag string) (string, error)
- func InstallDirAtomic(tmp, final string) error
Constants ¶
This section is empty.
Variables ¶
var ErrLockBusy = errors.New("file lock held by another process")
ErrLockBusy is returned by a NON-blocking AcquireFileLock when another holder already owns the lock. Callers detect it with errors.Is to render a precise "already in progress" message.
Functions ¶
func AcquireFileLock ¶
AcquireFileLock takes an advisory flock on path (creating the file + parent dirs on demand) and returns a release closure that unlocks + closes.
blocking selects the contention behavior:
- true → LOCK_EX: QUEUE until the lock is free — reporting periodically what it is waiting on and failing after lockTimeout with the holder named (bounded, never hangs, never silent).
- false → LOCK_EX|LOCK_NB: return ErrLockBusy immediately when another holder exists.
The lock file is deliberately NOT unlinked on release (unlinking a held lock races a waiter that already opened the prior inode). flock is per-open-file-description, so two acquires of the same path — even within ONE process — contend, which the duplicate-run guard relies on.
func AcquireFileLockWithin ¶ added in v0.2026268.1800
func AcquireFileLockWithin(path string, blocking bool, timeout time.Duration) (release func() error, err error)
AcquireFileLockWithin is AcquireFileLock with an explicit blocking bound (ignored when blocking is false). It exists for a SHORT critical section — a config-file read-modify-write — so a contended acquire fails FAST with a clear message instead of waiting the full 30-minute image-build bound. flock is per-open-file-description, so a same-process contention (two beds in one roster) is detected identically.
func AcquireImageBuildLock ¶
AcquireImageBuildLock takes the blocking per-image build lock for fullTag.
func AcquireLocalPkgBuildLock ¶
AcquireLocalPkgBuildLock serializes concurrent localpkg builds sharing a source dir.
func AcquireVmDomainLock ¶
AcquireVmDomainLock takes a BLOCKING, host-global advisory lock serializing every check bed that occupies the given libvirt domain. Host-global (under ~/.cache/charly/.locks/) because the qemu:///session domain namespace is host-wide, shared across project dirs.
func BedVmDomains ¶
func BedVmDomains(name string, node spec.DeployNode) []string
BedVmDomains returns the sorted, deduped libvirt domain names (charly-<from>) a bed's VM(s) occupy — the bed's own vm target plus any group-member vm targets. This is the unit of exclusive host contention two DISTINCT beds can collide on (the per-domain lock in AcquireVmDomainLock serializes them).
func ImageBuildLockPath ¶
ImageBuildLockPath is the pure per-image build-lock key derivation: the user-cache lock file for an image ref, with the :tag stripped (preserving any registry:port colon) so every CalVer build of one image shares ONE lock — a shared intermediate built COLD once while distinct leaves fan out in parallel. Shared across the module boundary (R3) so charly core's acquireImageBuildLock AND the compiled-in candy/plugin-build DRIVE derive the byte-identical path.
func InstallDirAtomic ¶
InstallDirAtomic atomically installs the freshly-populated tmp directory as final. When final already exists, the two dirs are swapped in a single atomic renameat2(RENAME_EXCHANGE) — a concurrent reader of final always sees a complete dir (the old one before, the new one after) — and the swapped-out old content (now under tmp) is removed. When final is absent, a plain rename installs it. A lost create-race (a concurrent process installed identical content first) is benign: the redundant tmp is discarded. Linux-only (renameat2); the project targets Linux. Relocated from charly core (P8b) so the build render engine and charly's staging primitives share the one primitive.
Types ¶
This section is empty.