WIP: quick&dirty list cache redis implementation

This commit is contained in:
Dimitri Herzog 2023-02-27 22:52:34 +01:00
parent d64b399fdc
commit a695d38c99
3 changed files with 70 additions and 7 deletions

View File

@ -1,11 +1,15 @@
package stringcache
import (
"context"
"regexp"
"sort"
"strings"
"time"
"github.com/0xERR0R/blocky/log"
"github.com/go-redis/redis/v8"
"github.com/hako/durafmt"
)
type StringCache interface {
@ -18,6 +22,23 @@ type CacheFactory interface {
Create() StringCache
}
type redisStringCache struct {
rdb *redis.Client
key string
}
func (cache *redisStringCache) ElementCount() int {
return int(cache.rdb.SCard(context.Background(), cache.key).Val())
}
func (cache *redisStringCache) Contains(searchString string) bool {
now := time.Now()
found := cache.rdb.SIsMember(context.Background(), cache.key, searchString).Val()
log.Log().Infof("redis lookup in set '%s', domain '%s': result: %t, duration %s", cache.key, searchString, found, durafmt.Parse(time.Since(now)).String())
return found
}
type stringCache map[int]string
func normalizeEntry(entry string) string {
@ -54,6 +75,39 @@ func (cache stringCache) Contains(searchString string) bool {
return false
}
type redisStringCacheFactory struct {
pipeline redis.Pipeliner
name string
rdb *redis.Client
}
func newRedisStringCacheFactory(rdb *redis.Client, name string) CacheFactory {
pipeline := rdb.Pipeline()
pipeline.Del(context.Background(), name)
return &redisStringCacheFactory{
rdb: rdb,
pipeline: pipeline,
name: name,
}
}
func (s *redisStringCacheFactory) AddEntry(entry string) {
err := s.pipeline.SAdd(context.Background(), s.name, entry).Err()
if err != nil {
panic(err)
}
}
func (s *redisStringCacheFactory) Create() StringCache {
// TODO batch
s.pipeline.Exec(context.Background())
return &redisStringCache{
rdb: s.rdb,
key: s.name,
}
}
type stringCacheFactory struct {
// temporary map which holds sorted slice of strings grouped by string length
tmp map[int][]string
@ -194,9 +248,13 @@ func (r *chainedCacheFactory) Create() StringCache {
}
}
func NewChainedCacheFactory() CacheFactory {
func NewChainedCacheFactory(name string) CacheFactory {
return &chainedCacheFactory{
stringCacheFactory: newStringCacheFactory(),
regexCacheFactory: newRegexCacheFactory(),
stringCacheFactory: newRedisStringCacheFactory(redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
}), name),
regexCacheFactory: newRegexCacheFactory(),
}
}

View File

@ -66,7 +66,7 @@ var _ = Describe("Caches", func() {
Describe("Chained StringCache", func() {
When("chained StringCache was created", func() {
factory := NewChainedCacheFactory()
factory := NewChainedCacheFactory("test")
factory.AddEntry("/.*google.com/")
factory.AddEntry("/^apple\\.(de|com)$/")
factory.AddEntry("amazon.com")

View File

@ -146,11 +146,16 @@ func logger() *logrus.Entry {
return log.PrefixedLog("list_cache")
}
func (b *ListCache) cacheKey(groupName string) string {
return fmt.Sprintf("cache_%s_%s", b.listType.String(), groupName)
}
// downloads and reads files with domain names and creates cache for them
func (b *ListCache) createCacheForGroup(links []string) (stringcache.StringCache, error) {
func (b *ListCache) createCacheForGroup(links []string, groupName string) (stringcache.StringCache, error) {
var err error
factory := stringcache.NewChainedCacheFactory()
factory := stringcache.NewChainedCacheFactory(b.cacheKey(groupName))
fileLinesChan := make(chan string, chanCap)
errChan := make(chan error, chanCap)
@ -226,7 +231,7 @@ func (b *ListCache) refresh(init bool) error {
var err error
for group, links := range b.groupToLinks {
cacheForGroup, e := b.createCacheForGroup(links)
cacheForGroup, e := b.createCacheForGroup(links, group)
if e != nil {
err = multierror.Append(err, multierror.Prefix(e, fmt.Sprintf("can't create cache group '%s':", group)))
}