github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/Godeps/_workspace/src/google.golang.org/grpc/picker.go (about) 1 /* 2 * 3 * Copyright 2014, Google Inc. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following disclaimer 14 * in the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Google Inc. nor the names of its 17 * contributors may be used to endorse or promote products derived from 18 * this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34 package grpc 35 36 import ( 37 "container/list" 38 "fmt" 39 "sync" 40 41 "golang.org/x/net/context" 42 "google.golang.org/grpc/grpclog" 43 "google.golang.org/grpc/naming" 44 "google.golang.org/grpc/transport" 45 ) 46 47 // Picker picks a Conn for RPC requests. 48 // This is EXPERIMENTAL and please do not implement your own Picker for now. 49 type Picker interface { 50 // Init does initial processing for the Picker, e.g., initiate some connections. 51 Init(cc *ClientConn) error 52 // Pick blocks until either a transport.ClientTransport is ready for the upcoming RPC 53 // or some error happens. 54 Pick(ctx context.Context) (transport.ClientTransport, error) 55 // PickAddr picks a peer address for connecting. This will be called repeated for 56 // connecting/reconnecting. 57 PickAddr() (string, error) 58 // State returns the connectivity state of the underlying connections. 59 State() (ConnectivityState, error) 60 // WaitForStateChange blocks until the state changes to something other than 61 // the sourceState. It returns the new state or error. 62 WaitForStateChange(ctx context.Context, sourceState ConnectivityState) (ConnectivityState, error) 63 // Close closes all the Conn's owned by this Picker. 64 Close() error 65 } 66 67 // unicastPicker is the default Picker which is used when there is no custom Picker 68 // specified by users. It always picks the same Conn. 69 type unicastPicker struct { 70 target string 71 conn *Conn 72 } 73 74 func (p *unicastPicker) Init(cc *ClientConn) error { 75 c, err := NewConn(cc) 76 if err != nil { 77 return err 78 } 79 p.conn = c 80 return nil 81 } 82 83 func (p *unicastPicker) Pick(ctx context.Context) (transport.ClientTransport, error) { 84 return p.conn.Wait(ctx) 85 } 86 87 func (p *unicastPicker) PickAddr() (string, error) { 88 return p.target, nil 89 } 90 91 func (p *unicastPicker) State() (ConnectivityState, error) { 92 return p.conn.State(), nil 93 } 94 95 func (p *unicastPicker) WaitForStateChange(ctx context.Context, sourceState ConnectivityState) (ConnectivityState, error) { 96 return p.conn.WaitForStateChange(ctx, sourceState) 97 } 98 99 func (p *unicastPicker) Close() error { 100 if p.conn != nil { 101 return p.conn.Close() 102 } 103 return nil 104 } 105 106 // unicastNamingPicker picks an address from a name resolver to set up the connection. 107 type unicastNamingPicker struct { 108 cc *ClientConn 109 resolver naming.Resolver 110 watcher naming.Watcher 111 mu sync.Mutex 112 // The list of the addresses are obtained from watcher. 113 addrs *list.List 114 // It tracks the current picked addr by PickAddr(). The next PickAddr may 115 // push it forward on addrs. 116 pickedAddr *list.Element 117 conn *Conn 118 } 119 120 // NewUnicastNamingPicker creates a Picker to pick addresses from a name resolver 121 // to connect. 122 func NewUnicastNamingPicker(r naming.Resolver) Picker { 123 return &unicastNamingPicker{ 124 resolver: r, 125 addrs: list.New(), 126 } 127 } 128 129 type addrInfo struct { 130 addr string 131 // Set to true if this addrInfo needs to be deleted in the next PickAddrr() call. 132 deleting bool 133 } 134 135 // processUpdates calls Watcher.Next() once and processes the obtained updates. 136 func (p *unicastNamingPicker) processUpdates() error { 137 updates, err := p.watcher.Next() 138 if err != nil { 139 return err 140 } 141 for _, update := range updates { 142 switch update.Op { 143 case naming.Add: 144 p.mu.Lock() 145 p.addrs.PushBack(&addrInfo{ 146 addr: update.Addr, 147 }) 148 p.mu.Unlock() 149 // Initial connection setup 150 if p.conn == nil { 151 conn, err := NewConn(p.cc) 152 if err != nil { 153 return err 154 } 155 p.conn = conn 156 } 157 case naming.Delete: 158 p.mu.Lock() 159 for e := p.addrs.Front(); e != nil; e = e.Next() { 160 if update.Addr == e.Value.(*addrInfo).addr { 161 if e == p.pickedAddr { 162 // Do not remove the element now if it is the current picked 163 // one. We leave the deletion to the next PickAddr() call. 164 e.Value.(*addrInfo).deleting = true 165 // Notify Conn to close it. All the live RPCs on this connection 166 // will be aborted. 167 p.conn.NotifyReset() 168 } else { 169 p.addrs.Remove(e) 170 } 171 } 172 } 173 p.mu.Unlock() 174 default: 175 grpclog.Println("Unknown update.Op ", update.Op) 176 } 177 } 178 return nil 179 } 180 181 // monitor runs in a standalone goroutine to keep watching name resolution updates until the watcher 182 // is closed. 183 func (p *unicastNamingPicker) monitor() { 184 for { 185 if err := p.processUpdates(); err != nil { 186 return 187 } 188 } 189 } 190 191 func (p *unicastNamingPicker) Init(cc *ClientConn) error { 192 w, err := p.resolver.Resolve(cc.target) 193 if err != nil { 194 return err 195 } 196 p.watcher = w 197 p.cc = cc 198 // Get the initial name resolution. 199 if err := p.processUpdates(); err != nil { 200 return err 201 } 202 go p.monitor() 203 return nil 204 } 205 206 func (p *unicastNamingPicker) Pick(ctx context.Context) (transport.ClientTransport, error) { 207 return p.conn.Wait(ctx) 208 } 209 210 func (p *unicastNamingPicker) PickAddr() (string, error) { 211 p.mu.Lock() 212 defer p.mu.Unlock() 213 if p.pickedAddr == nil { 214 p.pickedAddr = p.addrs.Front() 215 } else { 216 pa := p.pickedAddr 217 p.pickedAddr = pa.Next() 218 if pa.Value.(*addrInfo).deleting { 219 p.addrs.Remove(pa) 220 } 221 if p.pickedAddr == nil { 222 p.pickedAddr = p.addrs.Front() 223 } 224 } 225 if p.pickedAddr == nil { 226 return "", fmt.Errorf("there is no address available to pick") 227 } 228 return p.pickedAddr.Value.(*addrInfo).addr, nil 229 } 230 231 func (p *unicastNamingPicker) State() (ConnectivityState, error) { 232 return 0, fmt.Errorf("State() is not supported for unicastNamingPicker") 233 } 234 235 func (p *unicastNamingPicker) WaitForStateChange(ctx context.Context, sourceState ConnectivityState) (ConnectivityState, error) { 236 return 0, fmt.Errorf("WaitForStateChange is not supported for unicastNamingPciker") 237 } 238 239 func (p *unicastNamingPicker) Close() error { 240 p.watcher.Close() 241 p.conn.Close() 242 return nil 243 }