diff --git a/.travis.yml b/.travis.yml index a7a3bcff..bc877c5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,14 +18,18 @@ 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 & - - ./zk/bin/zkServer.sh start ./zk/conf/zoo.cfg 1> /dev/null + - ./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 ./... - go test -v -race ./... - script/coverage - goveralls -service=travis-ci -coverprofile=goverage.report + +dist: trusty 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/. 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 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 diff --git a/store/memo/memo.go b/store/memo/memo.go new file mode 100644 index 00000000..105cecde --- /dev/null +++ b/store/memo/memo.go @@ -0,0 +1,137 @@ +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}) + if err != nil && grpc.Code(err) == codes.NotFound { + return store.ErrKeyNotFound + } + 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) + } + if len(res) == 0 { + return nil, store.ErrKeyNotFound + } + 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/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) +} 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 (