From 4c2ec882ac610cf17315cca8df14f061d0386a47 Mon Sep 17 00:00:00 2001 From: Jacob Gunther Date: Fri, 3 Mar 2023 18:59:51 -0600 Subject: [PATCH] Improve Redis efficiency and speed with pipelining --- src/redis.go | 75 +++++++++------------------------------------ src/routes.go | 12 ++++---- src/status.go | 84 +++++++++++++++++---------------------------------- 3 files changed, 48 insertions(+), 123 deletions(-) diff --git a/src/redis.go b/src/redis.go index fc12d08..2c384f0 100644 --- a/src/redis.go +++ b/src/redis.go @@ -27,78 +27,31 @@ func (r *Redis) Connect() error { return r.Client.Ping(ctx).Err() } -func (r *Redis) Exists(key string) (bool, error) { +func (r *Redis) Get(key string) ([]byte, time.Duration, error) { if r.Client == nil { - return false, nil + return nil, 0, nil } ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - res := r.Client.Exists(ctx, key) + p := r.Client.Pipeline() - if err := res.Err(); err != nil { - return false, err + value := p.Get(ctx, key) + ttl := p.TTL(ctx, key) + + if _, err := p.Exec(ctx); err != nil { + if err == redis.Nil { + return nil, 0, nil + } + + return nil, 0, err } - val, err := res.Result() + data, err := value.Bytes() - return val == 1, err -} - -func (r *Redis) TTL(key string) (time.Duration, error) { - if r.Client == nil { - return 0, nil - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - - defer cancel() - - res := r.Client.TTL(ctx, key) - - if err := res.Err(); err != nil { - return 0, err - } - - return res.Result() -} - -func (r *Redis) GetString(key string) (string, error) { - if r.Client == nil { - return "", nil - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - - defer cancel() - - res := r.Client.Get(ctx, key) - - if err := res.Err(); err != nil { - return "", nil - } - - return res.Result() -} - -func (r *Redis) GetBytes(key string) ([]byte, error) { - if r.Client == nil { - return nil, nil - } - - ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) - - defer cancel() - - res := r.Client.Get(ctx, key) - - if err := res.Err(); err != nil { - return nil, err - } - - return res.Bytes() + return data, ttl.Val(), err } func (r *Redis) Set(key string, value interface{}, ttl time.Duration) error { diff --git a/src/routes.go b/src/routes.go index 70c0233..4523353 100644 --- a/src/routes.go +++ b/src/routes.go @@ -38,9 +38,9 @@ func JavaStatusHandler(ctx *fiber.Ctx) error { return err } - ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != nil)) + ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != 0)) - if expiresAt != nil { + if expiresAt != 0 { ctx.Set("X-Cache-Time-Remaining", strconv.Itoa(int(expiresAt.Seconds()))) } @@ -64,9 +64,9 @@ func BedrockStatusHandler(ctx *fiber.Ctx) error { return err } - ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != nil)) + ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != 0)) - if expiresAt != nil { + if expiresAt != 0 { ctx.Set("X-Cache-Time-Remaining", strconv.Itoa(int(expiresAt.Seconds()))) } @@ -86,9 +86,9 @@ func IconHandler(ctx *fiber.Ctx) error { return err } - ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != nil)) + ctx.Set("X-Cache-Hit", strconv.FormatBool(expiresAt != 0)) - if expiresAt != nil { + if expiresAt != 0 { ctx.Set("X-Cache-Time-Remaining", strconv.Itoa(int(expiresAt.Seconds()))) } diff --git a/src/status.go b/src/status.go index 28d6d28..f1769d9 100644 --- a/src/status.go +++ b/src/status.go @@ -87,117 +87,89 @@ type Mod struct { Version string `json:"version"` } -func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, *time.Duration, error) { +func GetJavaStatus(host string, port uint16) (*JavaStatusResponse, time.Duration, error) { cacheKey := fmt.Sprintf("java:%s-%d", host, port) - exists, err := r.Exists(cacheKey) + cache, ttl, err := r.Get(cacheKey) if err != nil { - return nil, nil, err + return nil, 0, err } - if exists { - data, err := r.GetBytes(cacheKey) - - if err != nil { - return nil, nil, err - } - + if cache != nil { var response JavaStatusResponse - if err = json.Unmarshal(data, &response); err != nil { - return nil, nil, err - } + err = json.Unmarshal(cache, &response) - ttl, err := r.TTL(cacheKey) - - return &response, &ttl, err + return &response, ttl, err } response, err := FetchJavaStatus(host, port) if err != nil { - return nil, nil, err + return nil, 0, err } data, err := json.Marshal(response) if err != nil { - return nil, nil, err + return nil, 0, err } if err := r.Set(cacheKey, data, config.Cache.JavaStatusDuration); err != nil { - return nil, nil, err + return nil, 0, err } - return response, nil, nil + return response, 0, nil } -func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, *time.Duration, error) { +func GetBedrockStatus(host string, port uint16) (*BedrockStatusResponse, time.Duration, error) { cacheKey := fmt.Sprintf("bedrock:%s-%d", host, port) - exists, err := r.Exists(cacheKey) + cache, ttl, err := r.Get(cacheKey) if err != nil { - return nil, nil, err + return nil, 0, err } - if exists { - data, err := r.GetBytes(cacheKey) - - if err != nil { - return nil, nil, err - } - + if cache != nil { var response BedrockStatusResponse - if err = json.Unmarshal(data, &response); err != nil { - return nil, nil, err - } + err = json.Unmarshal(cache, &response) - ttl, err := r.TTL(cacheKey) - - return &response, &ttl, err + return &response, ttl, err } response, err := FetchBedrockStatus(host, port) if err != nil { - return nil, nil, err + return nil, 0, err } data, err := json.Marshal(response) if err != nil { - return nil, nil, err + return nil, 0, err } if err := r.Set(cacheKey, data, config.Cache.BedrockStatusDuration); err != nil { - return nil, nil, err + return nil, 0, err } - return response, nil, nil + return response, 0, nil } -func GetServerIcon(host string, port uint16) ([]byte, *time.Duration, error) { +func GetServerIcon(host string, port uint16) ([]byte, time.Duration, error) { cacheKey := fmt.Sprintf("icon:%s-%d", host, port) - exists, err := r.Exists(cacheKey) + cache, ttl, err := r.Get(cacheKey) if err != nil { - return nil, nil, err + return nil, 0, err } - if exists { - data, err := r.GetBytes(cacheKey) - - if err != nil { - return nil, nil, err - } - - ttl, err := r.TTL(cacheKey) - - return data, &ttl, err + if cache != nil { + return cache, ttl, err } icon := defaultIcon @@ -208,17 +180,17 @@ func GetServerIcon(host string, port uint16) ([]byte, *time.Duration, error) { data, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(*status.Favicon, "data:image/png;base64,")) if err != nil { - return nil, nil, err + return nil, 0, err } icon = data } if err := r.Set(cacheKey, icon, config.Cache.IconDuration); err != nil { - return nil, nil, err + return nil, 0, err } - return icon, nil, nil + return icon, 0, nil } func FetchJavaStatus(host string, port uint16) (*JavaStatusResponse, error) {