forked from wal-g/wal-g
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutility.go
151 lines (131 loc) · 3.18 KB
/
utility.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
package walg
import (
"crypto/md5"
"encoding/hex"
"github.com/aws/aws-sdk-go/service/s3"
"hash"
"io"
"log"
"os"
"path/filepath"
"strconv"
"time"
"encoding/json"
)
// BackupTime is used to sort backups by
// latest modified time.
type BackupTime struct {
Name string
Time time.Time
WalFileName string
}
// TimeSlice represents a backup and its
// last modified time.
type TimeSlice []BackupTime
func (p TimeSlice) Len() int {
return len(p)
}
func (p TimeSlice) Less(i, j int) bool {
return p[i].Time.After(p[j].Time)
}
func (p TimeSlice) Swap(i, j int) {
p[i], p[j] = p[j], p[i]
}
func partition(a []string, b int) [][]string {
c := make([][]string, 0)
for i := 0; i < len(a); i += b {
if i+b > len(a) {
c = append(c, a[i:])
} else {
c = append(c, a[i:i+b])
}
}
return c
}
func partitionObjects(a []*s3.ObjectIdentifier, b int) [][]*s3.ObjectIdentifier {
// I've unsuccessfully tried this with interface{} but there was too much of casting
c := make([][]*s3.ObjectIdentifier, 0)
for i := 0; i < len(a); i += b {
if i+b > len(a) {
c = append(c, a[i:])
} else {
c = append(c, a[i:i+b])
}
}
return c
}
// ResolveSymlink converts path to physical if it is symlink
func ResolveSymlink(path string) string {
resolve, err := filepath.EvalSymlinks(path)
if err != nil {
// TODO: Consider descriptive panic here and other checks
// Directory may be absent et c.
return path
}
return resolve
}
func getMaxDownloadConcurrency(default_value int) int {
return getMaxConcurrency("WALG_DOWNLOAD_CONCURRENCY", default_value)
}
func getMaxUploadConcurrency(default_value int) int {
return getMaxConcurrency("WALG_UPLOAD_CONCURRENCY", default_value)
}
// This setting is intentially undocumented in README. Effectively, this configures how many prepared tar Files there
// may be in uploading state during backup-push.
func getMaxUploadQueue() int {
return getMaxConcurrency("WALG_UPLOAD_QUEUE", 2)
}
// GetSentinelUserData tries to parse WALG_SENTINEL_USER_DATA env variable
func GetSentinelUserData() interface{} {
dataStr, ok := os.LookupEnv("WALG_SENTINEL_USER_DATA")
if !ok || len(dataStr) == 0 {
return nil
}
var out interface{}
err := json.Unmarshal([]byte(dataStr), &out)
if err != nil {
log.Println("WARNING! Unable to parse WALG_SENTINEL_USER_DATA as JSON")
return dataStr
}
return out
}
func getMaxUploadDiskConcurrency() int {
return getMaxConcurrency("WALG_UPLOAD_DISK_CONCURRENCY", 1)
}
func getMaxConcurrency(key string, default_value int) int {
var con int
var err error
conc, ok := os.LookupEnv(key)
if ok {
con, err = strconv.Atoi(conc)
if err != nil {
log.Panic("Unknown concurrency number ", err)
}
} else {
if default_value > 0 {
con = default_value
} else {
con = 10
}
}
return max(con, 1)
}
type md5Reader struct {
internal io.Reader
md5 hash.Hash
}
func newMd5Reader(reader io.Reader) *md5Reader {
return &md5Reader{internal: reader, md5: md5.New()}
}
func (r *md5Reader) Read(p []byte) (n int, err error) {
n, err = r.internal.Read(p)
if err != nil {
return
}
_, err = r.md5.Write(p[:n])
return
}
func (r *md5Reader) Sum() string {
bytes := r.md5.Sum(nil)
return hex.EncodeToString(bytes)
}