blob: 2b7864ad8b0b021849065901385431161ffabd96 [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package clientv3
16
17import (
18 "context"
19
20 pb "go.etcd.io/etcd/etcdserver/etcdserverpb"
21
22 "google.golang.org/grpc"
23)
24
25type (
26 CompactResponse pb.CompactionResponse
27 PutResponse pb.PutResponse
28 GetResponse pb.RangeResponse
29 DeleteResponse pb.DeleteRangeResponse
30 TxnResponse pb.TxnResponse
31)
32
33type KV interface {
34 // Put puts a key-value pair into etcd.
35 // Note that key,value can be plain bytes array and string is
36 // an immutable representation of that bytes array.
37 // To get a string of bytes, do string([]byte{0x10, 0x20}).
38 Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error)
39
40 // Get retrieves keys.
41 // By default, Get will return the value for "key", if any.
42 // When passed WithRange(end), Get will return the keys in the range [key, end).
43 // When passed WithFromKey(), Get returns keys greater than or equal to key.
44 // When passed WithRev(rev) with rev > 0, Get retrieves keys at the given revision;
45 // if the required revision is compacted, the request will fail with ErrCompacted .
46 // When passed WithLimit(limit), the number of returned keys is bounded by limit.
47 // When passed WithSort(), the keys will be sorted.
48 Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error)
49
50 // Delete deletes a key, or optionally using WithRange(end), [key, end).
51 Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error)
52
53 // Compact compacts etcd KV history before the given rev.
54 Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error)
55
56 // Do applies a single Op on KV without a transaction.
57 // Do is useful when creating arbitrary operations to be issued at a
58 // later time; the user can range over the operations, calling Do to
59 // execute them. Get/Put/Delete, on the other hand, are best suited
60 // for when the operation should be issued at the time of declaration.
61 Do(ctx context.Context, op Op) (OpResponse, error)
62
63 // Txn creates a transaction.
64 Txn(ctx context.Context) Txn
65}
66
67type OpResponse struct {
68 put *PutResponse
69 get *GetResponse
70 del *DeleteResponse
71 txn *TxnResponse
72}
73
74func (op OpResponse) Put() *PutResponse { return op.put }
75func (op OpResponse) Get() *GetResponse { return op.get }
76func (op OpResponse) Del() *DeleteResponse { return op.del }
77func (op OpResponse) Txn() *TxnResponse { return op.txn }
78
79func (resp *PutResponse) OpResponse() OpResponse {
80 return OpResponse{put: resp}
81}
82func (resp *GetResponse) OpResponse() OpResponse {
83 return OpResponse{get: resp}
84}
85func (resp *DeleteResponse) OpResponse() OpResponse {
86 return OpResponse{del: resp}
87}
88func (resp *TxnResponse) OpResponse() OpResponse {
89 return OpResponse{txn: resp}
90}
91
92type kv struct {
93 remote pb.KVClient
94 callOpts []grpc.CallOption
95}
96
97func NewKV(c *Client) KV {
98 api := &kv{remote: RetryKVClient(c)}
99 if c != nil {
100 api.callOpts = c.callOpts
101 }
102 return api
103}
104
105func NewKVFromKVClient(remote pb.KVClient, c *Client) KV {
106 api := &kv{remote: remote}
107 if c != nil {
108 api.callOpts = c.callOpts
109 }
110 return api
111}
112
113func (kv *kv) Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) {
114 r, err := kv.Do(ctx, OpPut(key, val, opts...))
115 return r.put, toErr(ctx, err)
116}
117
118func (kv *kv) Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error) {
119 r, err := kv.Do(ctx, OpGet(key, opts...))
120 return r.get, toErr(ctx, err)
121}
122
123func (kv *kv) Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) {
124 r, err := kv.Do(ctx, OpDelete(key, opts...))
125 return r.del, toErr(ctx, err)
126}
127
128func (kv *kv) Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error) {
129 resp, err := kv.remote.Compact(ctx, OpCompact(rev, opts...).toRequest(), kv.callOpts...)
130 if err != nil {
131 return nil, toErr(ctx, err)
132 }
133 return (*CompactResponse)(resp), err
134}
135
136func (kv *kv) Txn(ctx context.Context) Txn {
137 return &txn{
138 kv: kv,
139 ctx: ctx,
140 callOpts: kv.callOpts,
141 }
142}
143
144func (kv *kv) Do(ctx context.Context, op Op) (OpResponse, error) {
145 var err error
146 switch op.t {
147 case tRange:
148 var resp *pb.RangeResponse
149 resp, err = kv.remote.Range(ctx, op.toRangeRequest(), kv.callOpts...)
150 if err == nil {
151 return OpResponse{get: (*GetResponse)(resp)}, nil
152 }
153 case tPut:
154 var resp *pb.PutResponse
155 r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV, IgnoreValue: op.ignoreValue, IgnoreLease: op.ignoreLease}
156 resp, err = kv.remote.Put(ctx, r, kv.callOpts...)
157 if err == nil {
158 return OpResponse{put: (*PutResponse)(resp)}, nil
159 }
160 case tDeleteRange:
161 var resp *pb.DeleteRangeResponse
162 r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV}
163 resp, err = kv.remote.DeleteRange(ctx, r, kv.callOpts...)
164 if err == nil {
165 return OpResponse{del: (*DeleteResponse)(resp)}, nil
166 }
167 case tTxn:
168 var resp *pb.TxnResponse
169 resp, err = kv.remote.Txn(ctx, op.toTxnRequest(), kv.callOpts...)
170 if err == nil {
171 return OpResponse{txn: (*TxnResponse)(resp)}, nil
172 }
173 default:
174 panic("Unknown op")
175 }
176 return OpResponse{}, toErr(ctx, err)
177}