mirror of https://github.com/jlelse/GoBlog
4 changed files with 215 additions and 70 deletions
@ -0,0 +1,64 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"net/http" |
||||
) |
||||
|
||||
// cacheRecorder is an implementation of http.ResponseWriter
|
||||
type cacheRecorder struct { |
||||
item *cacheItem |
||||
} |
||||
|
||||
func newCacheRecorder() *cacheRecorder { |
||||
return &cacheRecorder{ |
||||
item: &cacheItem{ |
||||
code: http.StatusOK, |
||||
header: make(http.Header), |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func (c *cacheRecorder) finish() (ci *cacheItem) { |
||||
ci = c.item |
||||
c.item = nil |
||||
return |
||||
} |
||||
|
||||
// Header implements http.ResponseWriter.
|
||||
func (rw *cacheRecorder) Header() http.Header { |
||||
if rw.item == nil { |
||||
return nil |
||||
} |
||||
return rw.item.header |
||||
} |
||||
|
||||
// Write implements http.ResponseWriter.
|
||||
func (rw *cacheRecorder) Write(buf []byte) (int, error) { |
||||
if rw.item == nil { |
||||
return 0, nil |
||||
} |
||||
rw.item.body = append(rw.item.body, buf...) |
||||
return len(buf), nil |
||||
} |
||||
|
||||
// WriteString implements io.StringWriter.
|
||||
func (rw *cacheRecorder) WriteString(str string) (int, error) { |
||||
return rw.Write([]byte(str)) |
||||
} |
||||
|
||||
// WriteHeader implements http.ResponseWriter.
|
||||
func (rw *cacheRecorder) WriteHeader(code int) { |
||||
if rw.item == nil { |
||||
return |
||||
} |
||||
if code < 100 || code > 999 { |
||||
panic(fmt.Sprintf("invalid WriteHeader code %v", code)) |
||||
} |
||||
rw.item.code = code |
||||
} |
||||
|
||||
// Flush implements http.Flusher.
|
||||
func (rw *cacheRecorder) Flush() { |
||||
// Do nothing
|
||||
} |
@ -0,0 +1,71 @@
|
||||
package main |
||||
|
||||
import ( |
||||
"io" |
||||
"net/http" |
||||
"net/http/httptest" |
||||
"strconv" |
||||
"testing" |
||||
"time" |
||||
|
||||
"github.com/dgraph-io/ristretto" |
||||
"github.com/stretchr/testify/assert" |
||||
) |
||||
|
||||
func Benchmark_cacheItem_cost(b *testing.B) { |
||||
ci := &cacheItem{ |
||||
creationTime: time.Now(), |
||||
eTag: "abc", |
||||
code: 200, |
||||
header: http.Header{ |
||||
"Content-Type": []string{"text/html"}, |
||||
}, |
||||
body: []byte("<html>abcdefghijklmnopqrstuvwxyz</html>"), |
||||
} |
||||
b.RunParallel(func(p *testing.PB) { |
||||
for p.Next() { |
||||
ci.cost() |
||||
} |
||||
}) |
||||
} |
||||
|
||||
func Test_cacheItem_cost(t *testing.T) { |
||||
ci := &cacheItem{ |
||||
header: http.Header{ |
||||
"Content-Type": []string{"text/html"}, |
||||
}, |
||||
body: []byte("<html>abcdefghijklmnopqrstuvwxyz</html>"), |
||||
eTag: "abc", |
||||
} |
||||
bodyLen := len(ci.body) |
||||
assert.Equal(t, 39, bodyLen) |
||||
eTagLen := len(ci.eTag) |
||||
assert.Equal(t, 3, eTagLen) |
||||
assert.Greater(t, ci.cost(), bodyLen+eTagLen) |
||||
} |
||||
|
||||
func Benchmark_cacheKey(b *testing.B) { |
||||
req := httptest.NewRequest(http.MethodGet, "/abc?abc=def&hij=klm", nil) |
||||
b.RunParallel(func(p *testing.PB) { |
||||
for p.Next() { |
||||
cacheKey(req) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
func Benchmark_cache_getCache(b *testing.B) { |
||||
c := &cache{} |
||||
c.c, _ = ristretto.NewCache(&ristretto.Config{ |
||||
NumCounters: 40 * 1000, |
||||
MaxCost: 20 * 1000 * 1000, |
||||
BufferItems: 64, |
||||
}) |
||||
req := httptest.NewRequest(http.MethodGet, "/abc?abc=def&hij=klm", nil) |
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
_, _ = io.WriteString(w, "abcdefghijklmnopqrstuvwxyz") |
||||
_, _ = w.Write([]byte("abcdefghijklmnopqrstuvwxyz")) |
||||
}) |
||||
for i := 0; i < b.N; i++ { |
||||
c.getCache(strconv.Itoa(i), handler, req) |
||||
} |
||||
} |
Loading…
Reference in new issue