Browse Source

clientv3: add 'WithIgnoreValue' option

Gyu-Ho Lee 9 years ago
parent
commit
d94d22122b
3 changed files with 47 additions and 2 deletions
  1. 33 0
      clientv3/integration/kv_test.go
  2. 1 1
      clientv3/kv.go
  3. 13 1
      clientv3/op.go

+ 33 - 0
clientv3/integration/kv_test.go

@@ -113,6 +113,39 @@ func TestKVPut(t *testing.T) {
 	}
 	}
 }
 }
 
 
+// TestKVPutWithIgnoreValue ensures that Put with WithIgnoreValue does not clobber the old value.
+func TestKVPutWithIgnoreValue(t *testing.T) {
+	defer testutil.AfterTest(t)
+
+	clus := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
+	defer clus.Terminate(t)
+
+	kv := clientv3.NewKV(clus.RandClient())
+
+	_, err := kv.Put(context.TODO(), "foo", "", clientv3.WithIgnoreValue())
+	if err != rpctypes.ErrKeyNotFound {
+		t.Fatalf("err expected %v, got %v", rpctypes.ErrKeyNotFound, err)
+	}
+
+	if _, err := kv.Put(context.TODO(), "foo", "bar"); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := kv.Put(context.TODO(), "foo", "", clientv3.WithIgnoreValue()); err != nil {
+		t.Fatal(err)
+	}
+	rr, rerr := kv.Get(context.TODO(), "foo")
+	if rerr != nil {
+		t.Fatal(rerr)
+	}
+	if len(rr.Kvs) != 1 {
+		t.Fatalf("len(rr.Kvs) expected 1, got %d", len(rr.Kvs))
+	}
+	if !bytes.Equal(rr.Kvs[0].Value, []byte("bar")) {
+		t.Fatalf("value expected 'bar', got %q", rr.Kvs[0].Value)
+	}
+}
+
 func TestKVPutWithRequireLeader(t *testing.T) {
 func TestKVPutWithRequireLeader(t *testing.T) {
 	defer testutil.AfterTest(t)
 	defer testutil.AfterTest(t)
 
 

+ 1 - 1
clientv3/kv.go

@@ -148,7 +148,7 @@ func (kv *kv) do(ctx context.Context, op Op) (OpResponse, error) {
 		}
 		}
 	case tPut:
 	case tPut:
 		var resp *pb.PutResponse
 		var resp *pb.PutResponse
-		r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV}
+		r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV, IgnoreValue: op.ignoreValue}
 		resp, err = kv.remote.Put(ctx, r)
 		resp, err = kv.remote.Put(ctx, r)
 		if err == nil {
 		if err == nil {
 			return OpResponse{put: (*PutResponse)(resp)}, nil
 			return OpResponse{put: (*PutResponse)(resp)}, nil

+ 13 - 1
clientv3/op.go

@@ -52,6 +52,9 @@ type Op struct {
 	// for watch, put, delete
 	// for watch, put, delete
 	prevKV bool
 	prevKV bool
 
 
+	// for put
+	ignoreValue bool
+
 	// progressNotify is for progress updates.
 	// progressNotify is for progress updates.
 	progressNotify bool
 	progressNotify bool
 	// createdNotify is for created event
 	// createdNotify is for created event
@@ -94,7 +97,7 @@ func (op Op) toRequestOp() *pb.RequestOp {
 	case tRange:
 	case tRange:
 		return &pb.RequestOp{Request: &pb.RequestOp_RequestRange{RequestRange: op.toRangeRequest()}}
 		return &pb.RequestOp{Request: &pb.RequestOp_RequestRange{RequestRange: op.toRangeRequest()}}
 	case tPut:
 	case tPut:
-		r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV}
+		r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV, IgnoreValue: op.ignoreValue}
 		return &pb.RequestOp{Request: &pb.RequestOp_RequestPut{RequestPut: r}}
 		return &pb.RequestOp{Request: &pb.RequestOp_RequestPut{RequestPut: r}}
 	case tDeleteRange:
 	case tDeleteRange:
 		r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV}
 		r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV}
@@ -360,6 +363,15 @@ func WithPrevKV() OpOption {
 	}
 	}
 }
 }
 
 
+// WithIgnoreValue updates the key using its current value.
+// Empty value should be passed when ignore_value is set.
+// Returns an error if the key does not exist.
+func WithIgnoreValue() OpOption {
+	return func(op *Op) {
+		op.ignoreValue = true
+	}
+}
+
 // LeaseOp represents an Operation that lease can execute.
 // LeaseOp represents an Operation that lease can execute.
 type LeaseOp struct {
 type LeaseOp struct {
 	id LeaseID
 	id LeaseID