mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00

Currently the user can't list only the keys in a prefix search. In order to support such operations the filtering will be done on the server side to reduce the encoding and network transfer costs.
173 lines
5.3 KiB
Go
173 lines
5.3 KiB
Go
// Copyright 2015 The etcd Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package clientv3
|
|
|
|
import (
|
|
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
|
|
"golang.org/x/net/context"
|
|
)
|
|
|
|
type (
|
|
PutResponse pb.PutResponse
|
|
GetResponse pb.RangeResponse
|
|
DeleteResponse pb.DeleteRangeResponse
|
|
TxnResponse pb.TxnResponse
|
|
)
|
|
|
|
type KV interface {
|
|
// Put puts a key-value pair into etcd.
|
|
// Note that key,value can be plain bytes array and string is
|
|
// an immutable representation of that bytes array.
|
|
// To get a string of bytes, do string([]byte(0x10, 0x20)).
|
|
Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error)
|
|
|
|
// 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).
|
|
// 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.
|
|
// When passed WithSort(), the keys will be sorted.
|
|
Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error)
|
|
|
|
// Delete deletes a key, or optionally using WithRange(end), [key, end).
|
|
Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error)
|
|
|
|
// Compact compacts etcd KV history before the given rev.
|
|
Compact(ctx context.Context, rev int64) error
|
|
|
|
// Do applies a single Op on KV without a transaction.
|
|
// Do is useful when declaring operations to be issued at a later time
|
|
// whereas Get/Put/Delete are for better suited for when the operation
|
|
// should be immediately issued at time of declaration.
|
|
|
|
// Do applies a single Op on KV without a transaction.
|
|
// Do is useful when creating arbitrary operations to be issued at a
|
|
// later time; the user can range over the operations, calling Do to
|
|
// execute them. Get/Put/Delete, on the other hand, are best suited
|
|
// for when the operation should be issued at the time of declaration.
|
|
Do(ctx context.Context, op Op) (OpResponse, error)
|
|
|
|
// Txn creates a transaction.
|
|
Txn(ctx context.Context) Txn
|
|
}
|
|
|
|
type OpResponse struct {
|
|
put *PutResponse
|
|
get *GetResponse
|
|
del *DeleteResponse
|
|
}
|
|
|
|
func (op OpResponse) Put() *PutResponse { return op.put }
|
|
func (op OpResponse) Get() *GetResponse { return op.get }
|
|
func (op OpResponse) Del() *DeleteResponse { return op.del }
|
|
|
|
type kv struct {
|
|
remote pb.KVClient
|
|
}
|
|
|
|
func NewKV(c *Client) KV {
|
|
return &kv{remote: pb.NewKVClient(c.conn)}
|
|
}
|
|
|
|
func (kv *kv) Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) {
|
|
r, err := kv.Do(ctx, OpPut(key, val, opts...))
|
|
return r.put, toErr(ctx, err)
|
|
}
|
|
|
|
func (kv *kv) Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error) {
|
|
r, err := kv.Do(ctx, OpGet(key, opts...))
|
|
return r.get, toErr(ctx, err)
|
|
}
|
|
|
|
func (kv *kv) Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) {
|
|
r, err := kv.Do(ctx, OpDelete(key, opts...))
|
|
return r.del, toErr(ctx, err)
|
|
}
|
|
|
|
func (kv *kv) Compact(ctx context.Context, rev int64) error {
|
|
if _, err := kv.remote.Compact(ctx, &pb.CompactionRequest{Revision: rev}); err != nil {
|
|
return toErr(ctx, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (kv *kv) Txn(ctx context.Context) Txn {
|
|
return &txn{
|
|
kv: kv,
|
|
ctx: ctx,
|
|
}
|
|
}
|
|
|
|
func (kv *kv) Do(ctx context.Context, op Op) (OpResponse, error) {
|
|
for {
|
|
resp, err := kv.do(ctx, op)
|
|
if err == nil {
|
|
return resp, nil
|
|
}
|
|
if isHaltErr(ctx, err) {
|
|
return resp, toErr(ctx, err)
|
|
}
|
|
// do not retry on modifications
|
|
if op.isWrite() {
|
|
return resp, toErr(ctx, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (kv *kv) do(ctx context.Context, op Op) (OpResponse, error) {
|
|
var err error
|
|
switch op.t {
|
|
// TODO: handle other ops
|
|
case tRange:
|
|
var resp *pb.RangeResponse
|
|
r := &pb.RangeRequest{
|
|
Key: op.key,
|
|
RangeEnd: op.end,
|
|
Limit: op.limit,
|
|
Revision: op.rev,
|
|
Serializable: op.serializable,
|
|
KeysOnly: op.keysOnly,
|
|
}
|
|
if op.sort != nil {
|
|
r.SortOrder = pb.RangeRequest_SortOrder(op.sort.Order)
|
|
r.SortTarget = pb.RangeRequest_SortTarget(op.sort.Target)
|
|
}
|
|
|
|
resp, err = kv.remote.Range(ctx, r)
|
|
if err == nil {
|
|
return OpResponse{get: (*GetResponse)(resp)}, nil
|
|
}
|
|
case tPut:
|
|
var resp *pb.PutResponse
|
|
r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID)}
|
|
resp, err = kv.remote.Put(ctx, r)
|
|
if err == nil {
|
|
return OpResponse{put: (*PutResponse)(resp)}, nil
|
|
}
|
|
case tDeleteRange:
|
|
var resp *pb.DeleteRangeResponse
|
|
r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end}
|
|
resp, err = kv.remote.DeleteRange(ctx, r)
|
|
if err == nil {
|
|
return OpResponse{del: (*DeleteResponse)(resp)}, nil
|
|
}
|
|
default:
|
|
panic("Unknown op")
|
|
}
|
|
return OpResponse{}, err
|
|
}
|