Documentation
¶
Overview ¶
Package cache provides DNS caching functionality for SDNS.
Index ¶
- Variables
- func Key(q dns.Question, cd ...bool) uint64
- func KeySimple(q dns.Question, cd ...bool) uint64
- func KeyString(qname string, qtype, qclass uint16, cd bool) uint64
- func KeyWithPrefix(q dns.Question, cd bool, prefix netip.Prefix) uint64
- type Cache
- func (c *Cache) Add(key uint64, value any)
- func (c *Cache) CompareAndDelete(key uint64, old any) bool
- func (c *Cache) CompareAndSwap(key uint64, old, value any) bool
- func (c *Cache) ForEach(f func(key uint64, value any) bool)
- func (c *Cache) Get(key uint64) (any, bool)
- func (c *Cache) Len() int
- func (c *Cache) Remove(key uint64)
- func (c *Cache) Stop()
- type Pair
- type SegmentUInt64Map
- func (m *SegmentUInt64Map[V]) All() iter.Seq2[uint64, V]
- func (m *SegmentUInt64Map[V]) Clear()
- func (m *SegmentUInt64Map[V]) ClearSegment(index int)
- func (m *SegmentUInt64Map[V]) Del(key uint64) bool
- func (m *SegmentUInt64Map[V]) ForEach(f func(uint64, V) bool)
- func (m *SegmentUInt64Map[V]) Get(key uint64) (V, bool)
- func (m *SegmentUInt64Map[V]) Has(key uint64) bool
- func (m *SegmentUInt64Map[V]) Keys() iter.Seq[uint64]
- func (m *SegmentUInt64Map[V]) Len() int64
- func (m *SegmentUInt64Map[V]) PutIfNotExists(key uint64, value V) (V, bool)
- func (m *SegmentUInt64Map[V]) SegmentCount() int
- func (m *SegmentUInt64Map[V]) Set(key uint64, value V)
- func (m *SegmentUInt64Map[V]) SetWithCap(key uint64, value V, capacity int64)
- func (m *SegmentUInt64Map[V]) Stop()
- func (m *SegmentUInt64Map[V]) Values() iter.Seq[V]
- type SyncUInt64Map
- func (m *SyncUInt64Map[V]) All() iter.Seq2[uint64, V]
- func (m *SyncUInt64Map[V]) Clear()
- func (m *SyncUInt64Map[V]) Compact() int
- func (m *SyncUInt64Map[V]) Del(key uint64) bool
- func (m *SyncUInt64Map[V]) ForEach(f func(uint64, V) bool)
- func (m *SyncUInt64Map[V]) Get(key uint64) (V, bool)
- func (m *SyncUInt64Map[V]) Has(key uint64) bool
- func (m *SyncUInt64Map[V]) Len() int64
- func (m *SyncUInt64Map[V]) Set(key uint64, value V)
- func (m *SyncUInt64Map[V]) SetWithCap(key uint64, value V, capacity int64)
- func (m *SyncUInt64Map[V]) Stop()
- type UInt64Map
- func (m *UInt64Map[V]) All() iter.Seq2[uint64, V]
- func (m *UInt64Map[V]) Clear()
- func (m *UInt64Map[V]) Del(key uint64) bool
- func (m *UInt64Map[V]) EvictKeysAt(offset, n int, skip uint64) int
- func (m *UInt64Map[V]) ForEach(f func(uint64, V) bool)
- func (m *UInt64Map[V]) Get(key uint64) (V, bool)
- func (m *UInt64Map[V]) Has(key uint64) bool
- func (m *UInt64Map[V]) Keys() iter.Seq[uint64]
- func (m *UInt64Map[V]) Len() int
- func (m *UInt64Map[V]) Put(key uint64, val V)
- func (m *UInt64Map[V]) PutIfNotExists(key uint64, val V) (V, bool)
- func (m *UInt64Map[V]) Values() iter.Seq[V]
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCacheNotFound error. ErrCacheNotFound = errors.New("cache not found") // ErrCacheExpired error. ErrCacheExpired = errors.New("cache expired") )
Functions ¶
func Key ¶
Key generates a cache key for DNS queries. This implementation uses object pooling and stack allocation to achieve zero heap allocations. The optional cd parameter indicates if the CD (Checking Disabled) bit should be included.
func KeySimple ¶
KeySimple generates a cache key without pooling for comparison. This is exported for benchmarking purposes only.
func KeyString ¶
KeyString is an optimized version for string-based keys. It uses unsafe conversion to avoid allocation when converting string to []byte.
func KeyWithPrefix ¶ added in v1.7.0
KeyWithPrefix is an ECS-aware variant of Key. An invalid prefix (the canonical "no scope" value) collapses to Key(q, cd) so cache entries written before this function existed still resolve on lookup — no flush needed on upgrade.
When prefix is valid, family + bit-length + the address bytes rounded up to a byte are folded into the hash preimage. The distinct family byte means an IPv4 /24 of [a, b, c] cannot collide with an IPv6 /24 whose first three bytes happen to be [a, b, c]. The distinct bit-length byte means /22 and /24 of 203.0.112.0 hash differently even though their byte-rounded addresses are both [203, 0, 112] — the earlier scope-bytes-only encoding aliased here and would serve a wider supernet's answer to a narrower-subnet query.
Types ¶
type Cache ¶
type Cache struct {
// contains filtered or unexported fields
}
Cache is a bounded concurrent map with proportional random eviction: an over-capacity insert evicts up to two entries from the segment it already holds the write lock for. No bulk clearing, no dedicated evictor, no lock a writer could ever queue behind (2026-07-28 incident: 1.43M goroutines, 93% blocked behind cache segment locks while segment-clearing eviction dumped 10-60% of the glue cache mid-outage).
func (*Cache) Add ¶
Add adds an item; an over-capacity insert self-evicts up to two entries from its own segment, so occupancy is bounded at any write rate while per-Add work stays a small constant.
func (*Cache) CompareAndDelete ¶ added in v1.7.3
CompareAndDelete removes key only if its current value is identical to old. Expiry cleanup uses this instead of an unconditional Remove: a fresh value may be published after the reader loaded the expired entry, and that newer value must not be deleted by the stale reader.
func (*Cache) CompareAndSwap ¶ added in v1.7.3
CompareAndSwap stores value under key only if the value currently stored is identical (==, i.e. pointer identity for pointer-typed values) to old. Returns false — storing nothing — when the key is absent or holds a different value. The check-and-set runs under the key's segment write lock, so a concurrent Add/Remove cannot interleave between the compare and the swap.
This is the late-write guard for asynchronous refreshes (GHSA-mqfw-f48p-2vc8): a stale in-flight result may only replace the exact entry it set out to refresh, never state that landed after it started.
func (*Cache) ForEach ¶
ForEach iterates over all cache entries. Iteration is not atomic with concurrent updates.
type SegmentUInt64Map ¶
type SegmentUInt64Map[V any] struct { // contains filtered or unexported fields }
SegmentUInt64Map is a fast, thread-safe map for int64 keys that uses sharding (segmentation) to reduce lock contention while maintaining the performance benefits of UInt64Map
func NewSegmentUInt64Map ¶
func NewSegmentUInt64Map[V any](segmentPower uint8, initialCapacity int) *SegmentUInt64Map[V]
NewSegmentUInt64Map creates a new segmented map for int64 keys segmentPower controls the number of segments (2^segmentPower) initialCapacity is the initial capacity per segment
func (*SegmentUInt64Map[V]) All ¶
func (m *SegmentUInt64Map[V]) All() iter.Seq2[uint64, V]
All returns an iterator over all key-value pairs
func (*SegmentUInt64Map[V]) Clear ¶
func (m *SegmentUInt64Map[V]) Clear()
Clear removes all entries from the map
func (*SegmentUInt64Map[V]) ClearSegment ¶
func (m *SegmentUInt64Map[V]) ClearSegment(index int)
ClearSegment clears a specific segment - for radical eviction
func (*SegmentUInt64Map[V]) Del ¶
func (m *SegmentUInt64Map[V]) Del(key uint64) bool
Del removes a key from the map
func (*SegmentUInt64Map[V]) ForEach ¶
func (m *SegmentUInt64Map[V]) ForEach(f func(uint64, V) bool)
ForEach iterates through all key-value pairs Note: The iteration is not atomic and may miss concurrent updates
func (*SegmentUInt64Map[V]) Get ¶
func (m *SegmentUInt64Map[V]) Get(key uint64) (V, bool)
Get retrieves a value by key
func (*SegmentUInt64Map[V]) Has ¶
func (m *SegmentUInt64Map[V]) Has(key uint64) bool
Has checks if a key exists in the map
func (*SegmentUInt64Map[V]) Keys ¶
func (m *SegmentUInt64Map[V]) Keys() iter.Seq[uint64]
Keys returns an iterator over all keys
func (*SegmentUInt64Map[V]) Len ¶
func (m *SegmentUInt64Map[V]) Len() int64
Len returns the number of elements in the map
func (*SegmentUInt64Map[V]) PutIfNotExists ¶
func (m *SegmentUInt64Map[V]) PutIfNotExists(key uint64, value V) (V, bool)
PutIfNotExists adds the key-value pair only if the key doesn't already exist Returns the value and true if inserted, or existing value and false if not inserted
func (*SegmentUInt64Map[V]) SegmentCount ¶
func (m *SegmentUInt64Map[V]) SegmentCount() int
SegmentCount returns the number of segments
func (*SegmentUInt64Map[V]) Set ¶
func (m *SegmentUInt64Map[V]) Set(key uint64, value V)
Set adds or updates a key-value pair
func (*SegmentUInt64Map[V]) SetWithCap ¶ added in v1.7.4
func (m *SegmentUInt64Map[V]) SetWithCap(key uint64, value V, capacity int64)
SetWithCap adds or updates a key-value pair and, when total occupancy exceeds capacity, evicts up to two other entries from the same segment — under the same write lock the insert already holds. This is the whole eviction design: no extra lock, no evictor handoff, no bulk pass for other writers to sleep behind. Every over-capacity insert pays a small constant toll (net occupancy change ≥ -1), so the map is self-bounding at any write rate. The scan offset is derived from the key's hash with a different mixer than slot placement, so the loss stays uniform.
func (*SegmentUInt64Map[V]) Stop ¶
func (m *SegmentUInt64Map[V]) Stop()
Stop is a no-op for compatibility
func (*SegmentUInt64Map[V]) Values ¶
func (m *SegmentUInt64Map[V]) Values() iter.Seq[V]
Values returns an iterator over all values
type SyncUInt64Map ¶
type SyncUInt64Map[V any] struct { // contains filtered or unexported fields }
SyncUInt64Map wraps SegmentUInt64Map to provide the expected interface
func NewSyncUInt64Map ¶
func NewSyncUInt64Map[V any](sizePower uint) *SyncUInt64Map[V]
NewSyncUInt64Map creates a new map
func (*SyncUInt64Map[V]) All ¶
func (m *SyncUInt64Map[V]) All() iter.Seq2[uint64, V]
All returns an iterator
func (*SyncUInt64Map[V]) Clear ¶
func (m *SyncUInt64Map[V]) Clear()
Clear removes all entries - FAST!
func (*SyncUInt64Map[V]) Compact ¶
func (m *SyncUInt64Map[V]) Compact() int
Compact is a no-op for this implementation as it handles memory efficiently
func (*SyncUInt64Map[V]) Del ¶
func (m *SyncUInt64Map[V]) Del(key uint64) bool
Del removes a key from the map
func (*SyncUInt64Map[V]) ForEach ¶
func (m *SyncUInt64Map[V]) ForEach(f func(uint64, V) bool)
ForEach iterates over all entries
func (*SyncUInt64Map[V]) Get ¶
func (m *SyncUInt64Map[V]) Get(key uint64) (V, bool)
Get retrieves a value by key
func (*SyncUInt64Map[V]) Has ¶
func (m *SyncUInt64Map[V]) Has(key uint64) bool
Has checks if a key exists
func (*SyncUInt64Map[V]) Len ¶
func (m *SyncUInt64Map[V]) Len() int64
Len returns the number of entries
func (*SyncUInt64Map[V]) Set ¶
func (m *SyncUInt64Map[V]) Set(key uint64, value V)
Set adds or updates a key-value pair
func (*SyncUInt64Map[V]) SetWithCap ¶ added in v1.7.4
func (m *SyncUInt64Map[V]) SetWithCap(key uint64, value V, capacity int64)
SetWithCap adds or updates a key-value pair, self-evicting from the same segment under the same lock when total occupancy exceeds capacity.
type UInt64Map ¶
type UInt64Map[V any] struct { // contains filtered or unexported fields }
UInt64Map is a specialized map for uint64 keys. It is specifically optimized for clustered keys, where keys are likely to be close to each other (e.g., sequential IDs, timestamp ranges).
func NewUInt64Map ¶
NewUInt64Map creates a new UInt64Map with given capacity
func (*UInt64Map[V]) EvictKeysAt ¶ added in v1.7.4
EvictKeysAt deletes up to n entries (skipping key skip) in one scan starting at offset, wrapping around, and returns the number deleted. This is eviction's primitive: deleting at the scan cursor skips the second hash-and-probe a collect-then-Del pass would pay per key. The caller derives offset from the key hash, so repeated eviction spreads across the array instead of hollowing out its front — a front-biased scan degrades to O(buckets) per key once the leading slots empty out.
func (*UInt64Map[V]) PutIfNotExists ¶
PutIfNotExists adds key-value pair only if key doesn't exist