github.com/macb/etcd@v0.3.1-0.20140227003422-a60481c6b1a0/server/transporter.go (about)

     1  package server
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"io"
     8  	"net"
     9  	"net/http"
    10  	"time"
    11  
    12  	"github.com/coreos/etcd/log"
    13  	"github.com/coreos/etcd/third_party/github.com/coreos/raft"
    14  )
    15  
    16  // Transporter layer for communication between raft nodes
    17  type transporter struct {
    18  	requestTimeout	time.Duration
    19  	followersStats	*raftFollowersStats
    20  	serverStats	*raftServerStats
    21  	registry	*Registry
    22  
    23  	client		*http.Client
    24  	transport	*http.Transport
    25  }
    26  
    27  type dialer func(network, addr string) (net.Conn, error)
    28  
    29  // Create transporter using by raft server
    30  // Create http or https transporter based on
    31  // whether the user give the server cert and key
    32  func NewTransporter(followersStats *raftFollowersStats, serverStats *raftServerStats, registry *Registry, dialTimeout, requestTimeout, responseHeaderTimeout time.Duration) *transporter {
    33  	tr := &http.Transport{
    34  		Dial: func(network, addr string) (net.Conn, error) {
    35  			return net.DialTimeout(network, addr, dialTimeout)
    36  		},
    37  		ResponseHeaderTimeout:	responseHeaderTimeout,
    38  	}
    39  
    40  	t := transporter{
    41  		client:		&http.Client{Transport: tr},
    42  		transport:	tr,
    43  		requestTimeout:	requestTimeout,
    44  		followersStats:	followersStats,
    45  		serverStats:	serverStats,
    46  		registry:	registry,
    47  	}
    48  
    49  	return &t
    50  }
    51  
    52  func (t *transporter) SetTLSConfig(tlsConf tls.Config) {
    53  	t.transport.TLSClientConfig = &tlsConf
    54  	t.transport.DisableCompression = true
    55  }
    56  
    57  // Sends AppendEntries RPCs to a peer when the server is the leader.
    58  func (t *transporter) SendAppendEntriesRequest(server raft.Server, peer *raft.Peer, req *raft.AppendEntriesRequest) *raft.AppendEntriesResponse {
    59  	var b bytes.Buffer
    60  
    61  	if _, err := req.Encode(&b); err != nil {
    62  		log.Warn("transporter.ae.encoding.error:", err)
    63  		return nil
    64  	}
    65  
    66  	size := b.Len()
    67  
    68  	t.serverStats.SendAppendReq(size)
    69  
    70  	u, _ := t.registry.PeerURL(peer.Name)
    71  
    72  	log.Debugf("Send LogEntries to %s ", u)
    73  
    74  	thisFollowerStats, ok := t.followersStats.Followers[peer.Name]
    75  
    76  	if !ok {	//this is the first time this follower has been seen
    77  		thisFollowerStats = &raftFollowerStats{}
    78  		thisFollowerStats.Latency.Minimum = 1 << 63
    79  		t.followersStats.Followers[peer.Name] = thisFollowerStats
    80  	}
    81  
    82  	start := time.Now()
    83  
    84  	resp, httpRequest, err := t.Post(fmt.Sprintf("%s/log/append", u), &b)
    85  
    86  	end := time.Now()
    87  
    88  	if err != nil {
    89  		log.Debugf("Cannot send AppendEntriesRequest to %s: %s", u, err)
    90  		if ok {
    91  			thisFollowerStats.Fail()
    92  		}
    93  		return nil
    94  	} else {
    95  		if ok {
    96  			thisFollowerStats.Succ(end.Sub(start))
    97  		}
    98  	}
    99  
   100  	if resp != nil {
   101  		defer resp.Body.Close()
   102  
   103  		t.CancelWhenTimeout(httpRequest)
   104  
   105  		aeresp := &raft.AppendEntriesResponse{}
   106  		if _, err = aeresp.Decode(resp.Body); err != nil && err != io.EOF {
   107  			log.Warn("transporter.ae.decoding.error:", err)
   108  			return nil
   109  		}
   110  		return aeresp
   111  	}
   112  
   113  	return nil
   114  }
   115  
   116  // Sends RequestVote RPCs to a peer when the server is the candidate.
   117  func (t *transporter) SendVoteRequest(server raft.Server, peer *raft.Peer, req *raft.RequestVoteRequest) *raft.RequestVoteResponse {
   118  	var b bytes.Buffer
   119  
   120  	if _, err := req.Encode(&b); err != nil {
   121  		log.Warn("transporter.vr.encoding.error:", err)
   122  		return nil
   123  	}
   124  
   125  	u, _ := t.registry.PeerURL(peer.Name)
   126  	log.Debugf("Send Vote from %s to %s", server.Name(), u)
   127  
   128  	resp, httpRequest, err := t.Post(fmt.Sprintf("%s/vote", u), &b)
   129  
   130  	if err != nil {
   131  		log.Debugf("Cannot send VoteRequest to %s : %s", u, err)
   132  	}
   133  
   134  	if resp != nil {
   135  		defer resp.Body.Close()
   136  
   137  		t.CancelWhenTimeout(httpRequest)
   138  
   139  		rvrsp := &raft.RequestVoteResponse{}
   140  		if _, err = rvrsp.Decode(resp.Body); err != nil && err != io.EOF {
   141  			log.Warn("transporter.vr.decoding.error:", err)
   142  			return nil
   143  		}
   144  		return rvrsp
   145  	}
   146  	return nil
   147  }
   148  
   149  // Sends SnapshotRequest RPCs to a peer when the server is the candidate.
   150  func (t *transporter) SendSnapshotRequest(server raft.Server, peer *raft.Peer, req *raft.SnapshotRequest) *raft.SnapshotResponse {
   151  	var b bytes.Buffer
   152  
   153  	if _, err := req.Encode(&b); err != nil {
   154  		log.Warn("transporter.ss.encoding.error:", err)
   155  		return nil
   156  	}
   157  
   158  	u, _ := t.registry.PeerURL(peer.Name)
   159  	log.Debugf("Send Snapshot Request from %s to %s", server.Name(), u)
   160  
   161  	resp, httpRequest, err := t.Post(fmt.Sprintf("%s/snapshot", u), &b)
   162  
   163  	if err != nil {
   164  		log.Debugf("Cannot send Snapshot Request to %s : %s", u, err)
   165  	}
   166  
   167  	if resp != nil {
   168  		defer resp.Body.Close()
   169  
   170  		t.CancelWhenTimeout(httpRequest)
   171  
   172  		ssrsp := &raft.SnapshotResponse{}
   173  		if _, err = ssrsp.Decode(resp.Body); err != nil && err != io.EOF {
   174  			log.Warn("transporter.ss.decoding.error:", err)
   175  			return nil
   176  		}
   177  		return ssrsp
   178  	}
   179  	return nil
   180  }
   181  
   182  // Sends SnapshotRecoveryRequest RPCs to a peer when the server is the candidate.
   183  func (t *transporter) SendSnapshotRecoveryRequest(server raft.Server, peer *raft.Peer, req *raft.SnapshotRecoveryRequest) *raft.SnapshotRecoveryResponse {
   184  	var b bytes.Buffer
   185  
   186  	if _, err := req.Encode(&b); err != nil {
   187  		log.Warn("transporter.ss.encoding.error:", err)
   188  		return nil
   189  	}
   190  
   191  	u, _ := t.registry.PeerURL(peer.Name)
   192  	log.Debugf("Send Snapshot Recovery from %s to %s", server.Name(), u)
   193  
   194  	resp, httpRequest, err := t.Post(fmt.Sprintf("%s/snapshotRecovery", u), &b)
   195  
   196  	if err != nil {
   197  		log.Debugf("Cannot send Snapshot Recovery to %s : %s", u, err)
   198  	}
   199  
   200  	if resp != nil {
   201  		defer resp.Body.Close()
   202  
   203  		t.CancelWhenTimeout(httpRequest)
   204  
   205  		ssrrsp := &raft.SnapshotRecoveryResponse{}
   206  		if _, err = ssrrsp.Decode(resp.Body); err != nil && err != io.EOF {
   207  			log.Warn("transporter.ssr.decoding.error:", err)
   208  			return nil
   209  		}
   210  		return ssrrsp
   211  	}
   212  	return nil
   213  
   214  }
   215  
   216  // Send server side POST request
   217  func (t *transporter) Post(urlStr string, body io.Reader) (*http.Response, *http.Request, error) {
   218  	req, _ := http.NewRequest("POST", urlStr, body)
   219  	resp, err := t.client.Do(req)
   220  	return resp, req, err
   221  }
   222  
   223  // Send server side GET request
   224  func (t *transporter) Get(urlStr string) (*http.Response, *http.Request, error) {
   225  	req, _ := http.NewRequest("GET", urlStr, nil)
   226  	resp, err := t.client.Do(req)
   227  	return resp, req, err
   228  }
   229  
   230  // Cancel the on fly HTTP transaction when timeout happens.
   231  func (t *transporter) CancelWhenTimeout(req *http.Request) {
   232  	go func() {
   233  		time.Sleep(t.requestTimeout)
   234  		t.transport.CancelRequest(req)
   235  	}()
   236  }