1 /* 2 * 3 * Copyright 2022 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package outlierdetection 19 20 import ( 21 "fmt" 22 "unsafe" 23 24 "google.golang.org/grpc/balancer" 25 "google.golang.org/grpc/internal/buffer" 26 "google.golang.org/grpc/resolver" 27 ) 28 29 // subConnWrapper wraps every created SubConn in the Outlier Detection Balancer, 30 // to help track the latest state update from the underlying SubConn, and also 31 // whether or not this SubConn is ejected. 32 type subConnWrapper struct { 33 balancer.SubConn 34 listener func(balancer.SubConnState) 35 36 // addressInfo is a pointer to the subConnWrapper's corresponding address 37 // map entry, if the map entry exists. 38 addressInfo unsafe.Pointer // *addressInfo 39 // These two pieces of state will reach eventual consistency due to sync in 40 // run(), and child will always have the correctly updated SubConnState. 41 // latestState is the latest state update from the underlying SubConn. This 42 // is used whenever a SubConn gets unejected. 43 latestState balancer.SubConnState 44 ejected bool 45 46 scUpdateCh *buffer.Unbounded 47 48 // addresses is the list of address(es) this SubConn was created with to 49 // help support any change in address(es) 50 addresses []resolver.Address 51 } 52 53 // eject causes the wrapper to report a state update with the TRANSIENT_FAILURE 54 // state, and to stop passing along updates from the underlying subchannel. 55 func (scw *subConnWrapper) eject() { 56 scw.scUpdateCh.Put(&ejectionUpdate{ 57 scw: scw, 58 isEjected: true, 59 }) 60 } 61 62 // uneject causes the wrapper to report a state update with the latest update 63 // from the underlying subchannel, and resume passing along updates from the 64 // underlying subchannel. 65 func (scw *subConnWrapper) uneject() { 66 scw.scUpdateCh.Put(&ejectionUpdate{ 67 scw: scw, 68 isEjected: false, 69 }) 70 } 71 72 func (scw *subConnWrapper) String() string { 73 return fmt.Sprintf("%+v", scw.addresses) 74 } 75