Hyper.Node.Img.ThinPool (Hyper v0.1.0)

Copy Markdown View Source

The node's single dm-thin pool. On start it materialises two sparse backing files in scratch_dir (metadata + data), attaches them as writable loop devices, zeroes the metadata (so the kernel treats it as a fresh pool), and creates the hyper-thinpool device-mapper pool.

create_external/3 provisions a thin volume whose unwritten blocks read through to a read-only external origin (the composed image device) and whose writes land in the pool - the per-VM writable rootfs. Thin device ids are a bump pointer plus a freed-id stack, mirroring Hyper.Node.Users.

Summary

Functions

Returns a specification to start this module under a supervisor.

Provision a thin volume of sectors over read-only origin_dev.

Remove thin volume name and free its thin device id.

The provisioned ranges of thin device thin_id, from the pool's own metadata. Because the volume reads through an external origin, provisioned blocks are exactly the blocks ever written — the divergence a fork publish must copy, discovered without scanning the device.

Take an internal snapshot of live thin volume origin_name (thin id origin_id) and activate it as name, sharing the pool's blocks COW-style.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

create_external(name, origin_dev, sectors)

@spec create_external(String.t(), Path.t(), pos_integer()) ::
  {:ok, %{dev: Path.t(), id: non_neg_integer()}} | {:error, term()}

Provision a thin volume of sectors over read-only origin_dev.

destroy(name, id)

@spec destroy(String.t(), non_neg_integer()) :: :ok

Remove thin volume name and free its thin device id.

mappings(thin_id)

@spec mappings(non_neg_integer()) ::
  {:ok, %{block_sectors: pos_integer(), ranges: [[non_neg_integer()]]}}
  | {:error, term()}

The provisioned ranges of thin device thin_id, from the pool's own metadata. Because the volume reads through an external origin, provisioned blocks are exactly the blocks ever written — the divergence a fork publish must copy, discovered without scanning the device.

Reserves the pool's metadata snapshot for the duration of the dump and always releases it (one reserve may exist at a time; this call is serialized by the pool server).

snapshot(name, origin_name, origin_id, sectors, origin_dev)

@spec snapshot(String.t(), String.t(), non_neg_integer(), pos_integer(), Path.t()) ::
  {:ok, %{dev: Path.t(), id: non_neg_integer()}} | {:error, term()}

Take an internal snapshot of live thin volume origin_name (thin id origin_id) and activate it as name, sharing the pool's blocks COW-style.

dm-thin requires the origin suspended while create_snap is sent; the origin is resumed on every path out, so a failed snapshot never leaves the parent VM's I/O frozen. The snapshot is activated with the same external origin (origin_dev) as its parent — unprovisioned reads must keep resolving through the composed RO image chain.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()