// BlockCache provides a means of caching domain blocks in memory to reduce load
// on an underlying storage mechanism, e.g. a database.
//
// It consists of a TTL primary cache that stores calculated domain string to block results,
// that on cache miss is filled by calculating block status by iterating over a list of all of
// the domain blocks stored in memory. This reduces CPU usage required by not need needing to
// iterate through a possible 100-1000s long block list, while saving memory by having a primary
// cache of limited size that evicts stale entries. The raw list of all domain blocks should in
// most cases be negligible when it comes to memory usage.
//
// The in-memory block list is kept up-to-date by means of a passed loader function during every
// call to .IsBlocked(). In the case of a nil internal block list, the loader function is called to
// hydrate the cache with the latest list of domain blocks. The .Clear() function can be used to invalidate
// the cache, e.g. when a domain block is added / deleted from the database. It will drop the current
// list of domain blocks and clear all entries from the primary cache.
typeBlockCachestruct{
pcache*ttl.Cache[string,bool]// primary cache of domains -> block results
blocks[]block// raw list of all domain blocks, nil => not loaded.
}
// New returns a new initialized BlockCache instance with given primary cache capacity and TTL.
funcNew(pcapint,pttltime.Duration)*BlockCache{
c:=new(BlockCache)
c.pcache=new(ttl.Cache[string,bool])
c.pcache.Init(0,pcap,pttl)
returnc
}
// Start will start the cache background eviction routine with given sweep frequency. If already running or a freq <= 0 provided, this is a no-op. This will block until the eviction routine has started.
func(b*BlockCache)Start(pfreqtime.Duration)bool{
returnb.pcache.Start(pfreq)
}
// Stop will stop cache background eviction routine. If not running this is a no-op. This will block until the eviction routine has stopped.
func(b*BlockCache)Stop()bool{
returnb.pcache.Stop()
}
// IsBlocked checks whether domain is blocked. If the cache is not currently loaded, then the provided load function is used to hydrate it.
// NOTE: be VERY careful using any kind of locking mechanism within the load function, as this itself is ran within the cache mutex lock.