Skip to content

Commit 9e35950

Browse files
committed
pump client: support change select pump's strategy (pingcap#221)
1 parent c2d3e78 commit 9e35950

File tree

3 files changed

+94
-70
lines changed

3 files changed

+94
-70
lines changed

tidb-binlog/pump_client/client.go

+40-25
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ var (
6565

6666
// PumpInfos saves pumps' infomations in pumps client.
6767
type PumpInfos struct {
68-
sync.RWMutex
6968
// Pumps saves the map of pump's nodeID and pump status.
7069
Pumps map[string]*PumpStatus
7170

@@ -88,6 +87,8 @@ func NewPumpInfos() *PumpInfos {
8887

8988
// PumpsClient is the client of pumps.
9089
type PumpsClient struct {
90+
sync.RWMutex
91+
9192
ctx context.Context
9293

9394
cancel context.CancelFunc
@@ -123,7 +124,7 @@ type PumpsClient struct {
123124

124125
// NewPumpsClient returns a PumpsClient.
125126
// TODO: get strategy from etcd, and can update strategy in real-time. Use Range as default now.
126-
func NewPumpsClient(etcdURLs string, timeout time.Duration, securityOpt pd.SecurityOption) (*PumpsClient, error) {
127+
func NewPumpsClient(etcdURLs, strategy string, timeout time.Duration, securityOpt pd.SecurityOption) (*PumpsClient, error) {
127128
ectdEndpoints, err := utils.ParseHostPortAddr(etcdURLs)
128129
if err != nil {
129130
return nil, errors.Trace(err)
@@ -154,7 +155,7 @@ func NewPumpsClient(etcdURLs string, timeout time.Duration, securityOpt pd.Secur
154155
ClusterID: clusterID,
155156
EtcdRegistry: node.NewEtcdRegistry(cli, DefaultEtcdTimeout),
156157
Pumps: NewPumpInfos(),
157-
Selector: NewSelector(Range),
158+
Selector: NewSelector(strategy),
158159
BinlogWriteTimeout: timeout,
159160
Security: security,
160161
nodePath: path.Join(node.DefaultRootPath, node.NodePrefix[node.PumpNode]),
@@ -241,14 +242,19 @@ func (c *PumpsClient) getPumpStatus(pctx context.Context) (revision int64, err e
241242

242243
// WriteBinlog writes binlog to a situable pump. Tips: will never return error for commit/rollback binlog.
243244
func (c *PumpsClient) WriteBinlog(binlog *pb.Binlog) error {
245+
c.RLock()
246+
pumpNum := len(c.Pumps.AvaliablePumps)
247+
selector := c.Selector
248+
c.RUnlock()
249+
244250
var choosePump *PumpStatus
245251
meetError := false
246252
defer func() {
247253
if meetError {
248254
c.checkPumpAvaliable()
249255
}
250256

251-
c.Selector.Feedback(binlog.StartTs, binlog.Tp, choosePump)
257+
selector.Feedback(binlog.StartTs, binlog.Tp, choosePump)
252258
}()
253259

254260
commitData, err := binlog.Marshal()
@@ -262,13 +268,9 @@ func (c *PumpsClient) WriteBinlog(binlog *pb.Binlog) error {
262268
var resp *pb.WriteBinlogResp
263269
startTime := time.Now()
264270

265-
c.Pumps.RLock()
266-
pumpNum := len(c.Pumps.AvaliablePumps)
267-
c.Pumps.RUnlock()
268-
269271
for {
270272
if pump == nil || binlog.Tp == pb.BinlogType_Prewrite {
271-
pump = c.Selector.Select(binlog, retryTime)
273+
pump = selector.Select(binlog, retryTime)
272274
}
273275
if pump == nil {
274276
err = ErrNoAvaliablePump
@@ -335,11 +337,11 @@ func (c *PumpsClient) backoffWriteBinlog(req *pb.WriteBinlogReq, binlogType pb.B
335337
}
336338

337339
unAvaliablePumps := make([]*PumpStatus, 0, 3)
338-
c.Pumps.RLock()
340+
c.RLock()
339341
for _, pump := range c.Pumps.UnAvaliablePumps {
340342
unAvaliablePumps = append(unAvaliablePumps, pump)
341343
}
342-
c.Pumps.RUnlock()
344+
c.RUnlock()
343345

344346
var resp *pb.WriteBinlogResp
345347
// send binlog to unavaliable pumps to retry again.
@@ -367,9 +369,9 @@ func (c *PumpsClient) backoffWriteBinlog(req *pb.WriteBinlogReq, binlogType pb.B
367369
}
368370

369371
func (c *PumpsClient) checkPumpAvaliable() {
370-
c.Pumps.RLock()
372+
c.RLock()
371373
allPumps := copyPumps(c.Pumps.Pumps)
372-
c.Pumps.RUnlock()
374+
c.RUnlock()
373375

374376
for _, pump := range allPumps {
375377
if !pump.IsUsable() {
@@ -380,8 +382,8 @@ func (c *PumpsClient) checkPumpAvaliable() {
380382

381383
// setPumpAvaliable set pump's isAvaliable, and modify UnAvaliablePumps or AvaliablePumps.
382384
func (c *PumpsClient) setPumpAvaliable(pump *PumpStatus, avaliable bool) {
383-
c.Pumps.Lock()
384-
defer c.Pumps.Unlock()
385+
c.Lock()
386+
defer c.Unlock()
385387

386388
pump.Reset()
387389

@@ -403,7 +405,7 @@ func (c *PumpsClient) setPumpAvaliable(pump *PumpStatus, avaliable bool) {
403405

404406
// addPump add a new pump.
405407
func (c *PumpsClient) addPump(pump *PumpStatus, updateSelector bool) {
406-
c.Pumps.Lock()
408+
c.Lock()
407409

408410
if pump.IsUsable() {
409411
c.Pumps.AvaliablePumps[pump.NodeID] = pump
@@ -416,13 +418,26 @@ func (c *PumpsClient) addPump(pump *PumpStatus, updateSelector bool) {
416418
c.Selector.SetPumps(copyPumps(c.Pumps.AvaliablePumps))
417419
}
418420

419-
c.Pumps.Unlock()
421+
c.Unlock()
422+
}
423+
424+
// SetSelectStrategy sets the selector's strategy, strategy should be 'range' or 'hash' now.
425+
func (c *PumpsClient) SetSelectStrategy(strategy string) error {
426+
if strategy != Range && strategy != Hash {
427+
return errors.Errorf("strategy %s is not support", strategy)
428+
}
429+
430+
c.Lock()
431+
c.Selector = NewSelector(strategy)
432+
c.Selector.SetPumps(copyPumps(c.Pumps.AvaliablePumps))
433+
c.Unlock()
434+
return nil
420435
}
421436

422437
// updatePump update pump's status, and return whether pump's IsAvaliable should be changed.
423438
func (c *PumpsClient) updatePump(status *node.Status) (pump *PumpStatus, avaliableChanged, avaliable bool) {
424439
var ok bool
425-
c.Pumps.Lock()
440+
c.Lock()
426441
if pump, ok = c.Pumps.Pumps[status.NodeID]; ok {
427442
if pump.Status.State != status.State {
428443
if status.State == node.Online {
@@ -435,29 +450,29 @@ func (c *PumpsClient) updatePump(status *node.Status) (pump *PumpStatus, avaliab
435450
}
436451
pump.Status = *status
437452
}
438-
c.Pumps.Unlock()
453+
c.Unlock()
439454

440455
return
441456
}
442457

443458
// removePump removes a pump, used when pump is offline.
444459
func (c *PumpsClient) removePump(nodeID string) {
445-
c.Pumps.Lock()
460+
c.Lock()
446461
if pump, ok := c.Pumps.Pumps[nodeID]; ok {
447462
pump.Reset()
448463
}
449464
delete(c.Pumps.Pumps, nodeID)
450465
delete(c.Pumps.UnAvaliablePumps, nodeID)
451466
delete(c.Pumps.AvaliablePumps, nodeID)
452467
c.Selector.SetPumps(copyPumps(c.Pumps.AvaliablePumps))
453-
c.Pumps.Unlock()
468+
c.Unlock()
454469
}
455470

456471
// exist returns true if pumps client has pump matched this nodeID.
457472
func (c *PumpsClient) exist(nodeID string) bool {
458-
c.Pumps.RLock()
473+
c.RLock()
459474
_, ok := c.Pumps.Pumps[nodeID]
460-
c.Pumps.RUnlock()
475+
c.RUnlock()
461476
return ok
462477
}
463478

@@ -533,13 +548,13 @@ func (c *PumpsClient) detect() {
533548
needCheckPumps := make([]*PumpStatus, 0, len(c.Pumps.UnAvaliablePumps))
534549
checkPassPumps := make([]*PumpStatus, 0, 1)
535550
req := &pb.WriteBinlogReq{ClusterID: c.ClusterID, Payload: nil}
536-
c.Pumps.RLock()
551+
c.RLock()
537552
for _, pump := range c.Pumps.UnAvaliablePumps {
538553
if pump.IsUsable() {
539554
needCheckPumps = append(needCheckPumps, pump)
540555
}
541556
}
542-
c.Pumps.RUnlock()
557+
c.RUnlock()
543558

544559
for _, pump := range needCheckPumps {
545560
_, err := pump.WriteBinlog(req, c.BinlogWriteTimeout)

tidb-binlog/pump_client/client_test.go

+22-5
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,16 @@ var _ = Suite(&testClientSuite{})
5050
type testClientSuite struct{}
5151

5252
func (t *testClientSuite) TestSelector(c *C) {
53-
algorithms := []string{Hash, Range}
54-
for _, algorithm := range algorithms {
55-
t.testSelector(c, algorithm)
53+
strategys := []string{Hash, Range}
54+
for _, strategy := range strategys {
55+
t.testSelector(c, strategy)
5656
}
5757
}
5858

59-
func (*testClientSuite) testSelector(c *C, algorithm string) {
59+
func (*testClientSuite) testSelector(c *C, strategy string) {
6060
pumpsClient := &PumpsClient{
6161
Pumps: NewPumpInfos(),
62-
Selector: NewSelector(algorithm),
62+
Selector: NewSelector(strategy),
6363
BinlogWriteTimeout: DefaultBinlogWriteTimeout,
6464
}
6565

@@ -139,6 +139,23 @@ func (*testClientSuite) testSelector(c *C, algorithm string) {
139139
// prewrite binlog and commit binlog with same start ts should choose same pump
140140
c.Assert(pump1.NodeID, Equals, pump2.NodeID)
141141
pumpsClient.setPumpAvaliable(pump1, true)
142+
143+
// after change strategy, prewrite binlog and commit binlog will choose same pump
144+
pump1 = pumpsClient.Selector.Select(prewriteBinlog, 0)
145+
pumpsClient.Selector.Feedback(prewriteBinlog.StartTs, prewriteBinlog.Tp, pump1)
146+
if strategy == Range {
147+
err := pumpsClient.SetSelectStrategy(Hash)
148+
c.Assert(err, IsNil)
149+
} else {
150+
err := pumpsClient.SetSelectStrategy(Range)
151+
c.Assert(err, IsNil)
152+
}
153+
pump2 = pumpsClient.Selector.Select(commitBinlog, 0)
154+
c.Assert(pump1.NodeID, Equals, pump2.NodeID)
155+
156+
// set back
157+
err := pumpsClient.SetSelectStrategy(strategy)
158+
c.Assert(err, IsNil)
142159
}
143160
}
144161

0 commit comments

Comments
 (0)