Skip to content

Commit

Permalink
feature/compress data in cache (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
MindHunter86 authored Jul 16, 2024
2 parents 2253a60 + 1fd27e4 commit 5461c22
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 31 deletions.
4 changes: 2 additions & 2 deletions cmd/alice/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ func main() {
&cli.IntFlag{
Name: "cache-shards",
Usage: "number of shards (must be a power of 2)",
Value: 1024,
Value: 512,
},
&cli.DurationFlag{
Name: "cache-life-window",
Expand All @@ -225,7 +225,7 @@ func main() {
&cli.IntFlag{
Name: "cache-max-entry-size",
Usage: "Max size of entry in bytes. Used only to calculate initial size for cache shards",
Value: 128 * 1024,
Value: 64 * 1024,
},

&cli.StringFlag{
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ require (
github.com/allegro/bigcache/v3 v3.1.0
github.com/gofiber/fiber/v2 v2.52.5
github.com/jedib0t/go-pretty/v6 v6.5.9
github.com/klauspost/compress v1.17.9
github.com/rs/zerolog v1.33.0
github.com/urfave/cli/v2 v2.27.2
github.com/valyala/bytebufferpool v1.0.0
github.com/valyala/fasthttp v1.55.0
)

require (
github.com/andybalholm/brotli v1.1.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect
golang.org/x/sys v0.21.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions internal/cache/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ type ApiCacheEntry struct {
Key string
}

func (m *Cache) ApiDump(key string) ([]byte, error) {
return m.Get(key)
func (m *Cache) ApiDump(key string, w io.Writer) error {
return m.Write(key, w)
}

func (m *Cache) ApiDumpKeys() io.Reader {
Expand Down
50 changes: 41 additions & 9 deletions internal/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package cache
import (
"context"
"errors"
"io"

"github.com/allegro/bigcache/v3"
"github.com/anilibria/alice/internal/utils"
"github.com/klauspost/compress/s2"
"github.com/rs/zerolog"
"github.com/urfave/cli/v2"
)
Expand Down Expand Up @@ -56,15 +58,7 @@ func (m *Cache) Bootstrap() {
}
}

func (m *Cache) CacheResponse(key string, payload []byte) error {
return m.Set(key, payload)
}

func (m *Cache) CachedResponse(key string) ([]byte, error) {
return m.Get(key)
}

func (m *Cache) IsResponseCached(key string) (_ bool, e error) {
func (m *Cache) IsCached(key string) (_ bool, e error) {
if _, e = m.Get(key); e != nil && errors.Is(e, bigcache.ErrEntryNotFound) {
return false, nil
} else if e != nil {
Expand All @@ -73,3 +67,41 @@ func (m *Cache) IsResponseCached(key string) (_ bool, e error) {

return true, nil
}

func (m *Cache) Cache(key string, payload []byte) error {
return m.setCompressed(key, payload)
}

func (m *Cache) Write(key string, w io.Writer) error {
return m.writeDecompressed(key, w)
}

func (m *Cache) setCompressed(key string, payload []byte) error {
cmp := s2.Encode(nil, payload)

if zerolog.GlobalLevel() <= zerolog.DebugLevel {
m.log.Trace().Msgf("compressed from %d to %d bytes", len(payload), len(cmp))
}

return m.Set(key, cmp)
}

func (m *Cache) writeDecompressed(key string, w io.Writer) (e error) {
var cmp, decmp []byte
if cmp, e = m.Get(key); e != nil {
return
}

if decmp, e = s2.Decode(nil, cmp); e != nil {
return
}

var wrote int
wrote, e = w.Write(decmp)

if zerolog.GlobalLevel() <= zerolog.DebugLevel {
m.log.Trace().Msgf("decompressed from %d to %d bytes, wrote %d bytes", len(cmp), len(decmp), wrote)
}

return
}
4 changes: 1 addition & 3 deletions internal/proxy/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,10 @@ func (m *Proxy) HandleCacheDump(c *fiber.Ctx) (e error) {
return fiber.NewError(fiber.StatusBadRequest, "key could not be empty")
}

var payload []byte
if payload, e = m.cache.ApiDump(cachekey); e != nil {
if e = m.cache.ApiDump(cachekey, c); e != nil {
return fiber.NewError(fiber.StatusInternalServerError, e.Error())
}

c.Response().SetBodyRaw(payload)
return respondPlainWithStatus(c, fiber.StatusOK)
}

Expand Down
14 changes: 8 additions & 6 deletions internal/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (m *Proxy) cacheResponse(c *fiber.Ctx, rsp *fasthttp.Response) (e error) {
m.cache.Stats().DelHits, m.cache.Stats().Hits, m.cache.Stats().Misses)
}

if e = m.cache.CacheResponse(key.UnsafeString(), rsp.Body()); e != nil {
if e = m.cache.Cache(key.UnsafeString(), rsp.Body()); e != nil {
return
}

Expand All @@ -138,7 +138,7 @@ func (m *Proxy) canRespondFromCache(c *fiber.Ctx) (_ bool, e error) {
key := c.Context().UserValue(utils.UVCacheKey).(*Key)

var ok bool
if ok, e = m.cache.IsResponseCached(key.UnsafeString()); e != nil {
if ok, e = m.cache.IsCached(key.UnsafeString()); e != nil {
rlog(c).Warn().Msg("there is problems with cache driver")
return
} else if !ok {
Expand All @@ -151,12 +151,11 @@ func (m *Proxy) canRespondFromCache(c *fiber.Ctx) (_ bool, e error) {
func (m *Proxy) respondFromCache(c *fiber.Ctx) (e error) {
key := c.Context().UserValue(utils.UVCacheKey).(*Key)

var body []byte
if body, e = m.cache.CachedResponse(key.UnsafeString()); e != nil {
if e = m.cache.Write(key.UnsafeString(), c); e != nil {
return
}

return m.respondWithStatus(c, body, fiber.StatusOK)
return m.respondWithStatus(c, nil, fiber.StatusOK)
}

func (m *Proxy) respondWithStatus(c *fiber.Ctx, body []byte, status int) error {
Expand All @@ -166,7 +165,10 @@ func (m *Proxy) respondWithStatus(c *fiber.Ctx, body []byte, status int) error {
m.cache.Stats().Hits, m.cache.Stats().Misses)
}

c.Response().SetBodyRaw(body)
if body != nil {
c.Response().SetBodyRaw(body)
}

c.Response().Header.SetContentType(fiber.MIMEApplicationJSONCharsetUTF8)
return c.SendStatus(status)
}
6 changes: 5 additions & 1 deletion internal/proxy/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,10 @@ func (m *Validator) encodeFormData() (e error) {

for k, v := range form.Value {
m.requestArgs.Add(k, v[0])
rlog(m.Ctx).Trace().Msg("parsed form value " + k + " - " + v[0])

if zerolog.GlobalLevel() <= zerolog.DebugLevel {
rlog(m.Ctx).Trace().Msg("parsed form value " + k + " - " + v[0])
}
}

// TODO - with go1.21.0 we can use:
Expand All @@ -206,6 +209,7 @@ func (m *Validator) encodeFormData() (e error) {

func (m *Validator) isArgsWhitelisted() (_ bool) {
// TODO too much allocations here:
// ? maybe make 'pool' fro chans map[size][]chan []byte?
declinedKeys := make(chan []byte, m.requestArgs.Len())

m.requestArgs.VisitAll(func(key, value []byte) {
Expand Down
6 changes: 0 additions & 6 deletions internal/service/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

"github.com/anilibria/alice/internal/utils"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/pprof"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/fiber/v2/middleware/skip"
Expand Down Expand Up @@ -125,11 +124,6 @@ func (m *Service) fiberMiddlewareInitialization() {
Prefix: gCli.String("http-pprof-prefix"),
}))
}

// compress support
m.fb.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed,
}))
}

func (m *Service) fiberRouterInitialization() {
Expand Down

0 comments on commit 5461c22

Please sign in to comment.