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 }