forked from wal-g/wal-g
/
backup_sentinel_dto.go
153 lines (130 loc) · 4.85 KB
/
backup_sentinel_dto.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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package greenplum
import (
"encoding/json"
"os"
"time"
"github.com/T0n0T/wal-g/internal/databases/postgres"
"github.com/T0n0T/wal-g/utility"
"github.com/wal-g/tracelog"
"github.com/greenplum-db/gp-common-go-libs/cluster"
)
type SegmentRole string
const MetadataDatetimeFormat = "%Y-%m-%dT%H:%M:%S.%fZ"
const (
Primary SegmentRole = "p"
Mirror SegmentRole = "m"
)
type SegmentMetadata struct {
DatabaseID int `json:"db_id"`
ContentID int `json:"content_id"`
Role SegmentRole `json:"role"`
Port int `json:"port"`
Hostname string `json:"hostname"`
DataDir string `json:"data_dir"`
BackupID string `json:"backup_id"`
BackupName string `json:"backup_name"`
RestorePointLSN string `json:"restore_point_lsn"`
}
func (c SegmentMetadata) ToSegConfig() cluster.SegConfig {
return cluster.SegConfig{
DbID: c.DatabaseID,
ContentID: c.ContentID,
Role: string(c.Role),
Port: c.Port,
Hostname: c.Hostname,
DataDir: c.DataDir,
}
}
func NewSegmentMetadata(backupID string, segCfg cluster.SegConfig, restoreLSN, backupName string) SegmentMetadata {
return SegmentMetadata{
DatabaseID: segCfg.DbID,
ContentID: segCfg.ContentID,
Role: SegmentRole(segCfg.Role),
Port: segCfg.Port,
Hostname: segCfg.Hostname,
DataDir: segCfg.DataDir,
BackupID: backupID,
RestorePointLSN: restoreLSN,
BackupName: backupName,
}
}
// PgSegmentSentinelDto is used during the initial fetching of the segment backup metadata
type PgSegmentSentinelDto struct {
postgres.BackupSentinelDto
BackupName string
}
// BackupSentinelDto describes file structure of json sentinel
type BackupSentinelDto struct {
RestorePoint *string `json:"restore_point,omitempty"`
Segments []SegmentMetadata `json:"segments,omitempty"`
UserData interface{} `json:"user_data,omitempty"`
StartTime time.Time `json:"start_time"`
FinishTime time.Time `json:"finish_time"`
DatetimeFormat string `json:"date_fmt,omitempty"`
Hostname string `json:"hostname"`
GpVersion string `json:"gp_version"`
IsPermanent bool `json:"is_permanent"`
SystemIdentifier *uint64 `json:"system_identifier"`
UncompressedSize int64 `json:"uncompressed_size"`
CompressedSize int64 `json:"compressed_size"`
DataCatalogSize int64 `json:"data_catalog_size"`
IncrementFrom *string `json:"increment_from,omitempty"`
IncrementFullName *string `json:"increment_full_name,omitempty"`
IncrementCount *int `json:"increment_count,omitempty"`
}
func (s *BackupSentinelDto) String() string {
b, err := json.Marshal(s)
if err != nil {
return "-"
}
return string(b)
}
// NewBackupSentinelDto returns new BackupSentinelDto instance
func NewBackupSentinelDto(currBackupInfo CurrBackupInfo, prevBackupInfo *PrevBackupInfo, restoreLSNs map[int]string, userData interface{},
isPermanent bool) BackupSentinelDto {
hostname, err := os.Hostname()
if err != nil {
tracelog.WarningLogger.Printf("Failed to fetch the hostname for metadata, leaving empty: %v", err)
}
sentinel := BackupSentinelDto{
RestorePoint: &currBackupInfo.backupName,
Segments: make([]SegmentMetadata, 0, len(currBackupInfo.segmentBackups)),
UserData: userData,
StartTime: currBackupInfo.startTime,
FinishTime: utility.TimeNowCrossPlatformUTC(),
DatetimeFormat: MetadataDatetimeFormat,
Hostname: hostname,
GpVersion: currBackupInfo.gpVersion.String(),
IsPermanent: isPermanent,
SystemIdentifier: currBackupInfo.systemIdentifier,
}
if prevBackupInfo.name != "" {
sentinel.IncrementCount = &currBackupInfo.incrementCount
sentinel.IncrementFrom = &prevBackupInfo.name
if prevBackupInfo.sentinelDto.IsIncremental() {
sentinel.IncrementFullName = prevBackupInfo.sentinelDto.IncrementFullName
} else {
sentinel.IncrementFullName = &prevBackupInfo.name
}
}
for backupID := range currBackupInfo.segmentsMetadata {
sentinel.CompressedSize += currBackupInfo.segmentsMetadata[backupID].CompressedSize
sentinel.UncompressedSize += currBackupInfo.segmentsMetadata[backupID].UncompressedSize
sentinel.DataCatalogSize += currBackupInfo.segmentsMetadata[backupID].DataCatalogSize
}
for backupID, cfg := range currBackupInfo.segmentBackups {
restoreLSN := restoreLSNs[cfg.ContentID]
backupName := currBackupInfo.segmentsMetadata[backupID].BackupName
sentinel.Segments = append(sentinel.Segments, NewSegmentMetadata(backupID, *cfg, restoreLSN, backupName))
}
return sentinel
}
func (s *BackupSentinelDto) IsIncremental() (isIncremental bool) {
// If we have increment base, we must have all the rest properties.
if s.IncrementFrom != nil {
if s.IncrementFullName == nil || s.IncrementCount == nil {
panic("Inconsistent BackupSentinelDto")
}
}
return s.IncrementFrom != nil
}