// Copyright 2016 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 ( "sync" "golang.org/x/net/context" "google.golang.org/grpc" ) type remoteClient struct { client *Client conn *grpc.ClientConn updateConn func(*grpc.ClientConn) mu sync.Mutex } func newRemoteClient(client *Client, update func(*grpc.ClientConn)) *remoteClient { ret := &remoteClient{ client: client, conn: client.ActiveConnection(), updateConn: update, } ret.mu.Lock() defer ret.mu.Unlock() ret.updateConn(ret.conn) return ret } // reconnectWait reconnects the client, returning when connection establishes/fails. func (r *remoteClient) reconnectWait(ctx context.Context, prevErr error) error { r.mu.Lock() updated := r.tryUpdate() r.mu.Unlock() if updated { return nil } conn, err := r.client.connWait(ctx, prevErr) if err == nil { r.mu.Lock() r.conn = conn r.updateConn(conn) r.mu.Unlock() } return err } // reconnect will reconnect the client without waiting func (r *remoteClient) reconnect(err error) { r.mu.Lock() defer r.mu.Unlock() if r.tryUpdate() { return } r.client.connStartRetry(err) } func (r *remoteClient) tryUpdate() bool { activeConn := r.client.ActiveConnection() if activeConn == nil || activeConn == r.conn { return false } r.conn = activeConn r.updateConn(activeConn) return true } func (r *remoteClient) acquire(ctx context.Context) error { for { r.client.mu.RLock() c := r.client.conn r.mu.Lock() match := r.conn == c r.mu.Unlock() if match { return nil } r.client.mu.RUnlock() if err := r.reconnectWait(ctx, nil); err != nil { return err } } } func (r *remoteClient) release() { r.client.mu.RUnlock() }