Skip to content

Commit

Permalink
Merge pull request etcd-io#7221 from fanminshi/grpcproxy_support_leas…
Browse files Browse the repository at this point in the history
…e_coalescing

grpcproxy: support lease coalescing
  • Loading branch information
fanminshi authored Feb 16, 2017
2 parents 507bd2a + 65b59f4 commit a5cf7fd
Show file tree
Hide file tree
Showing 7 changed files with 559 additions and 152 deletions.
9 changes: 6 additions & 3 deletions clientv3/lease.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,16 +144,19 @@ type keepAlive struct {
}

func NewLease(c *Client) Lease {
return NewLeaseFromLeaseClient(RetryLeaseClient(c), c.cfg.DialTimeout+time.Second)
}

func NewLeaseFromLeaseClient(remote pb.LeaseClient, keepAliveTimeout time.Duration) Lease {
l := &lessor{
donec: make(chan struct{}),
keepAlives: make(map[LeaseID]*keepAlive),
remote: RetryLeaseClient(c),
firstKeepAliveTimeout: c.cfg.DialTimeout + time.Second,
remote: remote,
firstKeepAliveTimeout: keepAliveTimeout,
}
if l.firstKeepAliveTimeout == time.Second {
l.firstKeepAliveTimeout = defaultTTL
}

l.stopCtx, l.stopCancel = context.WithCancel(context.Background())
return l
}
Expand Down
2 changes: 1 addition & 1 deletion etcdmain/grpc_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
kvp, _ := grpcproxy.NewKvProxy(client)
watchp, _ := grpcproxy.NewWatchProxy(client)
clusterp := grpcproxy.NewClusterProxy(client)
leasep := grpcproxy.NewLeaseProxy(client)
leasep, _ := grpcproxy.NewLeaseProxy(client)
mainp := grpcproxy.NewMaintenanceProxy(client)
authp := grpcproxy.NewAuthProxy(client)

Expand Down
15 changes: 10 additions & 5 deletions integration/cluster_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type grpcClientProxy struct {
grpc grpcAPI
wdonec <-chan struct{}
kvdonec <-chan struct{}
lpdonec <-chan struct{}
}

func toGRPC(c *clientv3.Client) grpcAPI {
Expand All @@ -42,32 +43,34 @@ func toGRPC(c *clientv3.Client) grpcAPI {
if v, ok := proxies[c]; ok {
return v.grpc
}

wp, wpch := grpcproxy.NewWatchProxy(c)
kvp, kvpch := grpcproxy.NewKvProxy(c)
wp, wpch := grpcproxy.NewWatchProxy(c)
lp, lpch := grpcproxy.NewLeaseProxy(c)
grpc := grpcAPI{
pb.NewClusterClient(c.ActiveConnection()),
grpcproxy.KvServerToKvClient(kvp),
pb.NewLeaseClient(c.ActiveConnection()),
grpcproxy.LeaseServerToLeaseClient(lp),
grpcproxy.WatchServerToWatchClient(wp),
pb.NewMaintenanceClient(c.ActiveConnection()),
pb.NewAuthClient(c.ActiveConnection()),
}
proxies[c] = grpcClientProxy{grpc: grpc, wdonec: wpch, kvdonec: kvpch}
proxies[c] = grpcClientProxy{grpc: grpc, wdonec: wpch, kvdonec: kvpch, lpdonec: lpch}
return grpc
}

type proxyCloser struct {
clientv3.Watcher
wdonec <-chan struct{}
kvdonec <-chan struct{}
lpdonec <-chan struct{}
}

func (pc *proxyCloser) Close() error {
// client ctx is canceled before calling close, so kv will close out
// client ctx is canceled before calling close, so kv and lp will close out
<-pc.kvdonec
err := pc.Watcher.Close()
<-pc.wdonec
<-pc.lpdonec
return err
}

Expand All @@ -79,10 +82,12 @@ func newClientV3(cfg clientv3.Config) (*clientv3.Client, error) {
rpc := toGRPC(c)
c.KV = clientv3.NewKVFromKVClient(rpc.KV)
pmu.Lock()
c.Lease = clientv3.NewLeaseFromLeaseClient(rpc.Lease, cfg.DialTimeout)
c.Watcher = &proxyCloser{
Watcher: clientv3.NewWatchFromWatchClient(rpc.Watch),
wdonec: proxies[c].wdonec,
kvdonec: proxies[c].kvdonec,
lpdonec: proxies[c].lpdonec,
}
pmu.Unlock()
return c, nil
Expand Down
132 changes: 132 additions & 0 deletions proxy/grpcproxy/chan_stream.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2017 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 grpcproxy

import (
"golang.org/x/net/context"

"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
)

// chanServerStream implements grpc.ServerStream with a chanStream
type chanServerStream struct {
headerc chan<- metadata.MD
trailerc chan<- metadata.MD
grpc.Stream

headers []metadata.MD
}

func (ss *chanServerStream) SendHeader(md metadata.MD) error {
if ss.headerc == nil {
return errAlreadySentHeader
}
outmd := make(map[string][]string)
for _, h := range append(ss.headers, md) {
for k, v := range h {
outmd[k] = v
}
}
select {
case ss.headerc <- outmd:
ss.headerc = nil
ss.headers = nil
return nil
case <-ss.Context().Done():
}
return ss.Context().Err()
}

func (ss *chanServerStream) SetHeader(md metadata.MD) error {
if ss.headerc == nil {
return errAlreadySentHeader
}
ss.headers = append(ss.headers, md)
return nil
}

func (ss *chanServerStream) SetTrailer(md metadata.MD) {
ss.trailerc <- md
}

// chanClientStream implements grpc.ClientStream with a chanStream
type chanClientStream struct {
headerc <-chan metadata.MD
trailerc <-chan metadata.MD
*chanStream
}

func (cs *chanClientStream) Header() (metadata.MD, error) {
select {
case md := <-cs.headerc:
return md, nil
case <-cs.Context().Done():
}
return nil, cs.Context().Err()
}

func (cs *chanClientStream) Trailer() metadata.MD {
select {
case md := <-cs.trailerc:
return md
case <-cs.Context().Done():
return nil
}
}

func (cs *chanClientStream) CloseSend() error {
close(cs.chanStream.sendc)
return nil
}

// chanStream implements grpc.Stream using channels
type chanStream struct {
recvc <-chan interface{}
sendc chan<- interface{}
ctx context.Context
cancel context.CancelFunc
}

func (s *chanStream) Context() context.Context { return s.ctx }

func (s *chanStream) SendMsg(m interface{}) error {
select {
case s.sendc <- m:
if err, ok := m.(error); ok {
return err
}
return nil
case <-s.ctx.Done():
}
return s.ctx.Err()
}

func (s *chanStream) RecvMsg(m interface{}) error {
v := m.(*interface{})
select {
case msg, ok := <-s.recvc:
if !ok {
return grpc.ErrClientConnClosing
}
if err, ok := msg.(error); ok {
return err
}
*v = msg
return nil
case <-s.ctx.Done():
}
return s.ctx.Err()
}
Loading

0 comments on commit a5cf7fd

Please sign in to comment.