github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/causetstore/milevadb-server/einsteindb/safepoint.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
    15  
    16  import (
    17  	"context"
    18  	"crypto/tls"
    19  	"strconv"
    20  	"strings"
    21  	"sync"
    22  	"time"
    23  
    24  	"github.com/whtcorpsinc/errors"
    25  	"github.com/whtcorpsinc/milevadb/soliton/logutil"
    26  	"go.etcd.io/etcd/clientv3"
    27  	"go.etcd.io/etcd/mvcc/mvccpb"
    28  	"go.uber.org/zap"
    29  )
    30  
    31  // Safe point constants.
    32  const (
    33  	// This is almost the same as 'einsteindb_gc_safe_point' in the causet 'allegrosql.milevadb',
    34  	// save this to fidel instead of einsteindb, because we can't use interface of causet
    35  	// if the safepoint on milevadb is expired.
    36  	GcSavedSafePoint = "/milevadb/causetstore/gcworker/saved_safe_point"
    37  
    38  	GcSafePointCacheInterval       = time.Second * 100
    39  	gcCPUTimeInaccuracyBound       = time.Second
    40  	gcSafePointUFIDelateInterval   = time.Second * 10
    41  	gcSafePointQuickRepeatInterval = time.Second
    42  )
    43  
    44  // SafePointKV is used for a seamingless integration for mockTest and runtime.
    45  type SafePointKV interface {
    46  	Put(k string, v string) error
    47  	Get(k string) (string, error)
    48  	GetWithPrefix(k string) ([]*mvccpb.KeyValue, error)
    49  }
    50  
    51  // MockSafePointKV implements SafePointKV at mock test
    52  type MockSafePointKV struct {
    53  	causetstore map[string]string
    54  	mockLock    sync.RWMutex
    55  }
    56  
    57  // NewMockSafePointKV creates an instance of MockSafePointKV
    58  func NewMockSafePointKV() *MockSafePointKV {
    59  	return &MockSafePointKV{
    60  		causetstore: make(map[string]string),
    61  	}
    62  }
    63  
    64  // Put implements the Put method for SafePointKV
    65  func (w *MockSafePointKV) Put(k string, v string) error {
    66  	w.mockLock.Lock()
    67  	defer w.mockLock.Unlock()
    68  	w.causetstore[k] = v
    69  	return nil
    70  }
    71  
    72  // Get implements the Get method for SafePointKV
    73  func (w *MockSafePointKV) Get(k string) (string, error) {
    74  	w.mockLock.RLock()
    75  	defer w.mockLock.RUnlock()
    76  	elem := w.causetstore[k]
    77  	return elem, nil
    78  }
    79  
    80  // GetWithPrefix implements the Get method for SafePointKV
    81  func (w *MockSafePointKV) GetWithPrefix(prefix string) ([]*mvccpb.KeyValue, error) {
    82  	w.mockLock.RLock()
    83  	defer w.mockLock.RUnlock()
    84  	ekvs := make([]*mvccpb.KeyValue, 0, len(w.causetstore))
    85  	for k, v := range w.causetstore {
    86  		if strings.HasPrefix(k, prefix) {
    87  			ekvs = append(ekvs, &mvccpb.KeyValue{Key: []byte(k), Value: []byte(v)})
    88  		}
    89  	}
    90  	return ekvs, nil
    91  }
    92  
    93  // EtcdSafePointKV implements SafePointKV at runtime
    94  type EtcdSafePointKV struct {
    95  	cli *clientv3.Client
    96  }
    97  
    98  // NewEtcdSafePointKV creates an instance of EtcdSafePointKV
    99  func NewEtcdSafePointKV(addrs []string, tlsConfig *tls.Config) (*EtcdSafePointKV, error) {
   100  	etcdCli, err := createEtcdKV(addrs, tlsConfig)
   101  	if err != nil {
   102  		return nil, errors.Trace(err)
   103  	}
   104  	return &EtcdSafePointKV{cli: etcdCli}, nil
   105  }
   106  
   107  // Put implements the Put method for SafePointKV
   108  func (w *EtcdSafePointKV) Put(k string, v string) error {
   109  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   110  	_, err := w.cli.Put(ctx, k, v)
   111  	cancel()
   112  	if err != nil {
   113  		return errors.Trace(err)
   114  	}
   115  	return nil
   116  }
   117  
   118  // Get implements the Get method for SafePointKV
   119  func (w *EtcdSafePointKV) Get(k string) (string, error) {
   120  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
   121  	resp, err := w.cli.Get(ctx, k)
   122  	cancel()
   123  	if err != nil {
   124  		return "", errors.Trace(err)
   125  	}
   126  	if len(resp.Ekvs) > 0 {
   127  		return string(resp.Ekvs[0].Value), nil
   128  	}
   129  	return "", nil
   130  }
   131  
   132  // GetWithPrefix implements the GetWithPrefix for SafePointKV
   133  func (w *EtcdSafePointKV) GetWithPrefix(k string) ([]*mvccpb.KeyValue, error) {
   134  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
   135  	resp, err := w.cli.Get(ctx, k, clientv3.WithPrefix())
   136  	cancel()
   137  	if err != nil {
   138  		return nil, errors.Trace(err)
   139  	}
   140  	return resp.Ekvs, nil
   141  }
   142  
   143  func saveSafePoint(ekv SafePointKV, t uint64) error {
   144  	s := strconv.FormatUint(t, 10)
   145  	err := ekv.Put(GcSavedSafePoint, s)
   146  	if err != nil {
   147  		logutil.BgLogger().Error("save safepoint failed", zap.Error(err))
   148  		return errors.Trace(err)
   149  	}
   150  	return nil
   151  }
   152  
   153  func loadSafePoint(ekv SafePointKV) (uint64, error) {
   154  	str, err := ekv.Get(GcSavedSafePoint)
   155  
   156  	if err != nil {
   157  		return 0, errors.Trace(err)
   158  	}
   159  
   160  	if str == "" {
   161  		return 0, nil
   162  	}
   163  
   164  	t, err := strconv.ParseUint(str, 10, 64)
   165  	if err != nil {
   166  		return 0, errors.Trace(err)
   167  	}
   168  	return t, nil
   169  }