copy

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package copy manages the lifecycle of ephemeral database copies.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CopyClient

type CopyClient interface {
	Create(ctx context.Context, opts CreateOptions) (*store.Copy, error)
	Destroy(ctx context.Context, id string) error
	List(ctx context.Context) ([]*store.Copy, error)
}

CopyClient abstracts local (Manager) and remote (HTTPClient) copy operations. Both implementations are used by CLI commands via copyClientFromContext.

type CreateOptions

type CreateOptions struct {
	TTLSeconds int
	RunID      string // optional: identifies the run/session that created this copy
	JobName    string // optional: identifies the job/task within the run
	DumpPath   string // optional: override dump path (local, s3://, http://); empty = use cfg.Dump.Path
	Obfuscate  bool   // apply post-restore obfuscation rules (explicit opt-in)
}

CreateOptions configures a copy creation request.

type HTTPClient

type HTTPClient struct {
	// contains filtered or unexported fields
}

HTTPClient implements CopyClient by talking to a remote ditto server.

func NewHTTPClient

func NewHTTPClient(baseURL, token string) *HTTPClient

NewHTTPClient creates a client. baseURL is e.g. "http://ditto.internal:8080". token is the Bearer auth token; pass "" to skip authentication.

func (*HTTPClient) Create

func (c *HTTPClient) Create(ctx context.Context, opts CreateOptions) (*store.Copy, error)

func (*HTTPClient) Destroy

func (c *HTTPClient) Destroy(ctx context.Context, id string) error

func (*HTTPClient) List

func (c *HTTPClient) List(ctx context.Context) ([]*store.Copy, error)

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager orchestrates the full lifecycle of ephemeral database copies.

func NewManager

func NewManager(
	cfg *config.Config,
	eng engine.Engine,
	copies *store.CopyStore,
	events *store.EventStore,
	ports *PortPool,
	docker *client.Client,
) (*Manager, error)

NewManager creates a Manager from an already-resolved Docker-compatible runtime client.

func (*Manager) Create

func (m *Manager) Create(ctx context.Context, opts CreateOptions) (*store.Copy, error)

Create provisions a new ephemeral database copy. When a pre-warmed copy is available in the pool it is claimed instantly. Otherwise the full slow path (container start + dump restore) is taken.

func (*Manager) Destroy

func (m *Manager) Destroy(ctx context.Context, id string) error

Destroy stops and removes a copy's container and marks it destroyed.

func (*Manager) ExpireOldCopies

func (m *Manager) ExpireOldCopies(ctx context.Context) error

ExpireOldCopies destroys all copies whose TTL has elapsed.

func (*Manager) List

func (m *Manager) List(ctx context.Context) ([]*store.Copy, error)

List returns all copies regardless of status, newest first.

func (*Manager) RecoverOrphans

func (m *Manager) RecoverOrphans(ctx context.Context) error

RecoverOrphans is called at daemon startup. It heals mid-transition records left by a crashed process and removes Docker containers not tracked in SQLite.

func (*Manager) StartPool

func (m *Manager) StartPool(ctx context.Context)

StartPool starts the warm copy pool refiller as a background goroutine. It is a no-op when warm_pool_size is 0.

type PortPool

type PortPool struct {
	// contains filtered or unexported fields
}

PortPool manages a bounded set of host ports for copy containers. Allocate() returns a free port; Release() returns it to the pool. All operations are safe for concurrent use.

func NewPortPool

func NewPortPool(start, end int, occupied []int) *PortPool

NewPortPool creates a pool covering ports [start, end] inclusive. Ports in occupied are pre-marked as in-use (loaded from SQLite at startup).

func (*PortPool) Allocate

func (p *PortPool) Allocate() (int, error)

Allocate returns a free port, marking it as in-use. It scans start-to-end and additionally TCP-dials each candidate to catch externally occupied ports (e.g. orphaned containers from a previous crash).

Returns an error if no port is available.

func (*PortPool) Free

func (p *PortPool) Free() int

Free returns the number of unallocated ports in the pool.

func (*PortPool) InUse

func (p *PortPool) InUse() []int

InUse returns a snapshot of currently allocated ports.

func (*PortPool) Release

func (p *PortPool) Release(port int)

Release marks port as free. It is safe to call Release on a port that was never allocated (no-op).

type WarmPoolRefiller

type WarmPoolRefiller struct {
	// contains filtered or unexported fields
}

WarmPoolRefiller maintains a target number of pre-warmed copies in the pool. When a copy is claimed, Signal() triggers an immediate refill check. A 30-second heartbeat ticker catches any silent drops (e.g. TTL expiry of un-claimed warm copies, which is disabled by ListExpired, but kept as defence).

func NewWarmPoolRefiller

func NewWarmPoolRefiller(mgr *Manager, target int) *WarmPoolRefiller

NewWarmPoolRefiller creates a refiller targeting target warm copies. target=0 means the pool is disabled; Run returns immediately.

func (*WarmPoolRefiller) Run

func (r *WarmPoolRefiller) Run(ctx context.Context)

Run blocks until ctx is cancelled. It refills the pool on each signal and on a 30-second heartbeat. Returns immediately when target == 0.

func (*WarmPoolRefiller) Signal

func (r *WarmPoolRefiller) Signal()

Signal queues a refill check. Non-blocking: if a signal is already pending, this call is a no-op.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL