forked from wal-g/wal-g
/
backup_push_handler.go
96 lines (83 loc) · 3.3 KB
/
backup_push_handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package sqlserver
import (
"context"
"database/sql"
"fmt"
"os"
"syscall"
"github.com/T0n0T/wal-g/internal/databases/sqlserver/blob"
"github.com/T0n0T/wal-g/internal"
"github.com/T0n0T/wal-g/utility"
"github.com/wal-g/tracelog"
)
func HandleBackupPush(dbnames []string, updateLatest bool) {
ctx, cancel := context.WithCancel(context.Background())
signalHandler := utility.NewSignalHandler(ctx, cancel, []os.Signal{syscall.SIGINT, syscall.SIGTERM})
defer func() { _ = signalHandler.Close() }()
folder, err := internal.ConfigureFolder()
tracelog.ErrorLogger.FatalOnError(err)
db, err := getSQLServerConnection()
tracelog.ErrorLogger.FatalfOnError("failed to connect to SQLServer: %v", err)
dbnames, err = getDatabasesToBackup(db, dbnames)
tracelog.ErrorLogger.FatalOnError(err)
tracelog.ErrorLogger.FatalfOnError("failed to list databases to backup: %v", err)
lock, err := RunOrReuseProxy(ctx, cancel, folder)
tracelog.ErrorLogger.FatalOnError(err)
defer lock.Close()
server, _ := os.Hostname()
timeStart := utility.TimeNowCrossPlatformLocal()
var backupName string
var sentinel *SentinelDto
if updateLatest {
backup, err := internal.GetBackupByName(internal.LatestString, utility.BaseBackupPath, folder)
tracelog.ErrorLogger.FatalfOnError("can't find latest backup: %v", err)
backupName = backup.Name
sentinel = new(SentinelDto)
err = backup.FetchSentinel(sentinel)
tracelog.ErrorLogger.FatalOnError(err)
sentinel.Databases = uniq(append(sentinel.Databases, dbnames...))
} else {
backupName = generateDatabaseBackupName()
sentinel = &SentinelDto{
Server: server,
Databases: dbnames,
StartLocalTime: timeStart,
}
}
builtinCompression := blob.UseBuiltinCompression()
err = runParallel(func(i int) error {
return backupSingleDatabase(ctx, db, backupName, dbnames[i], builtinCompression)
}, len(dbnames), getDBConcurrency())
tracelog.ErrorLogger.FatalfOnError("overall backup failed: %v", err)
if !updateLatest {
sentinel.StopLocalTime = utility.TimeNowCrossPlatformLocal()
}
uploader := internal.NewUploader(nil, folder.GetSubFolder(utility.BaseBackupPath))
tracelog.InfoLogger.Printf("uploading sentinel: %s", sentinel)
err = internal.UploadSentinel(uploader, sentinel, backupName)
tracelog.ErrorLogger.FatalfOnError("failed to save sentinel: %v", err)
tracelog.InfoLogger.Printf("backup finished")
}
func backupSingleDatabase(ctx context.Context, db *sql.DB, backupName string, dbname string, builtinCompression bool) error {
baseURL := getDatabaseBackupURL(backupName, dbname)
size, blobCount, err := estimateDBSize(db, dbname)
if err != nil {
return err
}
tracelog.InfoLogger.Printf("database [%s] size is %d, required blob count %d", dbname, size, blobCount)
urls := buildBackupUrls(baseURL, blobCount)
sql := fmt.Sprintf("BACKUP DATABASE %s TO %s", quoteName(dbname), urls)
sql += fmt.Sprintf(" WITH FORMAT, MAXTRANSFERSIZE=%d", MaxTransferSize)
if builtinCompression {
sql += ", COMPRESSION"
}
tracelog.InfoLogger.Printf("starting backup database [%s] to %s", dbname, urls)
tracelog.DebugLogger.Printf("SQL: %s", sql)
_, err = db.ExecContext(ctx, sql)
if err != nil {
tracelog.ErrorLogger.Printf("database [%s] backup failed: %#v", dbname, err)
} else {
tracelog.InfoLogger.Printf("database [%s] backup successfully finished", dbname)
}
return err
}