github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/einsteindb/client_collapse.go (about)

     1  // Copyright 2020 WHTCORPS INC, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package einsteindb provides tcp connection to ekvserver.
    15  package einsteindb
    16  
    17  import (
    18  	"context"
    19  	"strconv"
    20  	"time"
    21  
    22  	"github.com/whtcorpsinc/errors"
    23  	"github.com/whtcorpsinc/milevadb/causetstore/einsteindb/einsteindbrpc"
    24  	"golang.org/x/sync/singleflight"
    25  )
    26  
    27  var _ Client = reqDefCauslapse{}
    28  
    29  var resolveRegionSf singleflight.Group
    30  
    31  type reqDefCauslapse struct {
    32  	Client
    33  }
    34  
    35  func (r reqDefCauslapse) Close() error {
    36  	if r.Client == nil {
    37  		panic("client should not be nil")
    38  	}
    39  	return r.Client.Close()
    40  }
    41  
    42  func (r reqDefCauslapse) SendRequest(ctx context.Context, addr string, req *einsteindbrpc.Request, timeout time.Duration) (*einsteindbrpc.Response, error) {
    43  	if r.Client == nil {
    44  		panic("client should not be nil")
    45  	}
    46  	if canDefCauslapse, resp, err := r.tryDefCauslapseRequest(ctx, addr, req, timeout); canDefCauslapse {
    47  		return resp, err
    48  	}
    49  	return r.Client.SendRequest(ctx, addr, req, timeout)
    50  }
    51  
    52  func (r reqDefCauslapse) tryDefCauslapseRequest(ctx context.Context, addr string, req *einsteindbrpc.Request, timeout time.Duration) (canDefCauslapse bool, resp *einsteindbrpc.Response, err error) {
    53  	switch req.Type {
    54  	case einsteindbrpc.CmdResolveLock:
    55  		resolveLock := req.ResolveLock()
    56  		if len(resolveLock.Keys) > 0 {
    57  			// can not collapse resolve dagger lite
    58  			return
    59  		}
    60  		if len(resolveLock.TxnInfos) > 0 {
    61  			// can not collapse batch resolve locks which is only used by GC worker.
    62  			return
    63  		}
    64  		canDefCauslapse = true
    65  		key := strconv.FormatUint(resolveLock.Context.RegionId, 10) + "-" + strconv.FormatUint(resolveLock.StartVersion, 10)
    66  		resp, err = r.collapse(ctx, key, &resolveRegionSf, addr, req, timeout)
    67  		return
    68  	default:
    69  		// now we only support collapse resolve dagger.
    70  		return
    71  	}
    72  }
    73  
    74  func (r reqDefCauslapse) collapse(ctx context.Context, key string, sf *singleflight.Group,
    75  	addr string, req *einsteindbrpc.Request, timeout time.Duration) (resp *einsteindbrpc.Response, err error) {
    76  	rsC := sf.DoChan(key, func() (interface{}, error) {
    77  		return r.Client.SendRequest(context.Background(), addr, req, readTimeoutShort) // use resolveLock timeout.
    78  	})
    79  	timer := time.NewTimer(timeout)
    80  	defer timer.Stop()
    81  	select {
    82  	case <-ctx.Done():
    83  		err = errors.Trace(ctx.Err())
    84  		return
    85  	case <-timer.C:
    86  		err = errors.Trace(context.DeadlineExceeded)
    87  		return
    88  	case rs := <-rsC:
    89  		if rs.Err != nil {
    90  			err = errors.Trace(rs.Err)
    91  			return
    92  		}
    93  		resp = rs.Val.(*einsteindbrpc.Response)
    94  		return
    95  	}
    96  }