Skip to content

Commit 18d3c5d

Browse files
authored
meta: close grpc clientconn to avoid goroutine leak (pingcap#5)
Signed-off-by: Neil Shen <[email protected]>
1 parent 7430ea6 commit 18d3c5d

File tree

1 file changed

+46
-14
lines changed

1 file changed

+46
-14
lines changed

pkg/meta/meta.go

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http"
99
"net/url"
1010
"strings"
11+
"sync"
1112
"time"
1213

1314
"github.com/pingcap/errors"
@@ -33,7 +34,11 @@ type Backer struct {
3334
addrs []string
3435
cli *http.Client
3536
}
36-
tikvCli tikv.Storage
37+
tikvCli tikv.Storage
38+
backupClis struct {
39+
mu sync.Mutex
40+
clis map[uint64]*grpc.ClientConn
41+
}
3742
}
3843

3944
// NewBacker creates a new Backer.
@@ -51,18 +56,15 @@ func NewBacker(ctx context.Context, pdAddrs string) (*Backer, error) {
5156
return nil, errors.Trace(err)
5257
}
5358

54-
return &Backer{
59+
backer := &Backer{
5560
ctx: ctx,
5661
pdClient: pdClient,
57-
pdHTTP: struct {
58-
addrs []string
59-
cli *http.Client
60-
}{
61-
addrs: addrs,
62-
cli: &http.Client{Timeout: 30 * time.Second},
63-
},
64-
tikvCli: tikvCli.(tikv.Storage),
65-
}, nil
62+
tikvCli: tikvCli.(tikv.Storage),
63+
}
64+
backer.pdHTTP.addrs = addrs
65+
backer.pdHTTP.cli = &http.Client{Timeout: 30 * time.Second}
66+
backer.backupClis.clis = make(map[uint64]*grpc.ClientConn)
67+
return backer, nil
6668
}
6769

6870
// GetClusterVersion returns the current cluster version.
@@ -129,8 +131,16 @@ func (backer *Backer) Context() context.Context {
129131
return backer.ctx
130132
}
131133

132-
// NewBackupClient creates a new backup client.
133-
func (backer *Backer) NewBackupClient(storeID uint64) (backup.BackupClient, error) {
134+
// GetBackupClient get or create a backup client.
135+
func (backer *Backer) GetBackupClient(storeID uint64) (backup.BackupClient, error) {
136+
backer.backupClis.mu.Lock()
137+
defer backer.backupClis.mu.Unlock()
138+
139+
if conn, ok := backer.backupClis.clis[storeID]; ok {
140+
// Find a cached backup client.
141+
return backup.NewBackupClient(conn), nil
142+
}
143+
134144
store, err := backer.pdClient.GetStore(backer.ctx, storeID)
135145
if err != nil {
136146
return nil, errors.Trace(err)
@@ -154,10 +164,27 @@ func (backer *Backer) NewBackupClient(storeID uint64) (backup.BackupClient, erro
154164
if err != nil {
155165
return nil, errors.WithStack(err)
156166
}
167+
// Cache the conn.
168+
backer.backupClis.clis[storeID] = conn
169+
157170
client := backup.NewBackupClient(conn)
158171
return client, nil
159172
}
160173

174+
// ResetBackupClient reset and close cached backup client.
175+
func (backer *Backer) ResetBackupClient(storeID uint64) error {
176+
backer.backupClis.mu.Lock()
177+
defer backer.backupClis.mu.Unlock()
178+
179+
if conn, ok := backer.backupClis.clis[storeID]; ok {
180+
delete(backer.backupClis.clis, storeID)
181+
if err := conn.Close(); err != nil {
182+
return errors.Trace(err)
183+
}
184+
}
185+
return nil
186+
}
187+
161188
// SendBackup send backup request to the given store.
162189
// Stop receiving response if respFn returns error.
163190
func (backer *Backer) SendBackup(
@@ -167,7 +194,7 @@ func (backer *Backer) SendBackup(
167194
respFn func(*backup.BackupResponse) error,
168195
) error {
169196
log.Info("try backup", zap.Any("backup request", req))
170-
client, err := backer.NewBackupClient(storeID)
197+
client, err := backer.GetBackupClient(storeID)
171198
if err != nil {
172199
log.Warn("fail to connect store", zap.Uint64("StoreID", storeID))
173200
return nil
@@ -177,6 +204,11 @@ func (backer *Backer) SendBackup(
177204
bcli, err := client.Backup(ctx, &req)
178205
if err != nil {
179206
log.Warn("fail to create backup", zap.Uint64("StoreID", storeID))
207+
if err1 := backer.ResetBackupClient(storeID); err1 != nil {
208+
log.Warn("fail to reset backup client",
209+
zap.Uint64("StoreID", storeID),
210+
zap.Error(err1))
211+
}
180212
return nil
181213
}
182214
for {

0 commit comments

Comments
 (0)