One VM's metered compute over one wall-clock window: cpu_usec is CPU time
the VM actually executed between window_start and window_end, measured
from its cgroup's cpu.stat by Hyper.Node.FireVMM.Meter.
Append-only: one row per VM per flush window (plus a final row at teardown),
never updated. Windows with zero consumption are not recorded — absence of
rows over a span means no compute happened. Billing reads total/1 (a VM's
lifetime compute) or total/3 (compute over a half-open [from, to) range,
bucketed by window_start so consecutive ranges never double-count).
Stored in the cluster's shared Postgres via Hyper.Img.Db.Repo — usage
rows have no foreign keys so a billing record outlives the VM, its image,
and its lease.
Summary
Functions
Record one usage window. Zero-consumption windows are refused, not stored.
A VM's lifetime metered compute; nil when the VM was never metered.
A VM's metered compute across windows starting in [from, to); nil when
none do. A window straddling to counts whole — usage is bucketed by
window_start, so consecutive ranges never double-count.
Types
@type attrs() :: %{ vm_id: Hyper.Vm.Id.t(), node_id: String.t(), window_start: DateTime.t(), window_end: DateTime.t(), cpu_time: Unit.Time.t() }
Functions
@spec record(attrs()) :: :ok | {:error, Ecto.Changeset.t() | Exception.t()}
Record one usage window. Zero-consumption windows are refused, not stored.
Idempotent on (vm_id, window_start): a retried flush whose earlier attempt
actually committed (the insert succeeded server-side but the client saw an
error) is dropped by the unique index rather than double-billed. DB failures
(connection loss, timeouts) are returned as {:error, exception}, never
raised — the meter's keep-and-retry loop depends on that.
@spec total(Hyper.Vm.Id.t()) :: Unit.Time.t() | nil
A VM's lifetime metered compute; nil when the VM was never metered.
@spec total(Hyper.Vm.Id.t(), DateTime.t(), DateTime.t()) :: Unit.Time.t() | nil
A VM's metered compute across windows starting in [from, to); nil when
none do. A window straddling to counts whole — usage is bucketed by
window_start, so consecutive ranges never double-count.