github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/pkg/meta/internal/etcdkv/namespace/kv.go (about) 1 // Copyright 2022 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 // 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 //[reference]: https://github.com/etcd-io/etcd/blob/aa75fd08509db3aea8939cdad44e1ee9b8157b8c/client/v3/namespace/kv.go 16 17 package namespace 18 19 import ( 20 "context" 21 22 etcdImplModel "github.com/pingcap/tiflow/engine/pkg/meta/internal/etcdkv/model" 23 metaModel "github.com/pingcap/tiflow/engine/pkg/meta/model" 24 "github.com/pingcap/tiflow/pkg/errors" 25 ) 26 27 type prefixError struct { 28 cause error 29 } 30 31 func (p *prefixError) IsRetryable() bool { 32 return false 33 } 34 35 func (p *prefixError) Error() string { 36 return p.cause.Error() 37 } 38 39 type kvPrefix struct { 40 etcdImplModel.KVExt 41 pfx string 42 } 43 44 // NewPrefixKV wraps a KVExt instance so that all requests 45 // are prefixed with a given string. 46 func NewPrefixKV(kv etcdImplModel.KVExt, prefix string) metaModel.KV { 47 return &kvPrefix{kv, prefix} 48 } 49 50 func (kv *kvPrefix) Put(ctx context.Context, key, val string) (*metaModel.PutResponse, metaModel.Error) { 51 if len(key) == 0 { 52 return nil, prefixErrorFromOpFail(errors.ErrMetaEmptyKey.GenWithStackByArgs()) 53 } 54 op := kv.prefixOp(metaModel.OpPut(key, val)) 55 r, err := kv.KVExt.Do(ctx, op) 56 if err != nil { 57 return nil, err 58 } 59 put := r.Put() 60 return put, nil 61 } 62 63 func (kv *kvPrefix) Get(ctx context.Context, key string, opts ...metaModel.OpOption) (*metaModel.GetResponse, metaModel.Error) { 64 // Forbid empty key to protect the namespace prefix key 65 if len(key) == 0 && !(metaModel.IsOptsWithFromKey(opts) || metaModel.IsOptsWithPrefix(opts) || metaModel.IsOptsWithRange(opts)) { 66 return nil, prefixErrorFromOpFail(errors.ErrMetaEmptyKey.GenWithStackByArgs()) 67 } 68 r, err := kv.KVExt.Do(ctx, kv.prefixOp(metaModel.OpGet(key, opts...))) 69 if err != nil { 70 return nil, err 71 } 72 get := r.Get() 73 kv.unprefixGetResponse(get) 74 return get, nil 75 } 76 77 func (kv *kvPrefix) Delete(ctx context.Context, key string, opts ...metaModel.OpOption) (*metaModel.DeleteResponse, metaModel.Error) { 78 // Forbid empty key to protect the namespace prefix key 79 if len(key) == 0 && !(metaModel.IsOptsWithFromKey(opts) || metaModel.IsOptsWithPrefix(opts) || metaModel.IsOptsWithRange(opts)) { 80 return nil, prefixErrorFromOpFail(errors.ErrMetaEmptyKey.GenWithStackByArgs()) 81 } 82 r, err := kv.KVExt.Do(ctx, kv.prefixOp(metaModel.OpDelete(key, opts...))) 83 if err != nil { 84 return nil, err 85 } 86 del := r.Del() 87 return del, nil 88 } 89 90 // [TODO] check the empty key 91 func (kv *kvPrefix) Do(ctx context.Context, op metaModel.Op) (metaModel.OpResponse, metaModel.Error) { 92 if len(op.KeyBytes()) == 0 && !op.IsTxn() { 93 return metaModel.OpResponse{}, prefixErrorFromOpFail(errors.ErrMetaEmptyKey.GenWithStackByArgs()) 94 } 95 r, err := kv.KVExt.Do(ctx, kv.prefixOp(op)) 96 if err != nil { 97 return r, err 98 } 99 switch { 100 case r.Get() != nil: 101 kv.unprefixGetResponse(r.Get()) 102 case r.Txn() != nil: 103 kv.unprefixTxnResponse(r.Txn()) 104 } 105 return r, nil 106 } 107 108 type txnPrefix struct { 109 metaModel.Txn 110 kv *kvPrefix 111 } 112 113 func (kv *kvPrefix) Txn(ctx context.Context) metaModel.Txn { 114 return &txnPrefix{kv.KVExt.Txn(ctx), kv} 115 } 116 117 // [TODO] check the empty key 118 func (txn *txnPrefix) Do(ops ...metaModel.Op) metaModel.Txn { 119 txn.Txn = txn.Txn.Do(txn.kv.prefixOps(ops)...) 120 return txn 121 } 122 123 func (txn *txnPrefix) Commit() (*metaModel.TxnResponse, metaModel.Error) { 124 resp, err := txn.Txn.Commit() 125 if err != nil { 126 return nil, err 127 } 128 txn.kv.unprefixTxnResponse(resp) 129 return resp, nil 130 } 131 132 func (kv *kvPrefix) prefixOp(op metaModel.Op) metaModel.Op { 133 if !op.IsTxn() { 134 begin, end := kv.prefixInterval(op.KeyBytes(), op.RangeBytes()) 135 op.WithKeyBytes(begin) 136 op.WithRangeBytes(end) 137 return op 138 } 139 return metaModel.OpTxn(kv.prefixOps(op.Txn())) 140 } 141 142 func (kv *kvPrefix) unprefixGetResponse(resp *metaModel.GetResponse) { 143 for i := range resp.Kvs { 144 resp.Kvs[i].Key = resp.Kvs[i].Key[len(kv.pfx):] 145 } 146 } 147 148 func (kv *kvPrefix) unprefixTxnResponse(resp *metaModel.TxnResponse) { 149 for _, r := range resp.Responses { 150 switch tv := r.Response.(type) { 151 case *metaModel.ResponseOpResponseGet: 152 if tv.ResponseGet != nil { 153 kv.unprefixGetResponse(tv.ResponseGet) 154 } 155 case *metaModel.ResponseOpResponseTxn: 156 if tv.ResponseTxn != nil { 157 kv.unprefixTxnResponse(tv.ResponseTxn) 158 } 159 default: 160 } 161 } 162 } 163 164 func (kv *kvPrefix) prefixInterval(key, end []byte) (pfxKey []byte, pfxEnd []byte) { 165 return prefixInterval(kv.pfx, key, end) 166 } 167 168 func (kv *kvPrefix) prefixOps(ops []metaModel.Op) []metaModel.Op { 169 newOps := make([]metaModel.Op, len(ops)) 170 for i := range ops { 171 newOps[i] = kv.prefixOp(ops[i]) 172 } 173 return newOps 174 }