From 8782bbae65eda5582d52a3cb4e67f2b35e56b62e Mon Sep 17 00:00:00 2001 From: "Sahdev P. Zala" Date: Tue, 26 Feb 2019 16:45:47 -0500 Subject: [PATCH] clientV3: fix behavior of WithPrefix and WithFromKey functions The use of WithPrefix() and WithFromKey() together is not supported. The client doesn't respect this behavior currently. Fixes #10431 --- clientv3/op.go | 14 ++++++++++++++ clientv3/utils.go | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/clientv3/op.go b/clientv3/op.go index 13507c99a..085dd28ab 100644 --- a/clientv3/op.go +++ b/clientv3/op.go @@ -218,6 +218,10 @@ func (op Op) isWrite() bool { // OpGet returns "get" operation based on given key and operation options. func OpGet(key string, opts ...OpOption) Op { + // WithPrefix and WithFromKey are not supported together + if isWithPrefix(opts) && isWithFromKey(opts) { + panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one") + } ret := Op{t: tRange, key: []byte(key)} ret.applyOpts(opts) return ret @@ -225,6 +229,10 @@ func OpGet(key string, opts ...OpOption) Op { // OpDelete returns "delete" operation based on given key and operation options. func OpDelete(key string, opts ...OpOption) Op { + // WithPrefix and WithFromKey are not supported together + if isWithPrefix(opts) && isWithFromKey(opts) { + panic("`WithPrefix` and `WithFromKey` cannot be set at the same time, choose one") + } ret := Op{t: tDeleteRange, key: []byte(key)} ret.applyOpts(opts) switch { @@ -544,3 +552,9 @@ func toLeaseTimeToLiveRequest(id LeaseID, opts ...LeaseOption) *pb.LeaseTimeToLi ret.applyOpts(opts) return &pb.LeaseTimeToLiveRequest{ID: int64(id), Keys: ret.attachedKeys} } + +// isWithPrefix returns true if WithPrefix is being called in the op +func isWithPrefix(opts []OpOption) bool { return isOpFuncCalled("WithPrefix", opts) } + +// isWithFromKey returns true if WithFromKey is being called in the op +func isWithFromKey(opts []OpOption) bool { return isOpFuncCalled("WithFromKey", opts) } diff --git a/clientv3/utils.go b/clientv3/utils.go index 850275877..b998c41b9 100644 --- a/clientv3/utils.go +++ b/clientv3/utils.go @@ -16,6 +16,9 @@ package clientv3 import ( "math/rand" + "reflect" + "runtime" + "strings" "time" ) @@ -29,3 +32,18 @@ func jitterUp(duration time.Duration, jitter float64) time.Duration { multiplier := jitter * (rand.Float64()*2 - 1) return time.Duration(float64(duration) * (1 + multiplier)) } + +// Check if the provided function is being called in the op options. +func isOpFuncCalled(op string, opts []OpOption) bool { + for _, opt := range opts { + v := reflect.ValueOf(opt) + if v.Kind() == reflect.Func { + if opFunc := runtime.FuncForPC(v.Pointer()); opFunc != nil { + if strings.Contains(opFunc.Name(), op) { + return true + } + } + } + } + return false +}