Skip to content

Commit

Permalink
Merge pull request #100 from tminaorg/cache
Browse files Browse the repository at this point in the history
Cache
  • Loading branch information
aleksasiriski authored Oct 5, 2023
2 parents b2808f7 + d591d04 commit 675ab1a
Show file tree
Hide file tree
Showing 14 changed files with 345 additions and 47 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ src/engines/*/site/*

logdump/*.html
log/*.log
database/

# go generate
*_stringer.go
Expand Down
35 changes: 30 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,49 +4,74 @@ go 1.20

require (
github.com/alecthomas/kong v0.8.0
github.com/cockroachdb/pebble v0.0.0-20231004191855-d4bf20c546d3
github.com/fxamacker/cbor/v2 v2.5.0
github.com/gin-contrib/cors v1.4.0
github.com/gin-gonic/gin v1.9.1
github.com/gocolly/colly/v2 v2.0.0-00010101000000-000000000000
github.com/gocolly/colly/v2 v2.1.0
github.com/knadh/koanf/parsers/yaml v0.1.0
github.com/knadh/koanf/providers/env v0.1.0
github.com/knadh/koanf/providers/file v0.1.0
github.com/knadh/koanf/providers/structs v0.1.0
github.com/knadh/koanf/v2 v2.0.1
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/redis/go-redis/v9 v9.2.1
github.com/robertkrimen/otto v0.2.1
github.com/rs/zerolog v1.31.0
golang.org/x/tools v0.13.0
)

require (
github.com/bits-and-blooms/bitset v1.2.2-0.20220111210104-dfa3e347c392 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.9.0 // indirect
github.com/bytedance/sonic v1.10.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/getsentry/sentry-go v0.25.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.15.4 // indirect
github.com/go-playground/validator/v10 v10.15.5 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/google/go-cmp v0.5.8 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nlnwa/whatwg-url v0.1.2 // indirect
github.com/nlnwa/whatwg-url v0.4.0 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.17.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/arch v0.5.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
gopkg.in/sourcemap.v1 v1.0.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
92 changes: 84 additions & 8 deletions go.sum

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/cache/funcs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cache

import (
"time"

"github.com/rs/zerolog/log"
"github.com/tminaorg/brzaguza/src/bucket/result"
)

func Save(db DB, query string, results []result.Result) {
log.Debug().Msg("Caching...")
cacheTimer := time.Now()
db.Set(query, results)
log.Debug().Msgf("Cached results in %vns", time.Since(cacheTimer).Nanoseconds())
}
9 changes: 9 additions & 0 deletions src/cache/interfaces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package cache

type DB interface {
Close()
Set(k string, v Value)
Get(k string, o Value)
}

type Value interface{}
54 changes: 54 additions & 0 deletions src/cache/pebble/pebble.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package pebble

import (
"fmt"

"github.com/cockroachdb/pebble"
"github.com/fxamacker/cbor/v2"
"github.com/rs/zerolog/log"
"github.com/tminaorg/brzaguza/src/cache"
)

type DB struct {
pdb *pebble.DB
}

func New(path string) *DB {
pdb, err := pebble.Open(fmt.Sprintf("%v/database", path), &pebble.Options{})
if err != nil {
log.Panic().Msgf("Error opening pebble: %v (path: %v)", err, path)
} else {
log.Info().Msgf("Successfully opened pebble (path: %v)", path)
}
return &DB{pdb: pdb}
}

func (db *DB) Close() {
if err := db.pdb.Close(); err != nil {
log.Panic().Msgf("Error closing pebble: %v", err)
} else {
log.Debug().Msg("Successfully closed pebble")
}
}

func (db *DB) Set(k string, v cache.Value) {
if val, err := cbor.Marshal(v); err != nil {
log.Error().Msgf("Error marshaling value: %v", err)
} else if err := db.pdb.Set([]byte(k), val, pebble.Sync); err != nil { // should be set to NoSync when router gets graceful shutdown
log.Panic().Msgf("Error setting KV to pebble: %v", err)
}
}

func (db *DB) Get(k string, o cache.Value) {
v, c, err := db.pdb.Get([]byte(k))
val := []byte(v) // copy data before closing, casting needed for unmarshal
if err == pebble.ErrNotFound {
log.Trace().Msgf("Found no value in pebble for key (%v): %v", k, err)
} else if err != nil {
log.Panic().Msgf("Error getting value from pebble for key (%v): %v", k, err)
} else if err := c.Close(); err != nil {
log.Panic().Msgf("Error closing io to pebble for key (%v): %v", k, err)
} else if err := cbor.Unmarshal(val, o); err != nil {
log.Error().Msgf("Failed unmarshaling value from pebble for key (%v): %v", k, err)
}
}
53 changes: 53 additions & 0 deletions src/cache/redis/redis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package redis

import (
"context"
"fmt"

"github.com/fxamacker/cbor/v2"
"github.com/redis/go-redis/v9"
"github.com/rs/zerolog/log"
"github.com/tminaorg/brzaguza/src/cache"
"github.com/tminaorg/brzaguza/src/config"
)

var ctx = context.Background()

type DB struct {
rdb *redis.Client
}

func New(config config.Redis) *DB {
rdb := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%v:%v", config.Host, config.Port),
Password: config.Password,
DB: int(config.Database),
})
log.Info().Msgf("Successful connection to redis (addr: %v:%v/%v)", config.Host, config.Port, config.Database)
return &DB{rdb: rdb}
}

// needed to comply with interface
func (db *DB) Close() {
log.Debug().Msg("Successfully disconnected from redis")
}

func (db *DB) Set(k string, v cache.Value) {
if val, err := cbor.Marshal(v); err != nil {
log.Error().Msgf("Error marshaling value: %v", err)
} else if err := db.rdb.Set(ctx, k, val, 0).Err(); err != nil {
log.Panic().Msgf("Error setting KV to redis: %v", err)
}
}

func (db *DB) Get(k string, o cache.Value) {
v, err := db.rdb.Get(ctx, k).Result()
val := []byte(v) // copy data before closing, casting needed for unmarshal
if err == redis.Nil {
log.Trace().Msgf("Found no value in redis for key (%v): %v", k, err)
} else if err != nil {
log.Panic().Msgf("Error getting value from redis for key (%v): %v", k, err)
} else if err := cbor.Unmarshal(val, o); err != nil {
log.Error().Msgf("Failed unmarshaling value from redis for key (%v): %v", k, err)
}
}
8 changes: 7 additions & 1 deletion src/config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,13 @@ func New() *Config {
Server: Server{
Port: 3030,
FrontendUrls: []string{"http://localhost:8000"},
RedisUrl: "http://localhost:6379",
Cache: Cache{
Type: "pebble",
Redis: Redis{
Host: "localhost",
Port: 6379,
},
},
},
Engines: map[string]Engine{
engines.Bing.ToLower(): {
Expand Down
50 changes: 30 additions & 20 deletions src/config/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ package config

import "time"

type EngineRanking struct {
Mul float64 `koanf:"mul"`
Const float64 `koanf:"const"`
}

type Ranking struct {
REXP float64 `koanf:"rexp"`
A float64 `koanf:"a"`
B float64 `koanf:"b"`
C float64 `koanf:"c"`
D float64 `koanf:"d"`
TRA float64 `koanf:"tra"`
TRB float64 `koanf:"trb"`
TRC float64 `koanf:"trc"`
TRD float64 `koanf:"trd"`
Engines map[string]EngineRanking `koanf:"engines"`
}

// Delegates Timeout, PageTimeout to colly.Collector.SetRequestTimeout(); Note: See https://github.com/gocolly/colly/issues/644
// Delegates Delay, RandomDelay, Parallelism to colly.Collector.Limit()
type Timings struct {
Expand All @@ -23,32 +41,24 @@ type Engine struct {
Settings Settings `koanf:"settings"`
}

// Server config
type Server struct {
Port int `koanf:"port"`
FrontendUrls []string `koanf:"frontendUrls"`
RedisUrl string `koanf:"redisUrl"`
type Redis struct {
Host string `koanf:"host"`
Port uint16 `koanf:"port"`
Password string `koanf:"password"`
Database uint8 `koanf:"database"`
}

type EngineRanking struct {
Mul float64 `koanf:"mul"`
Const float64 `koanf:"const"`
type Cache struct {
Type string `koanf:"type"`
Redis Redis `koanf:"redis"`
}

type Ranking struct {
REXP float64 `koanf:"rexp"`
A float64 `koanf:"a"`
B float64 `koanf:"b"`
C float64 `koanf:"c"`
D float64 `koanf:"d"`
TRA float64 `koanf:"tra"`
TRB float64 `koanf:"trb"`
TRC float64 `koanf:"trc"`
TRD float64 `koanf:"trd"`
Engines map[string]EngineRanking `koanf:"engines"`
type Server struct {
Port int `koanf:"port"`
FrontendUrls []string `koanf:"frontendUrls"`
Cache Cache `koanf:"cache"`
}

// Config struct for Koanf
type Config struct {
Server Server `koanf:"server"`
Engines map[string]Engine `koanf:"engines"`
Expand Down
2 changes: 1 addition & 1 deletion src/engines/qwant/json_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ type QwantResponse struct {
} `json:"items"`
} `json:"result"`
} `json:"data"`
}
}
40 changes: 38 additions & 2 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import (

"github.com/rs/zerolog/log"
"github.com/tminaorg/brzaguza/src/bucket/result"
"github.com/tminaorg/brzaguza/src/cache"
"github.com/tminaorg/brzaguza/src/cache/pebble"
"github.com/tminaorg/brzaguza/src/cache/redis"
"github.com/tminaorg/brzaguza/src/config"
"github.com/tminaorg/brzaguza/src/engines"
"github.com/tminaorg/brzaguza/src/logger"
Expand All @@ -28,6 +31,8 @@ func printResults(results []result.Result) {
}

func main() {
mainTimer := time.Now()

// parse cli arguments
setupCli()

Expand All @@ -38,6 +43,18 @@ func main() {
config := config.New()
config.Load(cli.Config, cli.Log)

// cache database
var db cache.DB
switch config.Server.Cache.Type {
case "pebble":
db = pebble.New(cli.Config)
case "redis":
db = redis.New(config.Server.Cache.Redis)
default:
log.Warn().Msg("Running without caching!")
}

// startup
if cli.Cli {
log.Info().
Str("query", cli.Query).
Expand All @@ -51,13 +68,32 @@ func main() {
}

start := time.Now()
results := search.PerformSearch(cli.Query, options, config)

var results []result.Result
if db != nil {
db.Get(cli.Query, &results)
}
if results != nil {
log.Debug().Msgf("Found results for query (%v) in cache", cli.Query)
} else {
log.Debug().Msg("Nothing found in cache, doing a clean search")
results = search.PerformSearch(cli.Query, options, config)
cache.Save(db, cli.Query, results)
}

duration := time.Since(start)

if !cli.Silent {
printResults(results)
}
log.Info().Msgf("Found %v results in %vms", len(results), duration.Milliseconds())
} else {
router.Setup(config)
router.Setup(config, db)
}

if db != nil {
db.Close()
}

log.Debug().Msgf("Program finished in %vms", time.Since(mainTimer).Milliseconds())
}
Loading

0 comments on commit 675ab1a

Please sign in to comment.