Files
RenewCMS/internal/infrastructure/persistence/database/dumpBackup.go
T

81 lines
1.7 KiB
Go

package database
import (
domain "RenewCMS/internal/domain/update"
"bufio"
"os"
"time"
)
const (
dumpFileExtension = ".sql"
dumpPartialFileExtension = ".partial"
)
type DumpBackup struct {
open func() (DumpSource, error)
directory string
now func() time.Time
dialect dumpDialect
}
var _ domain.DatabaseBackup = &DumpBackup{}
func NewDumpBackup(open func() (DumpSource, error), directory string, now func() time.Time) *DumpBackup {
return &DumpBackup{open: open, directory: directory, now: now, dialect: mysqlDumpDialect}
}
func (b *DumpBackup) Backup() (string, error) {
target, err := newBackupTarget(b.directory, b.now(), dumpFileExtension)
if err != nil {
return "", err
}
if err := b.writeAtomically(target); err != nil {
return "", err
}
if err := pruneBackups(b.directory, dumpFileExtension); err != nil {
return "", err
}
return target, nil
}
func (b *DumpBackup) writeAtomically(target string) error {
partial := target + dumpPartialFileExtension
if err := b.writePartial(partial); err != nil {
_ = os.Remove(partial)
return err
}
if err := os.Rename(partial, target); err != nil {
_ = os.Remove(partial)
return err
}
return nil
}
func (b *DumpBackup) writePartial(partial string) error {
source, err := b.open()
if err != nil {
return err
}
defer source.Close()
file, err := os.OpenFile(partial, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
if err != nil {
return err
}
buffered := bufio.NewWriter(file)
if err := writeDump(buffered, source, b.dialect); err != nil {
_ = file.Close()
return err
}
if err := buffered.Flush(); err != nil {
_ = file.Close()
return err
}
if err := file.Sync(); err != nil {
_ = file.Close()
return err
}
return file.Close()
}