/
config.go
173 lines (132 loc) · 3.54 KB
/
config.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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package rdbms
import (
"fmt"
"net/url"
"regexp"
"strconv"
"strings"
"time"
)
type (
ConnConfig struct {
DriverName string
DataSourceName string
DBName string
// MaskedDSN is a DSN with sensitive data masked
// each connection is handling that independently
MaskedDSN string
// MaxOpenConns sets maximum number of open connections to the database
// defaults to same value as set in the db/sql
MaxOpenConns int
// ConnMaxLifetime sets the maximum amount of time a connection may be reused
// defaults to same value as set in the db/sql
ConnMaxLifetime time.Duration
// MaxIdleConns sets the maximum number of connections in the idle connection pool
// defaults to same value as set in the db/sql
MaxIdleConns int
// ConnTryPatience sets time window in which we do not complaining about failed connection tries
ConnTryPatience time.Duration
// ConnTryBackoffDelay sets backoff delay after failed try
ConnTryBackoffDelay time.Duration
// ConnTryTimeout sets timeout per try
ConnTryTimeout time.Duration
// ConnTryMax maximum number of retries for getting the connection
ConnTryMax int
}
)
var (
dsnMasker = regexp.MustCompile(`(.)(?:.*)(.):(.)(?:.*)(.)@`)
)
func (c *ConnConfig) SetDefaults() {
if c.MaskedDSN == "" {
c.MaskedDSN = c.DBName + "://********:********@********:********/********"
}
if c.MaxIdleConns == 0 {
// Same as default in the db/sql
c.MaxIdleConns = 32
}
if c.MaxOpenConns == 0 {
// Same as default in the db/sql
c.MaxOpenConns = 256
}
if c.ConnMaxLifetime == 0 {
// Same as default in the db/sql
c.ConnMaxLifetime = 10 * time.Minute
}
// ** ** ** ** ** ** ** ** ** ** ** ** ** **
if c.ConnTryPatience == 0 {
//c.ConnTryPatience = 1 * time.Minute
}
if c.ConnTryBackoffDelay == 0 {
c.ConnTryBackoffDelay = 10 * time.Second
}
if c.ConnTryTimeout == 0 {
c.ConnTryTimeout = 30 * time.Second
}
if c.ConnTryMax == 0 {
c.ConnTryMax = 99
}
}
// ParseExtra parses extra params (params starting with *)
// from DSN's querystring (after ?)
func (c *ConnConfig) ParseExtra() (err error) {
// Make sure we only got qs
const q = "?"
var (
dsn = c.DataSourceName
qs string
)
if pos := strings.LastIndex(dsn, q); pos == -1 {
return nil
} else {
// Trim qs from DSN, we'll re-attach the remaining params
c.DataSourceName, qs = dsn[:pos], dsn[pos+1:]
}
var vv url.Values
if vv, err = url.ParseQuery(qs); err != nil {
return err
}
var (
val string
parseInt = func(s string) (int, error) {
if tmp, err := strconv.ParseInt(s, 10, 32); err != nil {
return 0, err
} else {
return int(tmp), nil
}
}
)
const storePrefixChar = "*"
for key := range vv {
val = vv.Get(key)
if storePrefixChar != key[:1] {
// skip non-store specific config
continue
}
switch key {
case "*connTryPatience":
c.ConnTryPatience, err = time.ParseDuration(val)
case "*connTryBackoffDelay":
c.ConnTryBackoffDelay, err = time.ParseDuration(val)
case "*connTryTimeout":
c.ConnTryTimeout, err = time.ParseDuration(val)
case "*connMaxTries":
c.ConnTryMax, err = parseInt(val)
case "*connMaxOpen":
c.MaxOpenConns, err = parseInt(val)
case "*connMaxLifetime":
c.ConnMaxLifetime, err = time.ParseDuration(val)
case "*connMaxIdle":
c.MaxIdleConns, err = parseInt(val)
default:
err = fmt.Errorf("unknown key %q", key)
}
if err != nil {
return fmt.Errorf("invalid store configuration for key %q: %w", key, err)
}
delete(vv, key)
}
// Encode QS back to DSN
c.DataSourceName += q + vv.Encode()
return nil
}