Move cache Keys to 64bit for a better dispersion and lower collision frequency (#2077)
* - change Key for cache to 64bits. * - change Key for cache to 64bits.
This commit is contained in:
parent
d00e8c3918
commit
4c6c9d4b27
6 changed files with 43 additions and 41 deletions
30
plugin/cache/cache.go
vendored
30
plugin/cache/cache.go
vendored
|
@ -60,24 +60,24 @@ func New() *Cache {
|
|||
// Return key under which we store the item, -1 will be returned if we don't store the
|
||||
// message.
|
||||
// Currently we do not cache Truncated, errors zone transfers or dynamic update messages.
|
||||
func key(m *dns.Msg, t response.Type, do bool) int {
|
||||
func key(m *dns.Msg, t response.Type, do bool) (bool, uint64) {
|
||||
// We don't store truncated responses.
|
||||
if m.Truncated {
|
||||
return -1
|
||||
return false, 0
|
||||
}
|
||||
// Nor errors or Meta or Update
|
||||
if t == response.OtherError || t == response.Meta || t == response.Update {
|
||||
return -1
|
||||
return false, 0
|
||||
}
|
||||
|
||||
return int(hash(m.Question[0].Name, m.Question[0].Qtype, do))
|
||||
return true, hash(m.Question[0].Name, m.Question[0].Qtype, do)
|
||||
}
|
||||
|
||||
var one = []byte("1")
|
||||
var zero = []byte("0")
|
||||
|
||||
func hash(qname string, qtype uint16, do bool) uint32 {
|
||||
h := fnv.New32()
|
||||
func hash(qname string, qtype uint16, do bool) uint64 {
|
||||
h := fnv.New64()
|
||||
|
||||
if do {
|
||||
h.Write(one)
|
||||
|
@ -97,7 +97,7 @@ func hash(qname string, qtype uint16, do bool) uint32 {
|
|||
h.Write([]byte{c})
|
||||
}
|
||||
|
||||
return h.Sum32()
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
// ResponseWriter is a response writer that caches the reply message.
|
||||
|
@ -152,7 +152,7 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||
}
|
||||
|
||||
// key returns empty string for anything we don't want to cache.
|
||||
key := key(res, mt, do)
|
||||
hasKey, key := key(res, mt, do)
|
||||
|
||||
duration := w.pttl
|
||||
if mt == response.NameError || mt == response.NoData {
|
||||
|
@ -164,7 +164,7 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||
duration = msgTTL
|
||||
}
|
||||
|
||||
if key != -1 && duration > 0 {
|
||||
if hasKey && duration > 0 {
|
||||
if w.state.Match(res) {
|
||||
w.set(res, key, mt, duration)
|
||||
cacheSize.WithLabelValues(w.server, Success).Set(float64(w.pcache.Len()))
|
||||
|
@ -195,19 +195,17 @@ func (w *ResponseWriter) WriteMsg(res *dns.Msg) error {
|
|||
return w.ResponseWriter.WriteMsg(res)
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) set(m *dns.Msg, key int, mt response.Type, duration time.Duration) {
|
||||
if key == -1 || duration == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
func (w *ResponseWriter) set(m *dns.Msg, key uint64, mt response.Type, duration time.Duration) {
|
||||
// duration is expected > 0
|
||||
// and key is valid
|
||||
switch mt {
|
||||
case response.NoError, response.Delegation:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.pcache.Add(uint32(key), i)
|
||||
w.pcache.Add(key, i)
|
||||
|
||||
case response.NameError, response.NoData:
|
||||
i := newItem(m, w.now(), duration)
|
||||
w.ncache.Add(uint32(key), i)
|
||||
w.ncache.Add(key, i)
|
||||
|
||||
case response.OtherError:
|
||||
// don't cache these
|
||||
|
|
4
plugin/cache/cache_test.go
vendored
4
plugin/cache/cache_test.go
vendored
|
@ -167,9 +167,11 @@ func TestCache(t *testing.T) {
|
|||
state := request.Request{W: nil, Req: m}
|
||||
|
||||
mt, _ := response.Typify(m, utc)
|
||||
k := key(m, mt, state.Do())
|
||||
valid, k := key(m, mt, state.Do())
|
||||
|
||||
if valid {
|
||||
crr.set(m, k, mt, c.pttl)
|
||||
}
|
||||
|
||||
i, _ := c.get(time.Now().UTC(), state, "dns://:53")
|
||||
ok := i != nil
|
||||
|
|
|
@ -7,8 +7,8 @@ import (
|
|||
)
|
||||
|
||||
// hash serializes the RRset and return a signature cache key.
|
||||
func hash(rrs []dns.RR) uint32 {
|
||||
h := fnv.New32()
|
||||
func hash(rrs []dns.RR) uint64 {
|
||||
h := fnv.New64()
|
||||
buf := make([]byte, 256)
|
||||
for _, r := range rrs {
|
||||
off, err := dns.PackRR(r, buf, 0, nil, false)
|
||||
|
@ -17,6 +17,6 @@ func hash(rrs []dns.RR) uint32 {
|
|||
}
|
||||
}
|
||||
|
||||
i := h.Sum32()
|
||||
i := h.Sum64()
|
||||
return i
|
||||
}
|
||||
|
|
|
@ -110,9 +110,9 @@ func (d Dnssec) sign(rrs []dns.RR, signerName string, ttl, incep, expir uint32,
|
|||
return sigs.([]dns.RR), err
|
||||
}
|
||||
|
||||
func (d Dnssec) set(key uint32, sigs []dns.RR) { d.cache.Add(key, sigs) }
|
||||
func (d Dnssec) set(key uint64, sigs []dns.RR) { d.cache.Add(key, sigs) }
|
||||
|
||||
func (d Dnssec) get(key uint32, server string) ([]dns.RR, bool) {
|
||||
func (d Dnssec) get(key uint64, server string) ([]dns.RR, bool) {
|
||||
if s, ok := d.cache.Get(key); ok {
|
||||
// we sign for 8 days, check if a signature in the cache reached 3/4 of that
|
||||
is75 := time.Now().UTC().Add(sixDays)
|
||||
|
|
32
plugin/pkg/cache/cache.go
vendored
32
plugin/pkg/cache/cache.go
vendored
|
@ -9,10 +9,10 @@ import (
|
|||
)
|
||||
|
||||
// Hash returns the FNV hash of what.
|
||||
func Hash(what []byte) uint32 {
|
||||
h := fnv.New32()
|
||||
func Hash(what []byte) uint64 {
|
||||
h := fnv.New64()
|
||||
h.Write(what)
|
||||
return h.Sum32()
|
||||
return h.Sum64()
|
||||
}
|
||||
|
||||
// Cache is cache.
|
||||
|
@ -22,7 +22,7 @@ type Cache struct {
|
|||
|
||||
// shard is a cache with random eviction.
|
||||
type shard struct {
|
||||
items map[uint32]interface{}
|
||||
items map[uint64]interface{}
|
||||
size int
|
||||
|
||||
sync.RWMutex
|
||||
|
@ -45,19 +45,19 @@ func New(size int) *Cache {
|
|||
}
|
||||
|
||||
// Add adds a new element to the cache. If the element already exists it is overwritten.
|
||||
func (c *Cache) Add(key uint32, el interface{}) {
|
||||
func (c *Cache) Add(key uint64, el interface{}) {
|
||||
shard := key & (shardSize - 1)
|
||||
c.shards[shard].Add(key, el)
|
||||
}
|
||||
|
||||
// Get looks up element index under key.
|
||||
func (c *Cache) Get(key uint32) (interface{}, bool) {
|
||||
func (c *Cache) Get(key uint64) (interface{}, bool) {
|
||||
shard := key & (shardSize - 1)
|
||||
return c.shards[shard].Get(key)
|
||||
}
|
||||
|
||||
// Remove removes the element indexed with key.
|
||||
func (c *Cache) Remove(key uint32) {
|
||||
func (c *Cache) Remove(key uint64) {
|
||||
shard := key & (shardSize - 1)
|
||||
c.shards[shard].Remove(key)
|
||||
}
|
||||
|
@ -72,10 +72,10 @@ func (c *Cache) Len() int {
|
|||
}
|
||||
|
||||
// newShard returns a new shard with size.
|
||||
func newShard(size int) *shard { return &shard{items: make(map[uint32]interface{}), size: size} }
|
||||
func newShard(size int) *shard { return &shard{items: make(map[uint64]interface{}), size: size} }
|
||||
|
||||
// Add adds element indexed by key into the cache. Any existing element is overwritten
|
||||
func (s *shard) Add(key uint32, el interface{}) {
|
||||
func (s *shard) Add(key uint64, el interface{}) {
|
||||
l := s.Len()
|
||||
if l+1 > s.size {
|
||||
s.Evict()
|
||||
|
@ -87,7 +87,7 @@ func (s *shard) Add(key uint32, el interface{}) {
|
|||
}
|
||||
|
||||
// Remove removes the element indexed by key from the cache.
|
||||
func (s *shard) Remove(key uint32) {
|
||||
func (s *shard) Remove(key uint64) {
|
||||
s.Lock()
|
||||
delete(s.items, key)
|
||||
s.Unlock()
|
||||
|
@ -95,26 +95,28 @@ func (s *shard) Remove(key uint32) {
|
|||
|
||||
// Evict removes a random element from the cache.
|
||||
func (s *shard) Evict() {
|
||||
key := -1
|
||||
hasKey := false
|
||||
var key uint64
|
||||
|
||||
s.RLock()
|
||||
for k := range s.items {
|
||||
key = int(k)
|
||||
key = k
|
||||
hasKey = true
|
||||
break
|
||||
}
|
||||
s.RUnlock()
|
||||
|
||||
if key == -1 {
|
||||
if !hasKey {
|
||||
// empty cache
|
||||
return
|
||||
}
|
||||
|
||||
// If this item is gone between the RUnlock and Lock race we don't care.
|
||||
s.Remove(uint32(key))
|
||||
s.Remove(key)
|
||||
}
|
||||
|
||||
// Get looks up the element indexed under key.
|
||||
func (s *shard) Get(key uint32) (interface{}, bool) {
|
||||
func (s *shard) Get(key uint64) (interface{}, bool) {
|
||||
s.RLock()
|
||||
el, found := s.items[key]
|
||||
s.RUnlock()
|
||||
|
|
|
@ -31,17 +31,17 @@ type call struct {
|
|||
// units of work can be executed with duplicate suppression.
|
||||
type Group struct {
|
||||
mu sync.Mutex // protects m
|
||||
m map[uint32]*call // lazily initialized
|
||||
m map[uint64]*call // lazily initialized
|
||||
}
|
||||
|
||||
// Do executes and returns the results of the given function, making
|
||||
// sure that only one execution is in-flight for a given key at a
|
||||
// time. If a duplicate comes in, the duplicate caller waits for the
|
||||
// original to complete and receives the same results.
|
||||
func (g *Group) Do(key uint32, fn func() (interface{}, error)) (interface{}, error) {
|
||||
func (g *Group) Do(key uint64, fn func() (interface{}, error)) (interface{}, error) {
|
||||
g.mu.Lock()
|
||||
if g.m == nil {
|
||||
g.m = make(map[uint32]*call)
|
||||
g.m = make(map[uint64]*call)
|
||||
}
|
||||
if c, ok := g.m[key]; ok {
|
||||
g.mu.Unlock()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue