github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/cdc/kv/store_op.go (about)

     1  // Copyright 2020 PingCAP, 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 kv
    15  
    16  import (
    17  	"fmt"
    18  	"sync"
    19  	"time"
    20  
    21  	"github.com/pingcap/errors"
    22  	"github.com/pingcap/log"
    23  	"github.com/pingcap/ticdc/cdc/model"
    24  	cerror "github.com/pingcap/ticdc/pkg/errors"
    25  	"github.com/pingcap/ticdc/pkg/flags"
    26  	"github.com/pingcap/ticdc/pkg/security"
    27  	tidbconfig "github.com/pingcap/tidb/config"
    28  	"github.com/pingcap/tidb/kv"
    29  	tidbkv "github.com/pingcap/tidb/kv"
    30  	"github.com/pingcap/tidb/meta"
    31  	"github.com/pingcap/tidb/store"
    32  	"github.com/pingcap/tidb/store/driver"
    33  	"github.com/pingcap/tidb/store/tikv"
    34  	"github.com/pingcap/tidb/store/tikv/oracle"
    35  	"go.uber.org/zap"
    36  )
    37  
    38  // TiKVStorage is the tikv storage interface used by CDC.
    39  type TiKVStorage interface {
    40  	tikv.Storage
    41  	GetCachedCurrentVersion() (version tidbkv.Version, err error)
    42  }
    43  
    44  const (
    45  	storageVersionCacheUpdateInterval = time.Second * 2
    46  )
    47  
    48  // StorageWithCurVersionCache adds GetCachedCurrentVersion() to tikv.Storage
    49  type StorageWithCurVersionCache struct {
    50  	tikv.Storage
    51  	cacheKey string
    52  }
    53  
    54  type curVersionCacheEntry struct {
    55  	ts          model.Ts
    56  	lastUpdated time.Time
    57  	mu          sync.Mutex
    58  }
    59  
    60  var (
    61  	curVersionCache   = make(map[string]*curVersionCacheEntry, 1)
    62  	curVersionCacheMu sync.Mutex
    63  )
    64  
    65  func newStorageWithCurVersionCache(storage tikv.Storage, cacheKey string) TiKVStorage {
    66  	curVersionCacheMu.Lock()
    67  	defer curVersionCacheMu.Unlock()
    68  
    69  	if _, exists := curVersionCache[cacheKey]; !exists {
    70  		curVersionCache[cacheKey] = &curVersionCacheEntry{
    71  			ts:          0,
    72  			lastUpdated: time.Unix(0, 0),
    73  		}
    74  	}
    75  
    76  	return &StorageWithCurVersionCache{
    77  		Storage:  storage,
    78  		cacheKey: cacheKey,
    79  	}
    80  }
    81  
    82  // GetCachedCurrentVersion gets the cached version of currentVersion, and update the cache if necessary
    83  func (s *StorageWithCurVersionCache) GetCachedCurrentVersion() (version tidbkv.Version, err error) {
    84  	curVersionCacheMu.Lock()
    85  	entry, exists := curVersionCache[s.cacheKey]
    86  	curVersionCacheMu.Unlock()
    87  
    88  	if !exists {
    89  		err = cerror.ErrCachedTSONotExists.GenWithStackByArgs()
    90  		log.Warn("GetCachedCurrentVersion: cache entry does not exist", zap.String("cacheKey", s.cacheKey))
    91  		return
    92  	}
    93  	entry.mu.Lock()
    94  	defer entry.mu.Unlock()
    95  
    96  	if time.Now().After(entry.lastUpdated.Add(storageVersionCacheUpdateInterval)) {
    97  		var ts uint64
    98  		ts, err = s.CurrentTimestamp(oracle.GlobalTxnScope)
    99  		if err != nil {
   100  			return
   101  		}
   102  		ver := kv.NewVersion(ts)
   103  		entry.ts = ver.Ver
   104  		entry.lastUpdated = time.Now()
   105  	}
   106  
   107  	version.Ver = entry.ts
   108  	return
   109  }
   110  
   111  // GetSnapshotMeta returns tidb meta information
   112  // TODO: Simplify the signature of this function
   113  func GetSnapshotMeta(tiStore tidbkv.Storage, ts uint64) (*meta.Meta, error) {
   114  	snapshot := tiStore.GetSnapshot(tidbkv.NewVersion(ts))
   115  	return meta.NewSnapshotMeta(snapshot), nil
   116  }
   117  
   118  // CreateTiStore creates a new tikv storage client
   119  func CreateTiStore(urls string, credential *security.Credential) (kv.Storage, error) {
   120  	urlv, err := flags.NewURLsValue(urls)
   121  	if err != nil {
   122  		return nil, errors.Trace(err)
   123  	}
   124  
   125  	// Ignore error if it is already registered.
   126  	_ = store.Register("tikv", driver.TiKVDriver{})
   127  
   128  	if credential.CAPath != "" {
   129  		conf := tidbconfig.GetGlobalConfig()
   130  		conf.Security.ClusterSSLCA = credential.CAPath
   131  		conf.Security.ClusterSSLCert = credential.CertPath
   132  		conf.Security.ClusterSSLKey = credential.KeyPath
   133  		tidbconfig.StoreGlobalConfig(conf)
   134  	}
   135  
   136  	tiPath := fmt.Sprintf("tikv://%s?disableGC=true", urlv.HostString())
   137  	tiStore, err := store.New(tiPath)
   138  	if err != nil {
   139  		return nil, cerror.WrapError(cerror.ErrNewStore, err)
   140  	}
   141  	return tiStore, nil
   142  }