Skip to content

Commit

Permalink
move BucketCacheKey to a new package
Browse files Browse the repository at this point in the history
Signed-off-by: akanshat <[email protected]>
  • Loading branch information
akanshat committed Oct 30, 2021
1 parent fa71971 commit 9aca02c
Show file tree
Hide file tree
Showing 5 changed files with 253 additions and 279 deletions.
75 changes: 15 additions & 60 deletions pkg/cache/groupcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import (
"context"
"encoding/json"
"io/ioutil"
"regexp"
"strconv"
"strings"
"time"

"github.com/go-kit/kit/log"
Expand All @@ -22,6 +20,7 @@ import (
"github.com/thanos-io/thanos/pkg/model"
"github.com/thanos-io/thanos/pkg/objstore"
"github.com/thanos-io/thanos/pkg/runutil"
"github.com/thanos-io/thanos/pkg/store/cache/cachekey"
"gopkg.in/yaml.v2"
)

Expand Down Expand Up @@ -63,53 +62,6 @@ var (
}
)

type ExistsVerb struct {
Name string
}

type ContentVerb struct {
Name string
}

type IterVerb struct {
Name string
}

type SubrangeVerb struct {
Name string
Start, End int64
}

type AttributesVerb struct {
Name string
}

func ParseGroupcacheKey(key string) interface{} {
if strings.HasPrefix(key, "attrs:") {
return &AttributesVerb{Name: key[6:]}
}
if strings.HasPrefix(key, "iter:") {
return &IterVerb{Name: key[5:]}
}
if strings.HasPrefix(key, "exists:") {
return &ExistsVerb{Name: key[7:]}
}
if strings.HasPrefix(key, "content:") {
return &ContentVerb{Name: key[8:]}
}
if strings.HasPrefix(key, "subrange:") {
r := regexp.MustCompile(`subrange:(?P<Name>.+):(?P<Start>\d+):(?P<End>\d+)`)
matches := r.FindStringSubmatch(key)

start, _ := strconv.ParseInt(matches[2], 10, 64)
end, _ := strconv.ParseInt(matches[3], 10, 64)

return &SubrangeVerb{Name: matches[1], Start: start, End: end}
}

panic("unsupported verb")
}

// parseGroupcacheConfig unmarshals a buffer into a GroupcacheConfig with default values.
func parseGroupcacheConfig(conf []byte) (GroupcacheConfig, error) {
config := DefaultGroupcacheConfig
Expand Down Expand Up @@ -164,11 +116,14 @@ func NewGroupcacheWithConfig(name string, logger log.Logger, reg prometheus.Regi

group := groupcache.NewGroup(conf.GroupcacheGroup, int64(conf.MaxSize), groupcache.GetterFunc(
func(ctx context.Context, id string, dest groupcache.Sink) error {
parsedData := ParseGroupcacheKey(id)
parsedData, err := cachekey.ParseBucketCacheKey(id)
if err != nil {
return err
}

switch v := parsedData.(type) {
case *AttributesVerb:
attrs, err := bucket.Attributes(ctx, v.Name)
switch parsedData.Verb {
case cachekey.AttributesVerb:
attrs, err := bucket.Attributes(ctx, parsedData.Name)
if err != nil {
return err
}
Expand All @@ -181,12 +136,12 @@ func NewGroupcacheWithConfig(name string, logger log.Logger, reg prometheus.Regi
if err != nil {
return err
}
case *IterVerb:
case cachekey.IterVerb:
// Not supported.

return nil
case *ContentVerb:
rc, err := bucket.Get(ctx, v.Name)
case cachekey.ContentVerb:
rc, err := bucket.Get(ctx, parsedData.Name)
if err != nil {
return err
}
Expand All @@ -201,8 +156,8 @@ func NewGroupcacheWithConfig(name string, logger log.Logger, reg prometheus.Regi
if err != nil {
return err
}
case *ExistsVerb:
exists, err := bucket.Exists(ctx, v.Name)
case cachekey.ExistsVerb:
exists, err := bucket.Exists(ctx, parsedData.Name)
if err != nil {
return err
}
Expand All @@ -211,8 +166,8 @@ func NewGroupcacheWithConfig(name string, logger log.Logger, reg prometheus.Regi
if err != nil {
return err
}
case *SubrangeVerb:
rc, err := bucket.GetRange(ctx, v.Name, v.Start, v.End-v.Start)
case cachekey.SubrangeVerb:
rc, err := bucket.GetRange(ctx, parsedData.Name, parsedData.Start, parsedData.End-parsedData.Start)
if err != nil {
return err
}
Expand Down
97 changes: 97 additions & 0 deletions pkg/store/cache/cachekey/cachekey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package cachekey

import (
"fmt"
"strconv"
"strings"

"github.com/pkg/errors"
)

var (
ErrInvalidBucketCacheKeyFormat = errors.New("key has invalid format")
ErrInvalidBucketCacheKeyVerb = errors.New("key has invalid verb")
ErrParseKeyInt = errors.New("failed to parse integer in key")
)

// VerbType is the type of operation whose result has been stored in the caching bucket's cache.
type VerbType string

const (
ExistsVerb VerbType = "exists"
ContentVerb VerbType = "content"
IterVerb VerbType = "iter"
AttributesVerb VerbType = "attrs"
SubrangeVerb VerbType = "subrange"
)

type BucketCacheKey struct {
Verb VerbType
Name string
Start int64
End int64
}

// String returns the string representation of BucketCacheKey.
func (ck BucketCacheKey) String() string {
if ck.Start == 0 && ck.End == 0 {
return fmt.Sprintf("%s:%s", ck.Verb, ck.Name)
}

return fmt.Sprintf("%s:%s:%d:%d", ck.Verb, ck.Name, ck.Start, ck.End)
}

// IsValidVerb checks if the VerbType matches the predefined verbs.
func IsValidVerb(v VerbType) bool {
switch v {
case
ExistsVerb,
ContentVerb,
IterVerb,
AttributesVerb,
SubrangeVerb:
return true
}
return false
}

// ParseBucketCacheKey parses a string and returns BucketCacheKey.
func ParseBucketCacheKey(key string) (BucketCacheKey, error) {
ck := BucketCacheKey{}
slice := strings.Split(key, ":")
if len(slice) < 2 {
return ck, ErrInvalidBucketCacheKeyFormat
}

verb := VerbType(slice[0])
if !IsValidVerb(verb) {
return BucketCacheKey{}, ErrInvalidBucketCacheKeyVerb
}

if verb == SubrangeVerb {
if len(slice) != 4 {
return BucketCacheKey{}, ErrInvalidBucketCacheKeyFormat
}

start, err := strconv.ParseInt(slice[2], 10, 64)
if err != nil {
return BucketCacheKey{}, ErrParseKeyInt
}

end, err := strconv.ParseInt(slice[3], 10, 64)
if err != nil {
return BucketCacheKey{}, ErrParseKeyInt
}

ck.Start = start
ck.End = end
} else {
if len(slice) != 2 {
return BucketCacheKey{}, ErrInvalidBucketCacheKeyFormat
}
}

ck.Verb = verb
ck.Name = slice[1]
return ck, nil
}
120 changes: 120 additions & 0 deletions pkg/store/cache/cachekey/cachekey_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package cachekey

import (
"testing"

"github.com/thanos-io/thanos/pkg/testutil"
)

func TestParseBucketCacheKey(t *testing.T) {
testcases := []struct {
key string
expected BucketCacheKey
expectedErr error
}{
{
key: "exists:name",
expected: BucketCacheKey{
Verb: ExistsVerb,
Name: "name",
Start: 0,
End: 0,
},
expectedErr: nil,
},
{
key: "content:name",
expected: BucketCacheKey{
Verb: ContentVerb,
Name: "name",
Start: 0,
End: 0,
},
expectedErr: nil,
},
{
key: "iter:name",
expected: BucketCacheKey{
Verb: IterVerb,
Name: "name",
Start: 0,
End: 0,
},
expectedErr: nil,
},
{
key: "attrs:name",
expected: BucketCacheKey{
Verb: AttributesVerb,
Name: "name",
Start: 0,
End: 0,
},
expectedErr: nil,
},
{
key: "subrange:name:10:20",
expected: BucketCacheKey{
Verb: SubrangeVerb,
Name: "name",
Start: 10,
End: 20,
},
expectedErr: nil,
},
// Any VerbType other than SubrangeVerb should not have a "start" and "end".
{
key: "iter:name:10:20",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyFormat,
},
// Key must always have a name.
{
key: "iter",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyFormat,
},
// Invalid VerbType should return an error.
{
key: "random:name",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyVerb,
},
// Start must be an integer.
{
key: "subrange:name:random:10",
expected: BucketCacheKey{},
expectedErr: ErrParseKeyInt,
},
// End must be an integer.
{
key: "subrange:name:10:random",
expected: BucketCacheKey{},
expectedErr: ErrParseKeyInt,
},
// SubrangeVerb must have start and end.
{
key: "subrange:name",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyFormat,
},
// SubrangeVerb must have start and end both.
{
key: "subrange:name:10",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyFormat,
},
// Key must not be an empty string.
{
key: "",
expected: BucketCacheKey{},
expectedErr: ErrInvalidBucketCacheKeyFormat,
},
}

for _, tc := range testcases {
res, err := ParseBucketCacheKey(tc.key)
testutil.Equals(t, tc.expectedErr, err)
testutil.Equals(t, tc.expected, res)
}
}
Loading

0 comments on commit 9aca02c

Please sign in to comment.