From 6851fffdfb75f8091cfef039478593840bcb8990 Mon Sep 17 00:00:00 2001 From: Anthony Romano Date: Fri, 12 Feb 2016 12:02:57 -0800 Subject: [PATCH] clientv3: support >= Range requests Turns out grpc will convert an empty byte string to nil, so use "\0" to indicate Range on >= key in v3 grpc protocol. --- clientv3/kv.go | 4 ++-- clientv3/op.go | 1 + etcdserver/v3demo_server.go | 6 ++++++ integration/v3_grpc_test.go | 5 ++++- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/clientv3/kv.go b/clientv3/kv.go index 9efc2dc23..0c8cf4e77 100644 --- a/clientv3/kv.go +++ b/clientv3/kv.go @@ -38,8 +38,8 @@ type KV interface { // Get retrieves keys. // By default, Get will return the value for "key", if any. - // When passed WithRange(end), Get will return the keys in the range [key, end) if - // end is non-empty, otherwise it returns keys greater than or equal to key. + // When passed WithRange(end), Get will return the keys in the range [key, end). + // When passed WithFromKey(), Get returns keys greater than or equal to key. // When passed WithRev(rev) with rev > 0, Get retrieves keys at the given revision; // if the required revision is compacted, the request will fail with ErrCompacted . // When passed WithLimit(limit), the number of returned keys is bounded by limit. diff --git a/clientv3/op.go b/clientv3/op.go index f3458e1d9..616f86438 100644 --- a/clientv3/op.go +++ b/clientv3/op.go @@ -132,6 +132,7 @@ func WithSort(tgt SortTarget, order SortOrder) OpOption { func WithRange(endKey string) OpOption { return func(op *Op) { op.end = []byte(endKey) } } +func WithFromKey() OpOption { return WithRange("\x00") } func WithSerializable() OpOption { return func(op *Op) { op.serializable = true } } diff --git a/etcdserver/v3demo_server.go b/etcdserver/v3demo_server.go index b52d0010d..ed434f66b 100644 --- a/etcdserver/v3demo_server.go +++ b/etcdserver/v3demo_server.go @@ -311,6 +311,12 @@ func applyRange(txnID int64, kv dstorage.KV, r *pb.RangeRequest) (*pb.RangeRespo err error ) + // grpc sends empty byte strings as nils, so use a '\0' to indicate + // wanting a >= query + if len(r.RangeEnd) == 1 && r.RangeEnd[0] == 0 { + r.RangeEnd = []byte{} + } + limit := r.Limit if r.SortOrder != pb.RangeRequest_NONE { // fetch everything; sort and truncate afterwards diff --git a/integration/v3_grpc_test.go b/integration/v3_grpc_test.go index 2142a1a85..90efa5ca3 100644 --- a/integration/v3_grpc_test.go +++ b/integration/v3_grpc_test.go @@ -488,6 +488,8 @@ func TestV3RangeRequest(t *testing.T) { {Key: []byte("c"), RangeEnd: []byte("c")}, // [d, b) = empty {Key: []byte("d"), RangeEnd: []byte("b")}, + // ["\0", "\0") => all in range + {Key: []byte{0}, RangeEnd: []byte{0}}, }, [][]string{ @@ -496,8 +498,9 @@ func TestV3RangeRequest(t *testing.T) { {}, {}, {}, + {"a", "b", "c", "d", "e"}, }, - []bool{false, false, false, false, false}, + []bool{false, false, false, false, false, false}, }, // revision {