From 0f455474d6490856c66b63bd128fc6476d59145e Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Tue, 8 Aug 2017 13:47:27 +0200 Subject: [PATCH 1/7] travis: Update distro to trusty. Signed-off-by: Matthieu Nottale --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index a7a3bcff..d0579ee0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,3 +29,5 @@ script: - go test -v -race ./... - script/coverage - goveralls -service=travis-ci -coverprofile=goverage.report + +dist: trusty From 81b6cc8f00b9d77e9fba5c626f5fc91ea5852004 Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Thu, 10 Aug 2017 12:26:25 +0200 Subject: [PATCH 2/7] travis: Restart zk until it works. Signed-off-by: Matthieu Nottale --- .travis.yml | 2 +- script/travis_start_zk.sh | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100755 script/travis_start_zk.sh diff --git a/.travis.yml b/.travis.yml index d0579ee0..65089e85 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,7 +22,7 @@ before_script: script: - ./consul agent -server -bootstrap -advertise=127.0.0.1 -data-dir /tmp/consul -config-file=./config.json 1>/dev/null & - ./etcd/etcd --listen-client-urls 'http://0.0.0.0:4001' --advertise-client-urls 'http://127.0.0.1:4001' >/dev/null 2>&1 & - - ./zk/bin/zkServer.sh start ./zk/conf/zoo.cfg 1> /dev/null + - ./script/travis_start_zk.sh - script/validate-gofmt - go vet ./... - fgt golint ./... diff --git a/script/travis_start_zk.sh b/script/travis_start_zk.sh new file mode 100755 index 00000000..8892c4e2 --- /dev/null +++ b/script/travis_start_zk.sh @@ -0,0 +1,11 @@ +#! /bin/bash + +while true; do + ./zk/bin/zkServer.sh start ./zk/conf/zoo.cfg + sleep 3 + if echo stat |nc localhost 2181 |grep -q Mode; then + break + fi + echo zk did not start properly, retrying... + ./zk/bin/zkServer.sh stop +done From 9d06f5834525ebebf041001da636d7ee236b089e Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Wed, 5 Jul 2017 10:30:04 +0200 Subject: [PATCH 3/7] Add support for memo backend. Signed-off-by: Matthieu Nottale --- store/memo/memo.go | 131 +++++++ store/memo/memo_kvs/memo_kvs.pb.go | 570 +++++++++++++++++++++++++++++ store/store.go | 2 + 3 files changed, 703 insertions(+) create mode 100644 store/memo/memo.go create mode 100644 store/memo/memo_kvs/memo_kvs.pb.go diff --git a/store/memo/memo.go b/store/memo/memo.go new file mode 100644 index 00000000..62d56a03 --- /dev/null +++ b/store/memo/memo.go @@ -0,0 +1,131 @@ +package memo + +import ( + "github.com/docker/libkv" + "github.com/docker/libkv/store" + kvs "github.com/docker/libkv/store/memo/memo_kvs" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" +) + +// Memo is the receiver type for the Store interface +type Memo struct { + kvs kvs.KeyValueStoreClient +} + +// Register registers memo to libkv +func Register() { + libkv.AddStore("memo", New) +} + +// New creates a new memo client +func New(addrs []string, options *store.Config) (store.Store, error) { + conn, err := grpc.Dial(addrs[0], grpc.WithInsecure()) + if err != nil { + return nil, err + } + kvs := kvs.NewKeyValueStoreClient(conn) + return &Memo{kvs: kvs}, nil +} + +// Get current value at "key". +func (s *Memo) Get(key string) (*store.KVPair, error) { + res, err := s.kvs.Fetch(context.Background(), &kvs.FetchRequest{Key: key}) + if err != nil { + if grpc.Code(err) == codes.NotFound { + return nil, store.ErrKeyNotFound + } + return nil, err + } + return &store.KVPair{ + Key: key, + Value: res.Value, + LastIndex: 0, + }, nil +} + +// Put value at "key" +func (s *Memo) Put(key string, value []byte, options *store.WriteOptions) error { + _, err := s.kvs.Upsert(context.Background(), + &kvs.UpsertRequest{Key: key, Value: value}) + return err +} + +// Delete value at "key" +func (s *Memo) Delete(key string) error { + _, err := s.kvs.Delete(context.Background(), &kvs.DeleteRequest{Key: key}) + return err +} + +// Exists checks if "key" is present in the store +func (s *Memo) Exists(key string) (bool, error) { + _, err := s.kvs.Fetch(context.Background(), &kvs.FetchRequest{Key: key}) + if err == nil { + return true, nil + } + if grpc.Code(err) == codes.NotFound { + return false, nil + } + return false, err +} + +// Watch for changes. Not supported by memo. +func (s *Memo) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) { + return nil, store.ErrCallNotSupported +} + +// WatchTree for changes. Not supported by memo. +func (s *Memo) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) { + return nil, store.ErrCallNotSupported +} + +// NewLock is not supported by memo. +func (s *Memo) NewLock(key string, options *store.LockOptions) (store.Locker, error) { + return nil, store.ErrCallNotSupported +} + +// List keys with given prefix. +func (s *Memo) List(directory string) ([]*store.KVPair, error) { + keys, err := s.kvs.List(context.Background(), + &kvs.ListRequest{Prefix: directory, MaxKeys: 1000000000}) + if err != nil { + return nil, err + } + var res []*store.KVPair + for _, k := range keys.Items { + kv, err := s.Get(k.Key) + if err != nil { + return nil, err + } + res = append(res, kv) + } + return res, nil +} + +// DeleteTree deletes all entries with given prefix. +func (s *Memo) DeleteTree(directory string) error { + keys, err := s.kvs.List(context.Background(), + &kvs.ListRequest{Prefix: directory, MaxKeys: 1000000000}) + if err != nil { + return err + } + for _, k := range keys.Items { + s.Delete(k.Key) + } + return nil +} + +// AtomicPut is not supported by memo. +func (s *Memo) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) { + return false, nil, store.ErrCallNotSupported +} + +// AtomicDelete is not supported by memo. +func (s *Memo) AtomicDelete(key string, previous *store.KVPair) (bool, error) { + return false, store.ErrCallNotSupported +} + +// Close the connection +func (s *Memo) Close() { +} diff --git a/store/memo/memo_kvs/memo_kvs.pb.go b/store/memo/memo_kvs/memo_kvs.pb.go new file mode 100644 index 00000000..a6b32529 --- /dev/null +++ b/store/memo/memo_kvs/memo_kvs.pb.go @@ -0,0 +1,570 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: memo_kvs.proto + +/* +Package memo_kvs is a generated protocol buffer package. + +It is generated from these files: + memo_kvs.proto + +It has these top-level messages: + InsertRequest + InsertResponse + UpdateRequest + UpdateResponse + UpsertRequest + UpsertResponse + FetchRequest + FetchResponse + DeleteRequest + DeleteResponse + ListRequest + ListItem + ListResponse +*/ +package memo_kvs + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +import ( + context "golang.org/x/net/context" + grpc "google.golang.org/grpc" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type InsertRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *InsertRequest) Reset() { *m = InsertRequest{} } +func (m *InsertRequest) String() string { return proto.CompactTextString(m) } +func (*InsertRequest) ProtoMessage() {} +func (*InsertRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *InsertRequest) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *InsertRequest) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type InsertResponse struct { +} + +func (m *InsertResponse) Reset() { *m = InsertResponse{} } +func (m *InsertResponse) String() string { return proto.CompactTextString(m) } +func (*InsertResponse) ProtoMessage() {} +func (*InsertResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +type UpdateRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *UpdateRequest) Reset() { *m = UpdateRequest{} } +func (m *UpdateRequest) String() string { return proto.CompactTextString(m) } +func (*UpdateRequest) ProtoMessage() {} +func (*UpdateRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *UpdateRequest) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *UpdateRequest) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type UpdateResponse struct { +} + +func (m *UpdateResponse) Reset() { *m = UpdateResponse{} } +func (m *UpdateResponse) String() string { return proto.CompactTextString(m) } +func (*UpdateResponse) ProtoMessage() {} +func (*UpdateResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +type UpsertRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` + Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *UpsertRequest) Reset() { *m = UpsertRequest{} } +func (m *UpsertRequest) String() string { return proto.CompactTextString(m) } +func (*UpsertRequest) ProtoMessage() {} +func (*UpsertRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *UpsertRequest) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +func (m *UpsertRequest) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type UpsertResponse struct { +} + +func (m *UpsertResponse) Reset() { *m = UpsertResponse{} } +func (m *UpsertResponse) String() string { return proto.CompactTextString(m) } +func (*UpsertResponse) ProtoMessage() {} +func (*UpsertResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +type FetchRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` +} + +func (m *FetchRequest) Reset() { *m = FetchRequest{} } +func (m *FetchRequest) String() string { return proto.CompactTextString(m) } +func (*FetchRequest) ProtoMessage() {} +func (*FetchRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *FetchRequest) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type FetchResponse struct { + Value []byte `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (m *FetchResponse) Reset() { *m = FetchResponse{} } +func (m *FetchResponse) String() string { return proto.CompactTextString(m) } +func (*FetchResponse) ProtoMessage() {} +func (*FetchResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *FetchResponse) GetValue() []byte { + if m != nil { + return m.Value + } + return nil +} + +type DeleteRequest struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` +} + +func (m *DeleteRequest) Reset() { *m = DeleteRequest{} } +func (m *DeleteRequest) String() string { return proto.CompactTextString(m) } +func (*DeleteRequest) ProtoMessage() {} +func (*DeleteRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *DeleteRequest) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type DeleteResponse struct { +} + +func (m *DeleteResponse) Reset() { *m = DeleteResponse{} } +func (m *DeleteResponse) String() string { return proto.CompactTextString(m) } +func (*DeleteResponse) ProtoMessage() {} +func (*DeleteResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +type ListRequest struct { + Prefix string `protobuf:"bytes,1,opt,name=prefix" json:"prefix,omitempty"` + Marker string `protobuf:"bytes,2,opt,name=marker" json:"marker,omitempty"` + Delimiter string `protobuf:"bytes,3,opt,name=delimiter" json:"delimiter,omitempty"` + MaxKeys uint64 `protobuf:"varint,4,opt,name=maxKeys" json:"maxKeys,omitempty"` +} + +func (m *ListRequest) Reset() { *m = ListRequest{} } +func (m *ListRequest) String() string { return proto.CompactTextString(m) } +func (*ListRequest) ProtoMessage() {} +func (*ListRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *ListRequest) GetPrefix() string { + if m != nil { + return m.Prefix + } + return "" +} + +func (m *ListRequest) GetMarker() string { + if m != nil { + return m.Marker + } + return "" +} + +func (m *ListRequest) GetDelimiter() string { + if m != nil { + return m.Delimiter + } + return "" +} + +func (m *ListRequest) GetMaxKeys() uint64 { + if m != nil { + return m.MaxKeys + } + return 0 +} + +type ListItem struct { + Key string `protobuf:"bytes,1,opt,name=key" json:"key,omitempty"` +} + +func (m *ListItem) Reset() { *m = ListItem{} } +func (m *ListItem) String() string { return proto.CompactTextString(m) } +func (*ListItem) ProtoMessage() {} +func (*ListItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *ListItem) GetKey() string { + if m != nil { + return m.Key + } + return "" +} + +type ListResponse struct { + Items []*ListItem `protobuf:"bytes,1,rep,name=items" json:"items,omitempty"` + Prefixes []string `protobuf:"bytes,2,rep,name=prefixes" json:"prefixes,omitempty"` + Truncated bool `protobuf:"varint,3,opt,name=truncated" json:"truncated,omitempty"` +} + +func (m *ListResponse) Reset() { *m = ListResponse{} } +func (m *ListResponse) String() string { return proto.CompactTextString(m) } +func (*ListResponse) ProtoMessage() {} +func (*ListResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +func (m *ListResponse) GetItems() []*ListItem { + if m != nil { + return m.Items + } + return nil +} + +func (m *ListResponse) GetPrefixes() []string { + if m != nil { + return m.Prefixes + } + return nil +} + +func (m *ListResponse) GetTruncated() bool { + if m != nil { + return m.Truncated + } + return false +} + +func init() { + proto.RegisterType((*InsertRequest)(nil), "memo.kvs.InsertRequest") + proto.RegisterType((*InsertResponse)(nil), "memo.kvs.InsertResponse") + proto.RegisterType((*UpdateRequest)(nil), "memo.kvs.UpdateRequest") + proto.RegisterType((*UpdateResponse)(nil), "memo.kvs.UpdateResponse") + proto.RegisterType((*UpsertRequest)(nil), "memo.kvs.UpsertRequest") + proto.RegisterType((*UpsertResponse)(nil), "memo.kvs.UpsertResponse") + proto.RegisterType((*FetchRequest)(nil), "memo.kvs.FetchRequest") + proto.RegisterType((*FetchResponse)(nil), "memo.kvs.FetchResponse") + proto.RegisterType((*DeleteRequest)(nil), "memo.kvs.DeleteRequest") + proto.RegisterType((*DeleteResponse)(nil), "memo.kvs.DeleteResponse") + proto.RegisterType((*ListRequest)(nil), "memo.kvs.ListRequest") + proto.RegisterType((*ListItem)(nil), "memo.kvs.ListItem") + proto.RegisterType((*ListResponse)(nil), "memo.kvs.ListResponse") +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// Client API for KeyValueStore service + +type KeyValueStoreClient interface { + Insert(ctx context.Context, in *InsertRequest, opts ...grpc.CallOption) (*InsertResponse, error) + Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error) + Upsert(ctx context.Context, in *UpsertRequest, opts ...grpc.CallOption) (*UpsertResponse, error) + Fetch(ctx context.Context, in *FetchRequest, opts ...grpc.CallOption) (*FetchResponse, error) + Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) + List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) +} + +type keyValueStoreClient struct { + cc *grpc.ClientConn +} + +func NewKeyValueStoreClient(cc *grpc.ClientConn) KeyValueStoreClient { + return &keyValueStoreClient{cc} +} + +func (c *keyValueStoreClient) Insert(ctx context.Context, in *InsertRequest, opts ...grpc.CallOption) (*InsertResponse, error) { + out := new(InsertResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/Insert", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyValueStoreClient) Update(ctx context.Context, in *UpdateRequest, opts ...grpc.CallOption) (*UpdateResponse, error) { + out := new(UpdateResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/Update", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyValueStoreClient) Upsert(ctx context.Context, in *UpsertRequest, opts ...grpc.CallOption) (*UpsertResponse, error) { + out := new(UpsertResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/Upsert", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyValueStoreClient) Fetch(ctx context.Context, in *FetchRequest, opts ...grpc.CallOption) (*FetchResponse, error) { + out := new(FetchResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/Fetch", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyValueStoreClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) { + out := new(DeleteResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/Delete", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *keyValueStoreClient) List(ctx context.Context, in *ListRequest, opts ...grpc.CallOption) (*ListResponse, error) { + out := new(ListResponse) + err := grpc.Invoke(ctx, "/memo.kvs.KeyValueStore/List", in, out, c.cc, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// Server API for KeyValueStore service + +type KeyValueStoreServer interface { + Insert(context.Context, *InsertRequest) (*InsertResponse, error) + Update(context.Context, *UpdateRequest) (*UpdateResponse, error) + Upsert(context.Context, *UpsertRequest) (*UpsertResponse, error) + Fetch(context.Context, *FetchRequest) (*FetchResponse, error) + Delete(context.Context, *DeleteRequest) (*DeleteResponse, error) + List(context.Context, *ListRequest) (*ListResponse, error) +} + +func RegisterKeyValueStoreServer(s *grpc.Server, srv KeyValueStoreServer) { + s.RegisterService(&_KeyValueStore_serviceDesc, srv) +} + +func _KeyValueStore_Insert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(InsertRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).Insert(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/Insert", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).Insert(ctx, req.(*InsertRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyValueStore_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).Update(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/Update", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).Update(ctx, req.(*UpdateRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyValueStore_Upsert_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpsertRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).Upsert(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/Upsert", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).Upsert(ctx, req.(*UpsertRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyValueStore_Fetch_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FetchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).Fetch(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/Fetch", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).Fetch(ctx, req.(*FetchRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyValueStore_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).Delete(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/Delete", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).Delete(ctx, req.(*DeleteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _KeyValueStore_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(KeyValueStoreServer).List(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/memo.kvs.KeyValueStore/List", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(KeyValueStoreServer).List(ctx, req.(*ListRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _KeyValueStore_serviceDesc = grpc.ServiceDesc{ + ServiceName: "memo.kvs.KeyValueStore", + HandlerType: (*KeyValueStoreServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Insert", + Handler: _KeyValueStore_Insert_Handler, + }, + { + MethodName: "Update", + Handler: _KeyValueStore_Update_Handler, + }, + { + MethodName: "Upsert", + Handler: _KeyValueStore_Upsert_Handler, + }, + { + MethodName: "Fetch", + Handler: _KeyValueStore_Fetch_Handler, + }, + { + MethodName: "Delete", + Handler: _KeyValueStore_Delete_Handler, + }, + { + MethodName: "List", + Handler: _KeyValueStore_List_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "memo_kvs.proto", +} + +func init() { proto.RegisterFile("memo_kvs.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 413 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x9c, 0x53, 0xbf, 0x8f, 0xd3, 0x30, + 0x14, 0xbe, 0x5c, 0xda, 0x92, 0xbc, 0x6b, 0x4e, 0x27, 0x0b, 0x7a, 0x56, 0x75, 0x43, 0x88, 0x84, + 0x94, 0x29, 0xc3, 0x31, 0x9c, 0x84, 0xc4, 0x86, 0x90, 0x4e, 0x65, 0x32, 0x82, 0x15, 0x85, 0xf6, + 0x21, 0xa2, 0x34, 0x4d, 0xb0, 0x9d, 0xaa, 0xdd, 0xf8, 0xd3, 0x91, 0x63, 0xbb, 0x71, 0x52, 0x60, + 0xe8, 0x96, 0xf7, 0xfc, 0xbe, 0x1f, 0xcf, 0xfe, 0x02, 0xb7, 0x15, 0x56, 0xf5, 0xb7, 0x72, 0x2f, + 0xb2, 0x86, 0xd7, 0xb2, 0x26, 0x81, 0xaa, 0xb3, 0x72, 0x2f, 0x92, 0x27, 0x88, 0x9e, 0x77, 0x02, + 0xb9, 0x64, 0xf8, 0xab, 0x45, 0x21, 0xc9, 0x1d, 0xf8, 0x25, 0x1e, 0xa9, 0x17, 0x7b, 0x69, 0xc8, + 0xd4, 0x27, 0x79, 0x09, 0xd3, 0x7d, 0xbe, 0x6d, 0x91, 0x5e, 0xc7, 0x5e, 0x3a, 0x67, 0xba, 0x48, + 0xee, 0xe0, 0xd6, 0x02, 0x45, 0x53, 0xef, 0x04, 0x2a, 0xaa, 0x2f, 0xcd, 0x26, 0x97, 0x78, 0x01, + 0x95, 0x05, 0xba, 0x54, 0x17, 0xba, 0xb2, 0x40, 0x43, 0x15, 0xc3, 0xfc, 0x23, 0xca, 0xf5, 0xcf, + 0x7f, 0x32, 0x25, 0x6f, 0x20, 0x32, 0x13, 0x1a, 0xd2, 0x53, 0x7b, 0x2e, 0xf5, 0x6b, 0x88, 0x3e, + 0xe0, 0x16, 0xff, 0xb3, 0x9e, 0x52, 0xb7, 0x23, 0x46, 0xbd, 0x85, 0x9b, 0x4f, 0x85, 0x38, 0xad, + 0xb1, 0x80, 0x59, 0xc3, 0xf1, 0x47, 0x71, 0x30, 0x28, 0x53, 0xa9, 0x7e, 0x95, 0xf3, 0x12, 0x79, + 0xb7, 0x4d, 0xc8, 0x4c, 0x45, 0x1e, 0x20, 0xdc, 0xe0, 0xb6, 0xa8, 0x0a, 0x89, 0x9c, 0xfa, 0xdd, + 0x51, 0xdf, 0x20, 0x14, 0x5e, 0x54, 0xf9, 0x61, 0x85, 0x47, 0x41, 0x27, 0xb1, 0x97, 0x4e, 0x98, + 0x2d, 0x93, 0x07, 0x08, 0x94, 0xec, 0xb3, 0xc4, 0xea, 0x2f, 0x36, 0x39, 0xcc, 0xb5, 0x29, 0xb3, + 0x6f, 0x0a, 0xd3, 0x42, 0x62, 0x25, 0xa8, 0x17, 0xfb, 0xe9, 0xcd, 0x23, 0xc9, 0x6c, 0x3a, 0x32, + 0x4b, 0xc2, 0xf4, 0x00, 0x59, 0x42, 0xa0, 0x1d, 0xa3, 0xa0, 0xd7, 0xb1, 0x9f, 0x86, 0xec, 0x54, + 0x2b, 0xaf, 0x92, 0xb7, 0xbb, 0x75, 0x2e, 0x71, 0xd3, 0x79, 0x0d, 0x58, 0xdf, 0x78, 0xfc, 0xed, + 0x43, 0xb4, 0xc2, 0xe3, 0x57, 0x75, 0x95, 0x9f, 0x65, 0xcd, 0x91, 0xbc, 0x87, 0x99, 0x0e, 0x10, + 0xb9, 0xef, 0x05, 0x07, 0x59, 0x5c, 0xd2, 0xf3, 0x03, 0x73, 0xaf, 0x57, 0x0a, 0xae, 0x43, 0xe3, + 0xc2, 0x07, 0xf9, 0x73, 0xe1, 0xa3, 0x7c, 0x19, 0xf8, 0x58, 0x7d, 0x90, 0xb9, 0x21, 0x7c, 0xa4, + 0xfe, 0x0e, 0xa6, 0x5d, 0x66, 0xc8, 0xa2, 0x1f, 0x72, 0x63, 0xb6, 0xbc, 0x3f, 0xeb, 0xbb, 0xd2, + 0x3a, 0x25, 0xae, 0xf4, 0x20, 0x5a, 0xae, 0xf4, 0x28, 0x50, 0x57, 0xe4, 0x09, 0x26, 0xea, 0x59, + 0xc8, 0xab, 0xe1, 0x33, 0x59, 0xe8, 0x62, 0xdc, 0xb6, 0xc0, 0xef, 0xb3, 0xee, 0xdf, 0x7f, 0xfb, + 0x27, 0x00, 0x00, 0xff, 0xff, 0x6d, 0x76, 0x2d, 0x69, 0x0d, 0x04, 0x00, 0x00, +} diff --git a/store/store.go b/store/store.go index 7a4850c0..4efad4b1 100644 --- a/store/store.go +++ b/store/store.go @@ -18,6 +18,8 @@ const ( ZK Backend = "zk" // BOLTDB backend BOLTDB Backend = "boltdb" + // MEMO backend + MEMO Backend = "memo" ) var ( From 3f5e80880624c88248eb64cc0db873a51c3062e7 Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Mon, 7 Aug 2017 14:24:17 +0200 Subject: [PATCH 4/7] memo: Return ErrKeyNotFound from Delete and List when appropriate. Signed-off-by: Matthieu Nottale --- store/memo/memo.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/store/memo/memo.go b/store/memo/memo.go index 62d56a03..105cecde 100644 --- a/store/memo/memo.go +++ b/store/memo/memo.go @@ -55,6 +55,9 @@ func (s *Memo) Put(key string, value []byte, options *store.WriteOptions) error // Delete value at "key" func (s *Memo) Delete(key string) error { _, err := s.kvs.Delete(context.Background(), &kvs.DeleteRequest{Key: key}) + if err != nil && grpc.Code(err) == codes.NotFound { + return store.ErrKeyNotFound + } return err } @@ -100,6 +103,9 @@ func (s *Memo) List(directory string) ([]*store.KVPair, error) { } res = append(res, kv) } + if len(res) == 0 { + return nil, store.ErrKeyNotFound + } return res, nil } From df74520f4d41716417cf5860532a28b7a953e026 Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Mon, 7 Aug 2017 14:26:34 +0200 Subject: [PATCH 5/7] memo: Test it. Signed-off-by: Matthieu Nottale --- store/memo/memo_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 store/memo/memo_test.go diff --git a/store/memo/memo_test.go b/store/memo/memo_test.go new file mode 100644 index 00000000..8709a66c --- /dev/null +++ b/store/memo/memo_test.go @@ -0,0 +1,17 @@ +package memo + +import ( + "github.com/docker/libkv" + "github.com/docker/libkv/testutils" + "testing" +) + +func TestMemoStore(t *testing.T) { + Register() + kv, err := libkv.NewStore("memo", []string{"localhost:9000"}, nil) + if err != nil { + t.Fatal("error instantiating memo") + } + testutils.RunTestCommon(t, kv) + testutils.RunCleanup(t, kv) +} From 1a8a703cd02fae2919c2d68bc50dc180946ab3cc Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Tue, 8 Aug 2017 11:56:39 +0200 Subject: [PATCH 6/7] travis: Install and start memo kvs. Signed-off-by: Matthieu Nottale --- .travis.yml | 2 ++ script/travis_memo.sh | 17 +++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100755 script/travis_memo.sh diff --git a/.travis.yml b/.travis.yml index 65089e85..bc877c5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,11 +18,13 @@ before_script: - script/travis_consul.sh 0.6.3 - script/travis_etcd.sh 3.0.0 - script/travis_zk.sh 3.5.1-alpha + - script/travis_memo.sh 0.9.2 script: - ./consul agent -server -bootstrap -advertise=127.0.0.1 -data-dir /tmp/consul -config-file=./config.json 1>/dev/null & - ./etcd/etcd --listen-client-urls 'http://0.0.0.0:4001' --advertise-client-urls 'http://127.0.0.1:4001' >/dev/null 2>&1 & - ./script/travis_start_zk.sh + - ./memo/bin/memo kvs run kvs --allow-root-creation --grpc localhost:9000 >/dev/null 2>&1 & - script/validate-gofmt - go vet ./... - fgt golint ./... diff --git a/script/travis_memo.sh b/script/travis_memo.sh new file mode 100755 index 00000000..8f23c1c6 --- /dev/null +++ b/script/travis_memo.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +VERSION=$1 +if test -z "$VERSION"; then + VERSION=0.9.2 +fi + +tarball=https://storage.googleapis.com/sh_infinit_releases/linux64/memo-x86_64-linux_debian_oldstable-gcc4-$VERSION.tbz + +wget "$tarball" +tar -xvf memo-x86_64-linux_debian_oldstable-gcc4-$VERSION.tbz +mv memo-x86_64-linux_debian_oldstable-gcc4-$VERSION memo + +memo/bin/memo user create +memo/bin/memo silo create filesystem silo +memo/bin/memo network create network --silo silo +memo/bin/memo kvs create --name kvs --network network From abaf1d464f7ae5e99a618deea9ad147b5738aca5 Mon Sep 17 00:00:00 2001 From: Matthieu Nottale Date: Thu, 10 Aug 2017 13:40:37 +0200 Subject: [PATCH 7/7] README: Mention memo, update copyright years. Signed-off-by: Matthieu Nottale --- README.md | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index ff2cc446..d0bfa08e 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ You can find examples of usage for `libkv` under in `docs/examples.go`. Optional - Etcd versions >= `2.0` because it uses the new `coreos/etcd/client`, this might change in the future as the support for `APIv3` comes along and adds more capabilities. - Zookeeper versions >= `3.4.5`. Although this might work with previous version but this remains untested as of now. - Boltdb, which shouldn't be subject to any version dependencies. +- Memo version >= 0.9.2. ## Interface @@ -62,19 +63,19 @@ Backend drivers in `libkv` are generally divided between **local drivers** and * Local drivers are usually used in complement to the distributed drivers to store informations that only needs to be available locally. -| Calls | Consul | Etcd | Zookeeper | BoltDB | -|-----------------------|:----------:|:------:|:-----------:|:--------:| -| Put | X | X | X | X | -| Get | X | X | X | X | -| Delete | X | X | X | X | -| Exists | X | X | X | X | -| Watch | X | X | X | | -| WatchTree | X | X | X | | -| NewLock (Lock/Unlock) | X | X | X | | -| List | X | X | X | X | -| DeleteTree | X | X | X | X | -| AtomicPut | X | X | X | X | -| Close | X | X | X | X | +| Calls | Consul | Etcd | Zookeeper | BoltDB | Memo | +|-----------------------|:----------:|:------:|:-----------:|:--------:|:------:| +| Put | X | X | X | X | X | +| Get | X | X | X | X | X | +| Delete | X | X | X | X | X | +| Exists | X | X | X | X | X | +| Watch | X | X | X | | | +| WatchTree | X | X | X | | | +| NewLock (Lock/Unlock) | X | X | X | | | +| List | X | X | X | X | X | +| DeleteTree | X | X | X | X | X | +| AtomicPut | X | X | X | X | | +| Close | X | X | X | X | X | ## Limitations @@ -104,4 +105,4 @@ Want to hack on libkv? [Docker's contributions guidelines](https://github.com/do ## Copyright and license -Copyright © 2014-2016 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license. The README.md file, and files in the "docs" folder are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file "LICENSE.docs". You may obtain a duplicate copy of the same license, titled CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/. +Copyright © 2014-2017 Docker, Inc. All rights reserved, except as follows. Code is released under the Apache 2.0 license. The README.md file, and files in the "docs" folder are licensed under the Creative Commons Attribution 4.0 International License under the terms and conditions set forth in the file "LICENSE.docs". You may obtain a duplicate copy of the same license, titled CC-BY-SA-4.0, at http://creativecommons.org/licenses/by/4.0/.