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  }