Browse Source

Merge pull request #4555 from heyitsanthony/v3-with-prefix

clientv3: WithPrefix operation option
Anthony Romano 9 years ago
parent
commit
7d73d41758
3 changed files with 49 additions and 46 deletions
  1. 31 20
      clientv3/integration/kv_test.go
  2. 16 0
      clientv3/op.go
  3. 2 26
      clientv3/sync/syncer.go

+ 31 - 20
clientv3/integration/kv_test.go

@@ -96,10 +96,9 @@ func TestKVRange(t *testing.T) {
 	wheader := resp.Header
 
 	tests := []struct {
-		begin, end   string
-		rev          int64
-		sortOption   *clientv3.SortOption
-		serializable bool
+		begin, end string
+		rev        int64
+		opts       []clientv3.OpOption
 
 		wantSet []*storagepb.KeyValue
 	}{
@@ -108,7 +107,6 @@ func TestKVRange(t *testing.T) {
 			"a", "c",
 			0,
 			nil,
-			false,
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
@@ -119,8 +117,7 @@ func TestKVRange(t *testing.T) {
 		{
 			"a", "c",
 			0,
-			nil,
-			true,
+			[]clientv3.OpOption{clientv3.WithSerializable()},
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
@@ -132,7 +129,6 @@ func TestKVRange(t *testing.T) {
 			"a", "x",
 			2,
 			nil,
-			false,
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
@@ -142,8 +138,7 @@ func TestKVRange(t *testing.T) {
 		{
 			"a", "x",
 			0,
-			&clientv3.SortOption{Target: clientv3.SortByKey, Order: clientv3.SortAscend},
-			false,
+			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByKey, clientv3.SortAscend)},
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
@@ -158,8 +153,7 @@ func TestKVRange(t *testing.T) {
 		{
 			"a", "x",
 			0,
-			&clientv3.SortOption{Target: clientv3.SortByCreatedRev, Order: clientv3.SortDescend},
-			false,
+			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByCreatedRev, clientv3.SortDescend)},
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
@@ -174,8 +168,7 @@ func TestKVRange(t *testing.T) {
 		{
 			"a", "x",
 			0,
-			&clientv3.SortOption{Target: clientv3.SortByModifiedRev, Order: clientv3.SortDescend},
-			false,
+			[]clientv3.OpOption{clientv3.WithSort(clientv3.SortByModifiedRev, clientv3.SortDescend)},
 
 			[]*storagepb.KeyValue{
 				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
@@ -186,16 +179,34 @@ func TestKVRange(t *testing.T) {
 				{Key: []byte("a"), Value: nil, CreateRevision: 2, ModRevision: 2, Version: 1},
 			},
 		},
+		// WithPrefix
+		{
+			"foo", "",
+			0,
+			[]clientv3.OpOption{clientv3.WithPrefix()},
+
+			[]*storagepb.KeyValue{
+				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
+				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
+			},
+		},
+		// WithFromKey
+		{
+			"fo", "",
+			0,
+			[]clientv3.OpOption{clientv3.WithFromKey()},
+
+			[]*storagepb.KeyValue{
+				{Key: []byte("foo"), Value: nil, CreateRevision: 7, ModRevision: 7, Version: 1},
+				{Key: []byte("foo/abc"), Value: nil, CreateRevision: 8, ModRevision: 8, Version: 1},
+				{Key: []byte("fop"), Value: nil, CreateRevision: 9, ModRevision: 9, Version: 1},
+			},
+		},
 	}
 
 	for i, tt := range tests {
 		opts := []clientv3.OpOption{clientv3.WithRange(tt.end), clientv3.WithRev(tt.rev)}
-		if tt.sortOption != nil {
-			opts = append(opts, clientv3.WithSort(tt.sortOption.Target, tt.sortOption.Order))
-		}
-		if tt.serializable == true {
-			opts = append(opts, clientv3.WithSerializable())
-		}
+		opts = append(opts, tt.opts...)
 		resp, err := kv.Get(ctx, tt.begin, opts...)
 		if err != nil {
 			t.Fatalf("#%d: couldn't range (%v)", i, err)

+ 16 - 0
clientv3/op.go

@@ -129,6 +129,22 @@ func WithSort(tgt SortTarget, order SortOrder) OpOption {
 		op.sort = &SortOption{tgt, order}
 	}
 }
+func WithPrefix() OpOption {
+	return func(op *Op) {
+		op.end = make([]byte, len(op.key))
+		copy(op.end, op.key)
+		for i := len(op.end) - 1; i >= 0; i-- {
+			if op.end[i] < 0xff {
+				op.end[i] = op.end[i] + 1
+				op.end = op.end[:i+1]
+				return
+			}
+		}
+		// next prefix does not exist (e.g., 0xffff);
+		// default to WithFromKey policy
+		op.end = []byte{0}
+	}
+}
 func WithRange(endKey string) OpOption {
 	return func(op *Op) { op.end = []byte(endKey) }
 }

+ 2 - 26
clientv3/sync/syncer.go

@@ -65,7 +65,7 @@ func (s *syncer) SyncBase(ctx context.Context) (<-chan clientv3.GetResponse, cha
 		defer close(respchan)
 		defer close(errchan)
 
-		var key, end string
+		var key string
 
 		opts := []clientv3.OpOption{clientv3.WithLimit(batchLimit), clientv3.WithRev(s.rev)}
 
@@ -78,15 +78,8 @@ func (s *syncer) SyncBase(ctx context.Context) (<-chan clientv3.GetResponse, cha
 			// If len(s.prefix) != 0, we will sync key-value space with given prefix.
 			// We then range from the prefix to the next prefix if exists. Or we will
 			// range from the prefix to the end if the next prefix does not exists.
-			// (For example, when the given prefix is 0xffff, the next prefix does not
-			// exist).
+			opts = append(opts, clientv3.WithPrefix())
 			key = s.prefix
-			end = string(incr([]byte(s.prefix)))
-			if len(end) == 0 {
-				opts = append(opts, clientv3.WithFromKey())
-			} else {
-				opts = append(opts, clientv3.WithRange(string(end)))
-			}
 		}
 
 		for {
@@ -131,20 +124,3 @@ func (s *syncer) SyncUpdates(ctx context.Context) clientv3.WatchChan {
 
 	return respchan
 }
-
-func incr(bs []byte) []byte {
-	c := int8(1)
-	for i := range bs {
-		j := len(bs) - i - 1
-		n := int8(bs[j])
-		n += c
-		bs[j] = byte(n)
-		if n == 0 {
-			c = 1
-		} else {
-			c = 0
-			return bs
-		}
-	}
-	return nil
-}