Documentation
¶
Overview ¶
Package sqlitedisk replicates SQLite-provider disks from a runner to the coordinator's backup API. It supplies litestream with a ReplicaClient that speaks Miren RPC instead of S3, and a Manager that owns one replicated database per attached disk.
Index ¶
- Constants
- func BackupKey(appID, volumeName string) string
- func EnsureDatabase(path string) error
- type Manager
- type ReplicaClient
- func (c *ReplicaClient) DeleteAll(ctx context.Context) error
- func (c *ReplicaClient) DeleteLTXFiles(ctx context.Context, a []*ltx.FileInfo) error
- func (c *ReplicaClient) Init(ctx context.Context) error
- func (c *ReplicaClient) LTXFiles(ctx context.Context, level int, seek ltx.TXID, useMetadata bool) (ltx.FileIterator, error)
- func (c *ReplicaClient) OpenLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (io.ReadCloser, error)
- func (c *ReplicaClient) SetLogger(logger *slog.Logger)
- func (c *ReplicaClient) Type() string
- func (c *ReplicaClient) WriteLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, rd io.Reader) (*ltx.FileInfo, error)
Constants ¶
const ReplicaClientType = "miren"
ReplicaClientType identifies this backend in litestream's logs.
Variables ¶
This section is empty.
Functions ¶
func BackupKey ¶
BackupKey builds a coordinator backup key for one app's disk.
The coordinator uses the key as a single directory name and rejects anything that is not [a-zA-Z0-9][a-zA-Z0-9._-]*, while app IDs contain a slash and volume names are user-supplied. Sanitizing alone could collide (two distinct inputs mapping to the same safe string), so a digest of the exact input is appended to keep distinct disks distinct.
func EnsureDatabase ¶
EnsureDatabase makes sure a SQLite database exists at path and is in WAL mode, which litestream requires in order to replicate it.
It is safe to call on an existing database: opening it and setting the journal mode it already has is a no-op, so a restored database is left exactly as it was.
Types ¶
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the replicated databases for every SQLite-provider disk attached on this node: one litestream.DB per backup key, each replicating to the coordinator.
A nil *Manager is usable and does nothing. That keeps the runner's wiring simple when the coordinator backup service is unreachable — disks still attach and apps still run, they just are not backed up.
func NewManager ¶
func NewManager(log *slog.Logger, client *sqlitebackup_v1alpha.SqliteBackupClient) *Manager
NewManager returns a Manager replicating through client.
func (*Manager) Close ¶
Close stops replicating every database. Errors are collected so one failing database cannot strand the others still running.
func (*Manager) DeregisterOwner ¶
DeregisterOwner releases everything an owner registered, stopping replication for any database it was the last owner of.
Teardown calls this rather than deriving keys again, because the entities the keys came from may already be deleted. Unknown owners are ignored so teardown can run unconditionally.
func (*Manager) Register ¶
Register attaches owner to the database at dbPath, restoring it from the coordinator first when this node has no copy, and begins replicating it.
Registering a key that is already replicated adds owner to it rather than starting a second replicator: the database keeps replicating until every owner has released it. Re-registering the same owner is a no-op.
Restore happens before replication starts, so a database that exists locally is never overwritten by a backup — EnsureExists only acts on a missing file, and succeeds when there is no backup to restore (a genuinely new disk).
type ReplicaClient ¶
type ReplicaClient struct {
// contains filtered or unexported fields
}
ReplicaClient stores a single database's LTX files on the coordinator.
func NewReplicaClient ¶
func NewReplicaClient(log *slog.Logger, client *sqlitebackup_v1alpha.SqliteBackupClient, key string) *ReplicaClient
NewReplicaClient returns a client that stores files under key.
func (*ReplicaClient) DeleteAll ¶
func (c *ReplicaClient) DeleteAll(ctx context.Context) error
DeleteAll discards every file stored for this database.
func (*ReplicaClient) DeleteLTXFiles ¶
DeleteLTXFiles removes the named files. Files already gone are not an error.
func (*ReplicaClient) Init ¶
func (c *ReplicaClient) Init(ctx context.Context) error
Init is a no-op: the RPC connection is established before the client is built.
func (*ReplicaClient) LTXFiles ¶
func (c *ReplicaClient) LTXFiles(ctx context.Context, level int, seek ltx.TXID, useMetadata bool) (ltx.FileIterator, error)
LTXFiles lists the files stored at a level, starting at seek.
useMetadata is ignored: the coordinator stamps each file's transaction timestamp onto its mtime at write time, so listed timestamps are always the accurate ones and never need a second metadata fetch.
func (*ReplicaClient) OpenLTXFile ¶
func (c *ReplicaClient) OpenLTXFile(ctx context.Context, level int, minTXID, maxTXID ltx.TXID, offset, size int64) (io.ReadCloser, error)
OpenLTXFile streams one file back from the coordinator.
The RPC call pushes bytes into a pipe and only returns once the transfer finishes, so it runs in the background while the caller reads. Peeking a single byte before returning forces a failure that happened before any data was sent — a missing file, most importantly — to surface here rather than on a later Read, because litestream branches on os.IsNotExist at the call site.
func (*ReplicaClient) SetLogger ¶
func (c *ReplicaClient) SetLogger(logger *slog.Logger)
func (*ReplicaClient) Type ¶
func (c *ReplicaClient) Type() string