Why wrap external tools when you can BE the tool? New physical backup engines: • MySQL Clone Plugin - native 8.0.17+ physical backup • Filesystem Snapshots - LVM/ZFS/Btrfs orchestration • Binlog Streaming - continuous backup with seconds RPO • Parallel Cloud Upload - stream directly to S3, skip local disk Smart engine selection automatically picks the optimal strategy based on: - MySQL version and edition - Available filesystem features - Database size - Cloud connectivity Zero external dependencies. Single binary. Enterprise capabilities. Commercial backup vendors: we need to talk.
139 lines
3.8 KiB
Go
139 lines
3.8 KiB
Go
package snapshot
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// Backend is the interface for snapshot-capable filesystems
|
|
type Backend interface {
|
|
// Name returns the backend name (e.g., "lvm", "zfs", "btrfs")
|
|
Name() string
|
|
|
|
// Detect checks if this backend is available for the given path
|
|
Detect(dataDir string) (bool, error)
|
|
|
|
// CreateSnapshot creates a new snapshot
|
|
CreateSnapshot(ctx context.Context, opts SnapshotOptions) (*Snapshot, error)
|
|
|
|
// MountSnapshot mounts a snapshot at the given path
|
|
MountSnapshot(ctx context.Context, snap *Snapshot, mountPoint string) error
|
|
|
|
// UnmountSnapshot unmounts a snapshot
|
|
UnmountSnapshot(ctx context.Context, snap *Snapshot) error
|
|
|
|
// RemoveSnapshot deletes a snapshot
|
|
RemoveSnapshot(ctx context.Context, snap *Snapshot) error
|
|
|
|
// GetSnapshotSize returns the actual size of snapshot data (COW data)
|
|
GetSnapshotSize(ctx context.Context, snap *Snapshot) (int64, error)
|
|
|
|
// ListSnapshots lists all snapshots
|
|
ListSnapshots(ctx context.Context) ([]*Snapshot, error)
|
|
}
|
|
|
|
// Snapshot represents a filesystem snapshot
|
|
type Snapshot struct {
|
|
ID string // Unique identifier (e.g., LV name, ZFS snapshot name)
|
|
Backend string // "lvm", "zfs", "btrfs"
|
|
Source string // Original path/volume
|
|
Name string // Snapshot name
|
|
MountPoint string // Where it's mounted (if mounted)
|
|
CreatedAt time.Time // Creation time
|
|
Size int64 // Actual size (COW data)
|
|
Metadata map[string]string // Additional backend-specific metadata
|
|
}
|
|
|
|
// SnapshotOptions contains options for creating a snapshot
|
|
type SnapshotOptions struct {
|
|
Name string // Snapshot name (auto-generated if empty)
|
|
Size string // For LVM: COW space size (e.g., "10G")
|
|
ReadOnly bool // Create as read-only
|
|
Sync bool // Sync filesystem before snapshot
|
|
}
|
|
|
|
// Config contains configuration for snapshot backups
|
|
type Config struct {
|
|
// Filesystem type (auto-detect if not set)
|
|
Filesystem string // "auto", "lvm", "zfs", "btrfs"
|
|
|
|
// MySQL data directory
|
|
DataDir string
|
|
|
|
// LVM specific
|
|
LVM *LVMConfig
|
|
|
|
// ZFS specific
|
|
ZFS *ZFSConfig
|
|
|
|
// Btrfs specific
|
|
Btrfs *BtrfsConfig
|
|
|
|
// Post-snapshot handling
|
|
MountPoint string // Where to mount the snapshot
|
|
Compress bool // Compress when streaming
|
|
Threads int // Parallel compression threads
|
|
|
|
// Cleanup
|
|
AutoRemoveSnapshot bool // Remove snapshot after backup
|
|
}
|
|
|
|
// LVMConfig contains LVM-specific settings
|
|
type LVMConfig struct {
|
|
VolumeGroup string // Volume group name
|
|
LogicalVolume string // Logical volume name
|
|
SnapshotSize string // Size for COW space (e.g., "10G")
|
|
}
|
|
|
|
// ZFSConfig contains ZFS-specific settings
|
|
type ZFSConfig struct {
|
|
Dataset string // ZFS dataset name
|
|
}
|
|
|
|
// BtrfsConfig contains Btrfs-specific settings
|
|
type BtrfsConfig struct {
|
|
Subvolume string // Subvolume path
|
|
SnapshotPath string // Where to create snapshots
|
|
}
|
|
|
|
// BinlogPosition represents MySQL binlog position at snapshot time
|
|
type BinlogPosition struct {
|
|
File string
|
|
Position int64
|
|
GTID string
|
|
}
|
|
|
|
// DetectBackend auto-detects the filesystem backend for a given path
|
|
func DetectBackend(dataDir string) (Backend, error) {
|
|
// Try each backend in order of preference
|
|
backends := []Backend{
|
|
NewZFSBackend(nil),
|
|
NewLVMBackend(nil),
|
|
NewBtrfsBackend(nil),
|
|
}
|
|
|
|
for _, backend := range backends {
|
|
detected, err := backend.Detect(dataDir)
|
|
if err == nil && detected {
|
|
return backend, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("no supported snapshot filesystem detected for %s", dataDir)
|
|
}
|
|
|
|
// FormatSize returns human-readable size
|
|
func FormatSize(bytes int64) string {
|
|
const unit = 1024
|
|
if bytes < unit {
|
|
return fmt.Sprintf("%d B", bytes)
|
|
}
|
|
div, exp := int64(unit), 0
|
|
for n := bytes / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
|
|
}
|