github.com/KinWaiYuen/client-go/v2@v2.5.4/internal/mockstore/mocktikv/pd.go (about)

     1  // Copyright 2021 TiKV Authors
     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  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // NOTE: The code in this file is based on code from the
    16  // TiDB project, licensed under the Apache License v 2.0
    17  //
    18  // https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/mockstore/mocktikv/pd.go
    19  //
    20  
    21  // Copyright 2016 PingCAP, Inc.
    22  //
    23  // Licensed under the Apache License, Version 2.0 (the "License");
    24  // you may not use this file except in compliance with the License.
    25  // You may obtain a copy of the License at
    26  //
    27  //     http://www.apache.org/licenses/LICENSE-2.0
    28  //
    29  // Unless required by applicable law or agreed to in writing, software
    30  // distributed under the License is distributed on an "AS IS" BASIS,
    31  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    32  // See the License for the specific language governing permissions and
    33  // limitations under the License.
    34  
    35  package mocktikv
    36  
    37  import (
    38  	"context"
    39  	"fmt"
    40  	"math"
    41  	"sync"
    42  	"time"
    43  
    44  	"github.com/pingcap/errors"
    45  	"github.com/pingcap/kvproto/pkg/metapb"
    46  	"github.com/pingcap/kvproto/pkg/pdpb"
    47  	pd "github.com/tikv/pd/client"
    48  )
    49  
    50  // Use global variables to prevent pdClients from creating duplicate timestamps.
    51  var tsMu = struct {
    52  	sync.Mutex
    53  	physicalTS int64
    54  	logicalTS  int64
    55  }{}
    56  
    57  type pdClient struct {
    58  	cluster *Cluster
    59  	// SafePoint set by `UpdateGCSafePoint`. Not to be confused with SafePointKV.
    60  	gcSafePoint uint64
    61  	// Represents the current safePoint of all services including TiDB, representing how much data they want to retain
    62  	// in GC.
    63  	serviceSafePoints map[string]uint64
    64  	gcSafePointMu     sync.Mutex
    65  }
    66  
    67  // NewPDClient creates a mock pd.Client that uses local timestamp and meta data
    68  // from a Cluster.
    69  func NewPDClient(cluster *Cluster) pd.Client {
    70  	return &pdClient{
    71  		cluster:           cluster,
    72  		serviceSafePoints: make(map[string]uint64),
    73  	}
    74  }
    75  
    76  func (c *pdClient) GetClusterID(ctx context.Context) uint64 {
    77  	return 1
    78  }
    79  
    80  func (c *pdClient) GetTS(context.Context) (int64, int64, error) {
    81  	tsMu.Lock()
    82  	defer tsMu.Unlock()
    83  
    84  	ts := time.Now().UnixNano() / int64(time.Millisecond)
    85  	if tsMu.physicalTS >= ts {
    86  		tsMu.logicalTS++
    87  	} else {
    88  		tsMu.physicalTS = ts
    89  		tsMu.logicalTS = 0
    90  	}
    91  	return tsMu.physicalTS, tsMu.logicalTS, nil
    92  }
    93  
    94  func (c *pdClient) GetLocalTS(ctx context.Context, dcLocation string) (int64, int64, error) {
    95  	return c.GetTS(ctx)
    96  }
    97  
    98  func (c *pdClient) GetTSAsync(ctx context.Context) pd.TSFuture {
    99  	return &mockTSFuture{c, ctx, false}
   100  }
   101  
   102  func (c *pdClient) GetLocalTSAsync(ctx context.Context, dcLocation string) pd.TSFuture {
   103  	return c.GetTSAsync(ctx)
   104  }
   105  
   106  type mockTSFuture struct {
   107  	pdc  *pdClient
   108  	ctx  context.Context
   109  	used bool
   110  }
   111  
   112  func (m *mockTSFuture) Wait() (int64, int64, error) {
   113  	if m.used {
   114  		return 0, 0, errors.New("cannot wait tso twice")
   115  	}
   116  	m.used = true
   117  	return m.pdc.GetTS(m.ctx)
   118  }
   119  
   120  func (c *pdClient) GetRegion(ctx context.Context, key []byte) (*pd.Region, error) {
   121  	region, peer := c.cluster.GetRegionByKey(key)
   122  	return &pd.Region{Meta: region, Leader: peer}, nil
   123  }
   124  
   125  func (c *pdClient) GetRegionFromMember(ctx context.Context, key []byte, memberURLs []string) (*pd.Region, error) {
   126  	return &pd.Region{}, nil
   127  }
   128  
   129  func (c *pdClient) GetPrevRegion(ctx context.Context, key []byte) (*pd.Region, error) {
   130  	region, peer := c.cluster.GetPrevRegionByKey(key)
   131  	return &pd.Region{Meta: region, Leader: peer}, nil
   132  }
   133  
   134  func (c *pdClient) GetRegionByID(ctx context.Context, regionID uint64) (*pd.Region, error) {
   135  	region, peer := c.cluster.GetRegionByID(regionID)
   136  	return &pd.Region{Meta: region, Leader: peer}, nil
   137  }
   138  
   139  func (c *pdClient) ScanRegions(ctx context.Context, startKey []byte, endKey []byte, limit int) ([]*pd.Region, error) {
   140  	regions := c.cluster.ScanRegions(startKey, endKey, limit)
   141  	return regions, nil
   142  }
   143  
   144  func (c *pdClient) GetStore(ctx context.Context, storeID uint64) (*metapb.Store, error) {
   145  	select {
   146  	case <-ctx.Done():
   147  		return nil, ctx.Err()
   148  	default:
   149  	}
   150  	store := c.cluster.GetStore(storeID)
   151  	// It's same as PD's implementation.
   152  	if store == nil {
   153  		return nil, fmt.Errorf("invalid store ID %d, not found", storeID)
   154  	}
   155  	if store.GetState() == metapb.StoreState_Tombstone {
   156  		return nil, nil
   157  	}
   158  	return store, nil
   159  }
   160  
   161  func (c *pdClient) GetAllStores(ctx context.Context, opts ...pd.GetStoreOption) ([]*metapb.Store, error) {
   162  	return c.cluster.GetAllStores(), nil
   163  }
   164  
   165  func (c *pdClient) UpdateGCSafePoint(ctx context.Context, safePoint uint64) (uint64, error) {
   166  	c.gcSafePointMu.Lock()
   167  	defer c.gcSafePointMu.Unlock()
   168  
   169  	if safePoint > c.gcSafePoint {
   170  		c.gcSafePoint = safePoint
   171  	}
   172  	return c.gcSafePoint, nil
   173  }
   174  
   175  func (c *pdClient) UpdateServiceGCSafePoint(ctx context.Context, serviceID string, ttl int64, safePoint uint64) (uint64, error) {
   176  	c.gcSafePointMu.Lock()
   177  	defer c.gcSafePointMu.Unlock()
   178  
   179  	if ttl == 0 {
   180  		delete(c.serviceSafePoints, serviceID)
   181  	} else {
   182  		var minSafePoint uint64 = math.MaxUint64
   183  		for _, ssp := range c.serviceSafePoints {
   184  			if ssp < minSafePoint {
   185  				minSafePoint = ssp
   186  			}
   187  		}
   188  
   189  		if len(c.serviceSafePoints) == 0 || minSafePoint <= safePoint {
   190  			c.serviceSafePoints[serviceID] = safePoint
   191  		}
   192  	}
   193  
   194  	// The minSafePoint may have changed. Reload it.
   195  	var minSafePoint uint64 = math.MaxUint64
   196  	for _, ssp := range c.serviceSafePoints {
   197  		if ssp < minSafePoint {
   198  			minSafePoint = ssp
   199  		}
   200  	}
   201  	return minSafePoint, nil
   202  }
   203  
   204  func (c *pdClient) Close() {
   205  }
   206  
   207  func (c *pdClient) ScatterRegion(ctx context.Context, regionID uint64) error {
   208  	return nil
   209  }
   210  
   211  func (c *pdClient) ScatterRegions(ctx context.Context, regionsID []uint64, opts ...pd.RegionsOption) (*pdpb.ScatterRegionResponse, error) {
   212  	return nil, nil
   213  }
   214  
   215  func (c *pdClient) SplitRegions(ctx context.Context, splitKeys [][]byte, opts ...pd.RegionsOption) (*pdpb.SplitRegionsResponse, error) {
   216  	return nil, nil
   217  }
   218  
   219  func (c *pdClient) GetOperator(ctx context.Context, regionID uint64) (*pdpb.GetOperatorResponse, error) {
   220  	return &pdpb.GetOperatorResponse{Status: pdpb.OperatorStatus_SUCCESS}, nil
   221  }
   222  
   223  func (c *pdClient) GetAllMembers(ctx context.Context) ([]*pdpb.Member, error) {
   224  	return nil, nil
   225  }
   226  
   227  func (c *pdClient) GetLeaderAddr() string { return "mockpd" }