api: Add support for DeleteCAS

This commit is contained in:
Armon Dadgar 2015-01-13 13:57:48 -08:00
parent f3baa0a113
commit 18ebb1a8e9
2 changed files with 70 additions and 8 deletions

View File

@ -193,27 +193,44 @@ func (k *KV) put(key string, params map[string]string, body []byte, q *WriteOpti
// Delete is used to delete a single key // Delete is used to delete a single key
func (k *KV) Delete(key string, w *WriteOptions) (*WriteMeta, error) { func (k *KV) Delete(key string, w *WriteOptions) (*WriteMeta, error) {
return k.deleteInternal(key, nil, w) _, qm, err := k.deleteInternal(key, nil, w)
return qm, err
}
// DeleteCAS is used for a Delete Check-And-Set operation. The Key
// and ModifyIndex are respected. Returns true on success or false on failures.
func (k *KV) DeleteCAS(p *KVPair, q *WriteOptions) (bool, *WriteMeta, error) {
params := map[string]string{
"cas": strconv.FormatUint(p.ModifyIndex, 10),
}
return k.deleteInternal(p.Key, params, q)
} }
// DeleteTree is used to delete all keys under a prefix // DeleteTree is used to delete all keys under a prefix
func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) { func (k *KV) DeleteTree(prefix string, w *WriteOptions) (*WriteMeta, error) {
return k.deleteInternal(prefix, []string{"recurse"}, w) _, qm, err := k.deleteInternal(prefix, map[string]string{"recurse": ""}, w)
return qm, err
} }
func (k *KV) deleteInternal(key string, params []string, q *WriteOptions) (*WriteMeta, error) { func (k *KV) deleteInternal(key string, params map[string]string, q *WriteOptions) (bool, *WriteMeta, error) {
r := k.c.newRequest("DELETE", "/v1/kv/"+key) r := k.c.newRequest("DELETE", "/v1/kv/"+key)
r.setWriteOptions(q) r.setWriteOptions(q)
for _, param := range params { for param, val := range params {
r.params.Set(param, "") r.params.Set(param, val)
} }
rtt, resp, err := requireOK(k.c.doRequest(r)) rtt, resp, err := requireOK(k.c.doRequest(r))
if err != nil { if err != nil {
return nil, err return false, nil, err
} }
resp.Body.Close() defer resp.Body.Close()
qm := &WriteMeta{} qm := &WriteMeta{}
qm.RequestTime = rtt qm.RequestTime = rtt
return qm, nil
var buf bytes.Buffer
if _, err := io.Copy(&buf, resp.Body); err != nil {
return false, nil, fmt.Errorf("Failed to read response: %v", err)
}
res := strings.Contains(string(buf.Bytes()), "true")
return res, qm, nil
} }

View File

@ -117,6 +117,51 @@ func TestClient_List_DeleteRecurse(t *testing.T) {
} }
} }
func TestClient_DeleteCAS(t *testing.T) {
c, s := makeClient(t)
defer s.stop()
kv := c.KV()
// Put the key
key := testKey()
value := []byte("test")
p := &KVPair{Key: key, Value: value}
if work, _, err := kv.CAS(p, nil); err != nil {
t.Fatalf("err: %v", err)
} else if !work {
t.Fatalf("CAS failure")
}
// Get should work
pair, meta, err := kv.Get(key, nil)
if err != nil {
t.Fatalf("err: %v", err)
}
if pair == nil {
t.Fatalf("expected value: %#v", pair)
}
if meta.LastIndex == 0 {
t.Fatalf("unexpected value: %#v", meta)
}
// CAS update with bad index
p.ModifyIndex = 1
if work, _, err := kv.DeleteCAS(p, nil); err != nil {
t.Fatalf("err: %v", err)
} else if work {
t.Fatalf("unexpected CAS")
}
// CAS update with valid index
p.ModifyIndex = meta.LastIndex
if work, _, err := kv.DeleteCAS(p, nil); err != nil {
t.Fatalf("err: %v", err)
} else if !work {
t.Fatalf("unexpected CAS failure")
}
}
func TestClient_CAS(t *testing.T) { func TestClient_CAS(t *testing.T) {
c, s := makeClient(t) c, s := makeClient(t)
defer s.stop() defer s.stop()