github.com/kafkaliu/etcd@v0.1.2-0.20131007164923-44c16dd30d69/transporter.go (about) 1 /* 2 Copyright 2013 CoreOS Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "bytes" 21 "crypto/tls" 22 "encoding/json" 23 "fmt" 24 "io" 25 "net" 26 "net/http" 27 "time" 28 29 "github.com/coreos/go-raft" 30 ) 31 32 // Timeout for setup internal raft http connection 33 // This should not exceed 3 * RTT 34 var dailTimeout = 3 * HeartbeatTimeout 35 36 // Timeout for setup internal raft http connection + receive response header 37 // This should not exceed 3 * RTT + RTT 38 var responseHeaderTimeout = 4 * HeartbeatTimeout 39 40 // Timeout for receiving the response body from the server 41 // This should not exceed election timeout 42 var tranTimeout = ElectionTimeout 43 44 // Transporter layer for communication between raft nodes 45 type transporter struct { 46 client *http.Client 47 transport *http.Transport 48 } 49 50 // Create transporter using by raft server 51 // Create http or https transporter based on 52 // whether the user give the server cert and key 53 func newTransporter(scheme string, tlsConf tls.Config) *transporter { 54 t := transporter{} 55 56 tr := &http.Transport{ 57 Dial: dialWithTimeout, 58 ResponseHeaderTimeout: responseHeaderTimeout, 59 } 60 61 if scheme == "https" { 62 tr.TLSClientConfig = &tlsConf 63 tr.DisableCompression = true 64 } 65 66 t.client = &http.Client{Transport: tr} 67 t.transport = tr 68 69 return &t 70 } 71 72 // Dial with timeout 73 func dialWithTimeout(network, addr string) (net.Conn, error) { 74 return net.DialTimeout(network, addr, dailTimeout) 75 } 76 77 // Sends AppendEntries RPCs to a peer when the server is the leader. 78 func (t *transporter) SendAppendEntriesRequest(server *raft.Server, peer *raft.Peer, req *raft.AppendEntriesRequest) *raft.AppendEntriesResponse { 79 var aersp *raft.AppendEntriesResponse 80 var b bytes.Buffer 81 82 json.NewEncoder(&b).Encode(req) 83 84 size := b.Len() 85 86 r.serverStats.SendAppendReq(size) 87 88 u, _ := nameToRaftURL(peer.Name) 89 90 debugf("Send LogEntries to %s ", u) 91 92 thisFollowerStats, ok := r.followersStats.Followers[peer.Name] 93 94 if !ok { //this is the first time this follower has been seen 95 thisFollowerStats = &raftFollowerStats{} 96 thisFollowerStats.Latency.Minimum = 1 << 63 97 r.followersStats.Followers[peer.Name] = thisFollowerStats 98 } 99 100 start := time.Now() 101 102 resp, httpRequest, err := t.Post(fmt.Sprintf("%s/log/append", u), &b) 103 104 end := time.Now() 105 106 if err != nil { 107 debugf("Cannot send AppendEntriesRequest to %s: %s", u, err) 108 if ok { 109 thisFollowerStats.Fail() 110 } 111 } else { 112 if ok { 113 thisFollowerStats.Succ(end.Sub(start)) 114 } 115 } 116 117 if resp != nil { 118 defer resp.Body.Close() 119 120 t.CancelWhenTimeout(httpRequest) 121 122 aersp = &raft.AppendEntriesResponse{} 123 if err := json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF { 124 return aersp 125 } 126 127 } 128 129 return aersp 130 } 131 132 // Sends RequestVote RPCs to a peer when the server is the candidate. 133 func (t *transporter) SendVoteRequest(server *raft.Server, peer *raft.Peer, req *raft.RequestVoteRequest) *raft.RequestVoteResponse { 134 var rvrsp *raft.RequestVoteResponse 135 var b bytes.Buffer 136 json.NewEncoder(&b).Encode(req) 137 138 u, _ := nameToRaftURL(peer.Name) 139 debugf("Send Vote to %s", u) 140 141 resp, httpRequest, err := t.Post(fmt.Sprintf("%s/vote", u), &b) 142 143 if err != nil { 144 debugf("Cannot send VoteRequest to %s : %s", u, err) 145 } 146 147 if resp != nil { 148 defer resp.Body.Close() 149 150 t.CancelWhenTimeout(httpRequest) 151 152 rvrsp := &raft.RequestVoteResponse{} 153 if err := json.NewDecoder(resp.Body).Decode(&rvrsp); err == nil || err == io.EOF { 154 return rvrsp 155 } 156 157 } 158 return rvrsp 159 } 160 161 // Sends SnapshotRequest RPCs to a peer when the server is the candidate. 162 func (t *transporter) SendSnapshotRequest(server *raft.Server, peer *raft.Peer, req *raft.SnapshotRequest) *raft.SnapshotResponse { 163 var aersp *raft.SnapshotResponse 164 var b bytes.Buffer 165 json.NewEncoder(&b).Encode(req) 166 167 u, _ := nameToRaftURL(peer.Name) 168 debugf("Send Snapshot to %s [Last Term: %d, LastIndex %d]", u, 169 req.LastTerm, req.LastIndex) 170 171 resp, httpRequest, err := t.Post(fmt.Sprintf("%s/snapshot", u), &b) 172 173 if err != nil { 174 debugf("Cannot send SendSnapshotRequest to %s : %s", u, err) 175 } 176 177 if resp != nil { 178 defer resp.Body.Close() 179 180 t.CancelWhenTimeout(httpRequest) 181 182 aersp = &raft.SnapshotResponse{} 183 if err = json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF { 184 185 return aersp 186 } 187 } 188 189 return aersp 190 } 191 192 // Sends SnapshotRecoveryRequest RPCs to a peer when the server is the candidate. 193 func (t *transporter) SendSnapshotRecoveryRequest(server *raft.Server, peer *raft.Peer, req *raft.SnapshotRecoveryRequest) *raft.SnapshotRecoveryResponse { 194 var aersp *raft.SnapshotRecoveryResponse 195 var b bytes.Buffer 196 json.NewEncoder(&b).Encode(req) 197 198 u, _ := nameToRaftURL(peer.Name) 199 debugf("Send SnapshotRecovery to %s [Last Term: %d, LastIndex %d]", u, 200 req.LastTerm, req.LastIndex) 201 202 resp, _, err := t.Post(fmt.Sprintf("%s/snapshotRecovery", u), &b) 203 204 if err != nil { 205 debugf("Cannot send SendSnapshotRecoveryRequest to %s : %s", u, err) 206 } 207 208 if resp != nil { 209 defer resp.Body.Close() 210 aersp = &raft.SnapshotRecoveryResponse{} 211 212 if err = json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF { 213 return aersp 214 } 215 } 216 217 return aersp 218 } 219 220 // Send server side POST request 221 func (t *transporter) Post(urlStr string, body io.Reader) (*http.Response, *http.Request, error) { 222 223 req, _ := http.NewRequest("POST", urlStr, body) 224 225 resp, err := t.client.Do(req) 226 227 return resp, req, err 228 229 } 230 231 // Send server side GET request 232 func (t *transporter) Get(urlStr string) (*http.Response, *http.Request, error) { 233 234 req, _ := http.NewRequest("GET", urlStr, nil) 235 236 resp, err := t.client.Do(req) 237 238 return resp, req, err 239 } 240 241 // Cancel the on fly HTTP transaction when timeout happens 242 func (t *transporter) CancelWhenTimeout(req *http.Request) { 243 go func() { 244 time.Sleep(ElectionTimeout) 245 t.transport.CancelRequest(req) 246 }() 247 }