From: Brad Fitzpatrick Date: Thu, 28 Mar 2013 20:07:14 +0000 (-0700) Subject: net/http: remove two more server allocations per-request X-Git-Tag: go1.1rc2~290 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=42a840860f60b3e66c7bcd755795d193935a05cc;p=gostls13.git net/http: remove two more server allocations per-request benchmark old ns/op new ns/op delta BenchmarkServerFakeConnWithKeepAliveLite 11031 10689 -3.10% benchmark old allocs new allocs delta BenchmarkServerFakeConnWithKeepAliveLite 23 21 -8.70% benchmark old bytes new bytes delta BenchmarkServerFakeConnWithKeepAliveLite 1668 1626 -2.52% R=golang-dev, gri CC=golang-dev https://golang.org/cl/8110044 --- diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index c38c4c8e15..3a0cca7fdc 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -763,8 +763,40 @@ func (cw *chunkWriter) writeHeader(p []byte) { cw.header.Set("Connection", "close") } + io.WriteString(w.conn.buf, statusLine(w.req, code)) + cw.header.Write(w.conn.buf) + w.conn.buf.Write(crlf) +} + +// statusLines is a cache of Status-Line strings, keyed by code (for +// HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a +// map keyed by struct of two fields. This map's max size is bounded +// by 2*len(statusText), two protocol types for each known official +// status code in the statusText map. +var ( + statusMu sync.RWMutex + statusLines = make(map[int]string) +) + +// statusLine returns a response Status-Line (RFC 2616 Section 6.1) +// for the given request and response status code. +func statusLine(req *Request, code int) string { + // Fast path: + key := code + proto11 := req.ProtoAtLeast(1, 1) + if !proto11 { + key = -key + } + statusMu.RLock() + line, ok := statusLines[key] + statusMu.RUnlock() + if ok { + return line + } + + // Slow path: proto := "HTTP/1.0" - if w.req.ProtoAtLeast(1, 1) { + if proto11 { proto = "HTTP/1.1" } codestring := strconv.Itoa(code) @@ -772,9 +804,13 @@ func (cw *chunkWriter) writeHeader(p []byte) { if !ok { text = "status code " + codestring } - io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n") - cw.header.Write(w.conn.buf) - w.conn.buf.Write(crlf) + line = proto + " " + codestring + " " + text + "\r\n" + if ok { + statusMu.Lock() + defer statusMu.Unlock() + statusLines[key] = line + } + return line } // bodyAllowed returns true if a Write is allowed for this response type.