go.etcd.io/etcd@v3.3.27+incompatible/proxy/grpcproxy/kv.go (about)

     1  // Copyright 2016 The etcd Authors
     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  package grpcproxy
    16  
    17  import (
    18  	"context"
    19  
    20  	"github.com/coreos/etcd/clientv3"
    21  	pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
    22  	"github.com/coreos/etcd/proxy/grpcproxy/cache"
    23  )
    24  
    25  type kvProxy struct {
    26  	kv    clientv3.KV
    27  	cache cache.Cache
    28  }
    29  
    30  func NewKvProxy(c *clientv3.Client) (pb.KVServer, <-chan struct{}) {
    31  	kv := &kvProxy{
    32  		kv:    c.KV,
    33  		cache: cache.NewCache(cache.DefaultMaxEntries),
    34  	}
    35  	donec := make(chan struct{})
    36  	close(donec)
    37  	return kv, donec
    38  }
    39  
    40  func (p *kvProxy) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
    41  	if r.Serializable {
    42  		resp, err := p.cache.Get(r)
    43  		switch err {
    44  		case nil:
    45  			cacheHits.Inc()
    46  			return resp, nil
    47  		case cache.ErrCompacted:
    48  			cacheHits.Inc()
    49  			return nil, err
    50  		}
    51  
    52  		cachedMisses.Inc()
    53  	}
    54  
    55  	resp, err := p.kv.Do(ctx, RangeRequestToOp(r))
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	// cache linearizable as serializable
    61  	req := *r
    62  	req.Serializable = true
    63  	gresp := (*pb.RangeResponse)(resp.Get())
    64  	p.cache.Add(&req, gresp)
    65  	cacheKeys.Set(float64(p.cache.Size()))
    66  
    67  	return gresp, nil
    68  }
    69  
    70  func (p *kvProxy) Put(ctx context.Context, r *pb.PutRequest) (*pb.PutResponse, error) {
    71  	p.cache.Invalidate(r.Key, nil)
    72  	cacheKeys.Set(float64(p.cache.Size()))
    73  
    74  	resp, err := p.kv.Do(ctx, PutRequestToOp(r))
    75  	return (*pb.PutResponse)(resp.Put()), err
    76  }
    77  
    78  func (p *kvProxy) DeleteRange(ctx context.Context, r *pb.DeleteRangeRequest) (*pb.DeleteRangeResponse, error) {
    79  	p.cache.Invalidate(r.Key, r.RangeEnd)
    80  	cacheKeys.Set(float64(p.cache.Size()))
    81  
    82  	resp, err := p.kv.Do(ctx, DelRequestToOp(r))
    83  	return (*pb.DeleteRangeResponse)(resp.Del()), err
    84  }
    85  
    86  func (p *kvProxy) txnToCache(reqs []*pb.RequestOp, resps []*pb.ResponseOp) {
    87  	for i := range resps {
    88  		switch tv := resps[i].Response.(type) {
    89  		case *pb.ResponseOp_ResponsePut:
    90  			p.cache.Invalidate(reqs[i].GetRequestPut().Key, nil)
    91  		case *pb.ResponseOp_ResponseDeleteRange:
    92  			rdr := reqs[i].GetRequestDeleteRange()
    93  			p.cache.Invalidate(rdr.Key, rdr.RangeEnd)
    94  		case *pb.ResponseOp_ResponseRange:
    95  			req := *(reqs[i].GetRequestRange())
    96  			req.Serializable = true
    97  			p.cache.Add(&req, tv.ResponseRange)
    98  		}
    99  	}
   100  }
   101  
   102  func (p *kvProxy) Txn(ctx context.Context, r *pb.TxnRequest) (*pb.TxnResponse, error) {
   103  	op := TxnRequestToOp(r)
   104  	opResp, err := p.kv.Do(ctx, op)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	resp := opResp.Txn()
   109  
   110  	// txn may claim an outdated key is updated; be safe and invalidate
   111  	for _, cmp := range r.Compare {
   112  		p.cache.Invalidate(cmp.Key, cmp.RangeEnd)
   113  	}
   114  	// update any fetched keys
   115  	if resp.Succeeded {
   116  		p.txnToCache(r.Success, resp.Responses)
   117  	} else {
   118  		p.txnToCache(r.Failure, resp.Responses)
   119  	}
   120  
   121  	cacheKeys.Set(float64(p.cache.Size()))
   122  
   123  	return (*pb.TxnResponse)(resp), nil
   124  }
   125  
   126  func (p *kvProxy) Compact(ctx context.Context, r *pb.CompactionRequest) (*pb.CompactionResponse, error) {
   127  	var opts []clientv3.CompactOption
   128  	if r.Physical {
   129  		opts = append(opts, clientv3.WithCompactPhysical())
   130  	}
   131  
   132  	resp, err := p.kv.Compact(ctx, r.Revision, opts...)
   133  	if err == nil {
   134  		p.cache.Compact(r.Revision)
   135  	}
   136  
   137  	cacheKeys.Set(float64(p.cache.Size()))
   138  
   139  	return (*pb.CompactionResponse)(resp), err
   140  }
   141  
   142  func requestOpToOp(union *pb.RequestOp) clientv3.Op {
   143  	switch tv := union.Request.(type) {
   144  	case *pb.RequestOp_RequestRange:
   145  		if tv.RequestRange != nil {
   146  			return RangeRequestToOp(tv.RequestRange)
   147  		}
   148  	case *pb.RequestOp_RequestPut:
   149  		if tv.RequestPut != nil {
   150  			return PutRequestToOp(tv.RequestPut)
   151  		}
   152  	case *pb.RequestOp_RequestDeleteRange:
   153  		if tv.RequestDeleteRange != nil {
   154  			return DelRequestToOp(tv.RequestDeleteRange)
   155  		}
   156  	case *pb.RequestOp_RequestTxn:
   157  		if tv.RequestTxn != nil {
   158  			return TxnRequestToOp(tv.RequestTxn)
   159  		}
   160  	}
   161  	panic("unknown request")
   162  }
   163  
   164  func RangeRequestToOp(r *pb.RangeRequest) clientv3.Op {
   165  	opts := []clientv3.OpOption{}
   166  	if len(r.RangeEnd) != 0 {
   167  		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
   168  	}
   169  	opts = append(opts, clientv3.WithRev(r.Revision))
   170  	opts = append(opts, clientv3.WithLimit(r.Limit))
   171  	opts = append(opts, clientv3.WithSort(
   172  		clientv3.SortTarget(r.SortTarget),
   173  		clientv3.SortOrder(r.SortOrder)),
   174  	)
   175  	opts = append(opts, clientv3.WithMaxCreateRev(r.MaxCreateRevision))
   176  	opts = append(opts, clientv3.WithMinCreateRev(r.MinCreateRevision))
   177  	opts = append(opts, clientv3.WithMaxModRev(r.MaxModRevision))
   178  	opts = append(opts, clientv3.WithMinModRev(r.MinModRevision))
   179  	if r.CountOnly {
   180  		opts = append(opts, clientv3.WithCountOnly())
   181  	}
   182  	if r.KeysOnly {
   183  		opts = append(opts, clientv3.WithKeysOnly())
   184  	}
   185  	if r.Serializable {
   186  		opts = append(opts, clientv3.WithSerializable())
   187  	}
   188  
   189  	return clientv3.OpGet(string(r.Key), opts...)
   190  }
   191  
   192  func PutRequestToOp(r *pb.PutRequest) clientv3.Op {
   193  	opts := []clientv3.OpOption{}
   194  	opts = append(opts, clientv3.WithLease(clientv3.LeaseID(r.Lease)))
   195  	if r.IgnoreValue {
   196  		opts = append(opts, clientv3.WithIgnoreValue())
   197  	}
   198  	if r.IgnoreLease {
   199  		opts = append(opts, clientv3.WithIgnoreLease())
   200  	}
   201  	if r.PrevKv {
   202  		opts = append(opts, clientv3.WithPrevKV())
   203  	}
   204  	return clientv3.OpPut(string(r.Key), string(r.Value), opts...)
   205  }
   206  
   207  func DelRequestToOp(r *pb.DeleteRangeRequest) clientv3.Op {
   208  	opts := []clientv3.OpOption{}
   209  	if len(r.RangeEnd) != 0 {
   210  		opts = append(opts, clientv3.WithRange(string(r.RangeEnd)))
   211  	}
   212  	if r.PrevKv {
   213  		opts = append(opts, clientv3.WithPrevKV())
   214  	}
   215  	return clientv3.OpDelete(string(r.Key), opts...)
   216  }
   217  
   218  func TxnRequestToOp(r *pb.TxnRequest) clientv3.Op {
   219  	cmps := make([]clientv3.Cmp, len(r.Compare))
   220  	thenops := make([]clientv3.Op, len(r.Success))
   221  	elseops := make([]clientv3.Op, len(r.Failure))
   222  	for i := range r.Compare {
   223  		cmps[i] = (clientv3.Cmp)(*r.Compare[i])
   224  	}
   225  	for i := range r.Success {
   226  		thenops[i] = requestOpToOp(r.Success[i])
   227  	}
   228  	for i := range r.Failure {
   229  		elseops[i] = requestOpToOp(r.Failure[i])
   230  	}
   231  	return clientv3.OpTxn(cmps, thenops, elseops)
   232  }