Reduce allocations

Store temporary buffers in a sync.Pool.

Create one httpGetter per peer when Set() is called so we don't
allocate a new one on each call PickPeer().
diff --git a/http.go b/http.go
index abc25a3..8f637d7 100644
--- a/http.go
+++ b/http.go
@@ -17,8 +17,9 @@
 package groupcache
 
 import (
+	"bytes"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/url"
 	"strings"
@@ -51,8 +52,9 @@
 	// this peer's base URL, e.g. "https://example.net:8000"
 	self string
 
-	mu    sync.Mutex
-	peers *consistenthash.Map
+	mu          sync.Mutex // guards peers and httpGetters
+	peers       *consistenthash.Map
+	httpGetters map[string]*httpGetter // keyed by e.g. "http://10.0.0.2:8008"
 }
 
 // HTTPPoolOptions are the configurations of a HTTPPool.
@@ -103,9 +105,10 @@
 	}
 
 	p := &HTTPPool{
-		basePath: opts.BasePath,
-		self:     self,
-		peers:    consistenthash.New(opts.Replicas, opts.HashFn),
+		basePath:    opts.BasePath,
+		self:        self,
+		peers:       consistenthash.New(opts.Replicas, opts.HashFn),
+		httpGetters: make(map[string]*httpGetter),
 	}
 	RegisterPeerPicker(func() PeerPicker { return p })
 	return p
@@ -119,6 +122,10 @@
 	defer p.mu.Unlock()
 	p.peers = consistenthash.New(defaultReplicas, nil)
 	p.peers.Add(peers...)
+	p.httpGetters = make(map[string]*httpGetter, len(peers))
+	for _, peer := range peers {
+		p.httpGetters[peer] = &httpGetter{transport: p.Transport, baseURL: peer + p.basePath}
+	}
 }
 
 func (p *HTTPPool) PickPeer(key string) (ProtoGetter, bool) {
@@ -128,9 +135,7 @@
 		return nil, false
 	}
 	if peer := p.peers.Get(key); peer != p.self {
-		// TODO: pre-build a slice of *httpGetter when Set()
-		// is called to avoid these two allocations.
-		return &httpGetter{p.Transport, peer + p.basePath}, true
+		return p.httpGetters[peer], true
 	}
 	return nil, false
 }
@@ -182,6 +187,10 @@
 	baseURL   string
 }
 
+var bufferPool = sync.Pool{
+	New: func() interface{} { return new(bytes.Buffer) },
+}
+
 func (h *httpGetter) Get(context Context, in *pb.GetRequest, out *pb.GetResponse) error {
 	u := fmt.Sprintf(
 		"%v%v/%v",
@@ -205,12 +214,14 @@
 	if res.StatusCode != http.StatusOK {
 		return fmt.Errorf("server returned: %v", res.Status)
 	}
-	// TODO: avoid this garbage.
-	b, err := ioutil.ReadAll(res.Body)
+	b := bufferPool.Get().(*bytes.Buffer)
+	b.Reset()
+	defer bufferPool.Put(b)
+	_, err = io.Copy(b, res.Body)
 	if err != nil {
 		return fmt.Errorf("reading response body: %v", err)
 	}
-	err = proto.Unmarshal(b, out)
+	err = proto.Unmarshal(b.Bytes(), out)
 	if err != nil {
 		return fmt.Errorf("decoding response body: %v", err)
 	}