Documentation
¶
Overview ¶
Package pool is a copy-on-write, pooled block-volume manager — a small, ZFS-inspired alternative to LVM thin provisioning.
A pool owns a flat array of fixed-size physical blocks backed by a single file. Volumes are logical block devices carved out of the pool; each keeps a logical→physical block map. Writes are copy-on-write: overwriting a block that is shared with a snapshot allocates a fresh physical block, so the snapshot's data is never disturbed.
The defining property — and the reason it is not LVM — is failure behaviour: a snapshot is immutable (its blocks are reference-counted and never rewritten), so it can never be corrupted by the live volume filling up. When the pool runs out of free blocks, a copy-on-write write fails *cleanly* with ErrPoolFull, atomically, before any on-disk state changes. The caller (or a filesystem mounted on the volume) sees a normal ENOSPC/EIO rather than silent corruption.
Any block-device consumer can sit on a Volume: it implements ReadAt, WriteAt, Sync, Size, Truncate and Close, the same shape the go-filesystems ext4/xfs drivers accept as a BlockBackend.
Index ¶
- Variables
- type Backing
- type Pool
- func (p *Pool) Capacity() (free, total uint32)
- func (p *Pool) Clone(src, clone string) (*Volume, error)
- func (p *Pool) Close() error
- func (p *Pool) CreateVolume(name string, sizeBytes int64) (*Volume, error)
- func (p *Pool) ImportRaw(name string, r io.ReaderAt, size int64) (*Volume, error)
- func (p *Pool) ImportRawFile(name, path string) (*Volume, error)
- func (p *Pool) OpenVolume(name string) (*Volume, error)
- func (p *Pool) Snapshot(src, snap string) (*Volume, error)
- func (p *Pool) Sync() error
- func (p *Pool) Volumes() []string
- type Volume
- func (v *Volume) Close() error
- func (v *Volume) ExportRaw(w io.WriterAt) error
- func (v *Volume) ExportRawFile(path string) error
- func (v *Volume) Name() string
- func (v *Volume) ReadAt(b []byte, off int64) (int, error)
- func (v *Volume) ReadOnly() bool
- func (v *Volume) Size() (int64, error)
- func (v *Volume) Sync() error
- func (v *Volume) Truncate(size int64) error
- func (v *Volume) WriteAt(b []byte, off int64) (int, error)
Constants ¶
This section is empty.
Variables ¶
var ( // ErrPoolFull is returned by a write that needs to allocate a physical // block when none are free. The write makes no on-disk change, so // snapshots and already-written data stay intact. ErrPoolFull = errors.New("pool: no free blocks (pool full)") // ErrBadMagic is returned when opening a file that is not a pool. ErrBadMagic = errors.New("pool: bad magic") // ErrUnsupportedVersion is returned for an unknown on-disk version. ErrUnsupportedVersion = errors.New("pool: unsupported version") // ErrNotFound is returned when a named volume/snapshot does not exist. ErrNotFound = errors.New("pool: volume not found") // ErrExists is returned when creating a volume/snapshot whose name is taken. ErrExists = errors.New("pool: name already exists") // ErrReadOnly is returned by writes to a snapshot or a read-only volume. ErrReadOnly = errors.New("pool: volume is read-only") // ErrCorrupt is returned when on-disk metadata fails a sanity check. ErrCorrupt = errors.New("pool: corrupt metadata") )
Functions ¶
This section is empty.
Types ¶
type Backing ¶
type Backing interface {
io.ReaderAt // ReadAt(p []byte, off int64) (n int, err error)
io.WriterAt // WriteAt(p []byte, off int64) (n int, err error)
// Truncate sets the store's size in bytes (growing reserves space, the way
// Create reserves the data region; shrinking discards the tail).
Truncate(size int64) error
// Sync durably commits buffered writes.
Sync() error
io.Closer // Close releases the store.
}
Backing is the physical byte store a Pool's data and metadata live on: a single local file today, an S3-backed chunk store or an NBD export tomorrow. The copy-on-write volume engine is identical regardless of where the bytes physically reside — only the Backing changes.
*os.File satisfies Backing directly, so the file-backed Create / Open paths need no adapter. To run a pool on a different store, implement Backing and open the pool with CreateWith / OpenWith.
type Pool ¶
type Pool struct {
// contains filtered or unexported fields
}
Pool is an open copy-on-write block pool backed by a single file.
On-disk layout:
[0, blockSize) header [blockSize, blockSize+N*BS) data region: N physical blocks [metaOffset, metaOffset+metaLen) gob-encoded metadata (refcounts + volumes)
The data region is fixed; metadata is rewritten after the data region on every Sync (its offset/length live in the header).
func Create ¶
Create makes a new pool at path with room for capacityBytes of data, rounded down to whole blocks. An existing file is overwritten.
func CreateBlock ¶
CreateBlock is Create with an explicit block size (power of two ≥ 512).
func CreateWith ¶
CreateWith makes a new pool on an arbitrary Backing — a memory buffer, an S3-backed chunk store, an NBD export — rather than a local file. The backing is assumed empty; CreateWith reserves the data region on it. On success the pool owns the backing and Pool.Close closes it; on error the caller keeps ownership of b.
func OpenWith ¶
OpenWith opens an existing pool that lives on an arbitrary Backing. On success the pool owns the backing and Pool.Close closes it; on error the caller keeps ownership of b.
func (*Pool) Clone ¶
Clone creates a new *writable* volume that shares src's blocks copy-on-write (an instant, space-shared branch — ZFS-style). Writes to the clone or to src diverge independently. src is typically a snapshot, but any volume works.
func (*Pool) CreateVolume ¶
CreateVolume creates a new, empty (all-holes) volume of sizeBytes.
func (*Pool) ImportRaw ¶
ImportRaw creates a new volume named `name` of the given size and populates it from the raw image r. All-zero blocks are left unallocated (holes), so a sparse or zero-padded raw image imports thinly. Useful to bring a raw image (e.g. one a vz guest wrote to) back under pool management — snapshot it afterwards to capture a point in time.
func (*Pool) ImportRawFile ¶
ImportRawFile is ImportRaw reading from a file at path.
func (*Pool) OpenVolume ¶
OpenVolume returns a handle to an existing volume or snapshot.
type Volume ¶
type Volume struct {
// contains filtered or unexported fields
}
Volume is a logical block device carved out of a Pool. It implements the block-backend shape (ReadAt, WriteAt, Sync, Size, Truncate, Close) that the go-filesystems ext4/xfs drivers accept, so a filesystem can be formatted and mounted directly on it.
func (*Volume) Close ¶
Close is a no-op for a volume handle; the pool owns the file. Sync the pool (or Close it) to persist.
func (*Volume) ExportRaw ¶
ExportRaw writes the volume's logical contents to w as a flat ("raw") image. Only allocated blocks are written; unallocated (hole) blocks are skipped, so when w is a freshly-truncated file the result is a sparse raw image. This is the bridge to consumers that only accept raw files — e.g. Apple's Virtualization.framework (vz), which attaches raw disk images at the kernel level and cannot call a Go block backend. Clone a golden volume, ExportRaw the clone, hand the raw file to vz; ImportRaw the modified file back to capture changes.
func (*Volume) ExportRawFile ¶
ExportRawFile writes the volume to a sparse raw file at path (overwriting it), truncated to the volume's logical size. The file is suitable to attach to a VM that requires raw images.
func (*Volume) ReadAt ¶
ReadAt reads len(b) bytes at byte offset off. Unallocated regions read as zeros (sparse).
func (*Volume) Truncate ¶
Truncate is accepted for block-backend compatibility but the volume size is fixed at creation; growing/shrinking is not supported in this version.