github.com/letsencrypt/boulder@v0.20251208.0/email/cache.go (about) 1 package email 2 3 import ( 4 "crypto/sha256" 5 "encoding/hex" 6 "sync" 7 8 "github.com/golang/groupcache/lru" 9 "github.com/prometheus/client_golang/prometheus" 10 "github.com/prometheus/client_golang/prometheus/promauto" 11 ) 12 13 type EmailCache struct { 14 sync.Mutex 15 cache *lru.Cache 16 requests *prometheus.CounterVec 17 } 18 19 func NewHashedEmailCache(maxEntries int, stats prometheus.Registerer) *EmailCache { 20 requests := promauto.With(stats).NewCounterVec(prometheus.CounterOpts{ 21 Name: "email_cache_requests", 22 }, []string{"status"}) 23 24 return &EmailCache{ 25 cache: lru.New(maxEntries), 26 requests: requests, 27 } 28 } 29 30 func hashEmail(email string) string { 31 sum := sha256.Sum256([]byte(email)) 32 return hex.EncodeToString(sum[:]) 33 } 34 35 func (c *EmailCache) Seen(email string) bool { 36 if c == nil { 37 // If the cache is nil we assume it was not configured. 38 return false 39 } 40 41 hash := hashEmail(email) 42 43 c.Lock() 44 defer c.Unlock() 45 46 _, ok := c.cache.Get(hash) 47 if !ok { 48 c.requests.WithLabelValues("miss").Inc() 49 return false 50 } 51 52 c.requests.WithLabelValues("hit").Inc() 53 return true 54 } 55 56 func (c *EmailCache) Remove(email string) { 57 if c == nil { 58 // If the cache is nil we assume it was not configured. 59 return 60 } 61 62 hash := hashEmail(email) 63 64 c.Lock() 65 defer c.Unlock() 66 67 c.cache.Remove(hash) 68 } 69 70 // StoreIfAbsent stores the email in the cache if it is not already present, as 71 // a single atomic operation. It returns true if the email was stored and false 72 // if it was already in the cache. If the cache is nil, true is always returned. 73 func (c *EmailCache) StoreIfAbsent(email string) bool { 74 if c == nil { 75 // If the cache is nil we assume it was not configured. 76 return true 77 } 78 79 hash := hashEmail(email) 80 81 c.Lock() 82 defer c.Unlock() 83 84 _, ok := c.cache.Get(hash) 85 if ok { 86 c.requests.WithLabelValues("hit").Inc() 87 return false 88 } 89 c.cache.Add(hash, nil) 90 c.requests.WithLabelValues("miss").Inc() 91 return true 92 }