vm.go (1529 LOC) splits into vm_create, vm_lifecycle, vm_set, vm_stats, vm_disk, vm_authsync; firecracker/DNS/helpers stay in vm.go. guest_sessions.go (1266 LOC) splits into session_controller, session_lifecycle, session_attach, session_stream; scripts and helpers stay in guest_sessions.go. Mechanical move only. No behavior change. Adds doc.go and ARCHITECTURE.md capturing subsystem map and current lock ordering as the baseline for the upcoming subsystem extraction. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
59 lines
2.4 KiB
Markdown
59 lines
2.4 KiB
Markdown
# `internal/daemon` architecture
|
|
|
|
This document captures the current (pre-refactor) layout of the daemon
|
|
package and the lock ordering its callers must respect. It is the baseline
|
|
against which the phased split described in
|
|
`~/.claude/plans/fluffy-seeking-teapot.md` is executed.
|
|
|
|
## Composition
|
|
|
|
`Daemon` is a single struct aggregating state for every subsystem:
|
|
|
|
- Layout, config, store, runner, logger, pid — infrastructure handles.
|
|
- `mu sync.Mutex` — coarse lock, currently guards guest session controller
|
|
map mutations and image registry mutations.
|
|
- `vmLocks sync.Map` — per-VM `*sync.Mutex`, one per VM ID.
|
|
- `createOps`, `createOpsMu` — in-flight `vm create` operations.
|
|
- `imageBuildOps`, `imageBuildOpsMu` — in-flight `image build` operations.
|
|
- `tapPool`, `tapPoolNext`, `tapPoolMu` — TAP interface pool.
|
|
- `sessionControllers` — active guest session controllers (guarded by `mu`).
|
|
- `listener`, `webListener`, `webServer`, `webURL`, `vmDNS` — networking.
|
|
- `vmCaps` — registered VM capability hooks.
|
|
- `imageBuild`, `requestHandler`, `guestWaitForSSH`, `guestDial`,
|
|
`waitForGuestSessionReady` — injectable seams used by tests.
|
|
|
|
## Lock ordering
|
|
|
|
Acquire in this order, release in reverse. Never acquire in the opposite
|
|
direction.
|
|
|
|
```
|
|
vmLocks[id] → mu → {createOpsMu, imageBuildOpsMu, tapPoolMu}
|
|
```
|
|
|
|
Notes:
|
|
|
|
- `vmLocks[id]` is the outer lock for any operation scoped to a single VM.
|
|
Acquired via `withVMLockByID` / `withVMLockByRef`.
|
|
- `mu` is currently load-bearing for both session controller lookups and
|
|
image registry changes. Holding it while calling into guest SSH is
|
|
discouraged; prefer copying needed state out under the lock and releasing
|
|
before blocking I/O.
|
|
- The three subsystem locks (`createOpsMu`, `imageBuildOpsMu`, `tapPoolMu`)
|
|
are leaves. Nothing else is acquired while one is held.
|
|
|
|
The upcoming Phase 2 refactor will retire `mu` entirely by giving each
|
|
concern it currently guards its own owning type and lock. At that point
|
|
the ordering collapses to `vmLocks[id] → subsystem-local lock`.
|
|
|
|
## External API
|
|
|
|
Only `internal/cli` imports this package. The surface is:
|
|
|
|
- `daemon.Open(ctx) (*Daemon, error)`
|
|
- `(*Daemon).Serve(ctx) error`
|
|
- `(*Daemon).Close() error`
|
|
- `daemon.Doctor(...)` — host diagnostics (no receiver).
|
|
|
|
All other `*Daemon` methods are reached only through the RPC `dispatch`
|
|
switch in `daemon.go` and are free to move/rename during refactoring.
|