banger/internal/daemon/ARCHITECTURE.md
Thales Maciel ea0db1e17e
Split internal/daemon vm.go and guest_sessions.go by concern
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>
2026-04-15 15:47:08 -03:00

2.4 KiB

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.