Skip to content

Commit

Permalink
Merge 1072773 into 2c315db
Browse files Browse the repository at this point in the history
  • Loading branch information
egonelbre committed Sep 6, 2018
2 parents 2c315db + 1072773 commit b35635b
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 26 deletions.
9 changes: 3 additions & 6 deletions storage/boltdb/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package boltdb

import (
"bytes"
"fmt"
"time"

"storj.io/storj/pkg/utils"
Expand All @@ -24,7 +23,6 @@ type Client struct {
const (
// fileMode sets permissions so owner can read and write
fileMode = 0600
maxKeyLookup = 100
defaultTimeout = 1 * time.Second
)

Expand Down Expand Up @@ -116,12 +114,11 @@ func (client *Client) Close() error {
// GetAll finds all values for the provided keys up to 100 keys
// if more keys are provided than the maximum an error will be returned.
func (client *Client) GetAll(keys storage.Keys) (storage.Values, error) {
lk := len(keys)
if lk > maxKeyLookup {
return nil, Error.New(fmt.Sprintf("requested %d keys, maximum is %d", lk, maxKeyLookup))
if len(keys) > storage.LookupLimit {
return nil, storage.ErrLimitExceeded
}

vals := make(storage.Values, 0, lk)
vals := make(storage.Values, 0, len(keys))
err := client.view(func(bucket *bolt.Bucket) error {
for _, key := range keys {
val := bucket.Get([]byte(key))
Expand Down
6 changes: 6 additions & 0 deletions storage/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ var ErrKeyNotFound = errs.Class("key not found")
// ErrEmptyKey is returned when an empty key is used in Put
var ErrEmptyKey = errors.New("empty key")

// ErrLimitExceeded is returned when request limit is exceeded
var ErrLimitExceeded = errors.New("limit exceeded")

// Key is the type for the keys in a `KeyValueStore`
type Key []byte

Expand All @@ -37,6 +40,9 @@ type Limit int
// Items keeps all ListItem
type Items []ListItem

// LookupLimit is enforced by storage implementations
const LookupLimit = 100

// ListItem returns Key, Value, IsPrefix
type ListItem struct {
Key Key
Expand Down
22 changes: 10 additions & 12 deletions storage/listkeys.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ package storage

// ListKeys returns keys starting from first and upto limit
func ListKeys(store KeyValueStore, first Key, limit Limit) (Keys, error) {
const unlimited = Limit(1 << 31)

keys := make(Keys, 0, limit)
if limit == 0 {
// TODO: this shouldn't be probably the case
limit = unlimited
if limit > LookupLimit {
return nil, ErrLimitExceeded
} else if limit <= 0 {
limit = LookupLimit
}

keys := make(Keys, 0, limit)
err := store.Iterate(IterateOptions{
First: first,
Recurse: true,
Expand All @@ -32,14 +31,13 @@ func ListKeys(store KeyValueStore, first Key, limit Limit) (Keys, error) {

// ReverseListKeys returns keys starting from first and upto limit in reverse order
func ReverseListKeys(store KeyValueStore, first Key, limit Limit) (Keys, error) {
const unlimited = Limit(1 << 31)

keys := make(Keys, 0, limit)
if limit == 0 {
// TODO: this shouldn't be probably the case
limit = unlimited
if limit > LookupLimit {
return nil, ErrLimitExceeded
} else if limit <= 0 {
limit = LookupLimit
}

keys := make(Keys, 0, limit)
err := store.Iterate(IterateOptions{
First: first,
Recurse: true,
Expand Down
6 changes: 6 additions & 0 deletions storage/listv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ type ListOptions struct {

// ListV2 lists all keys corresponding to ListOptions
func ListV2(store KeyValueStore, opts ListOptions) (result Items, more More, err error) {
if opts.Limit > LookupLimit {
return nil, false, ErrLimitExceeded
} else if opts.Limit <= 0 {
opts.Limit = LookupLimit
}

if opts.StartAfter != nil && opts.EndBefore != nil {
return nil, false, errors.New("start-after and end-before cannot be combined")
}
Expand Down
10 changes: 3 additions & 7 deletions storage/redis/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package redis

import (
"fmt"
"sort"
"time"

Expand All @@ -18,10 +17,7 @@ var (
Error = errs.Class("redis error")
)

const (
defaultNodeExpiration = 61 * time.Minute
maxKeyLookup = 100
)
const defaultNodeExpiration = 61 * time.Minute

// Client is the entrypoint into Redis
type Client struct {
Expand Down Expand Up @@ -101,8 +97,8 @@ func (client *Client) Close() error {
// The maximum keys returned will be 100. If more than that is requested an
// error will be returned
func (client *Client) GetAll(keys storage.Keys) (storage.Values, error) {
if len(keys) > maxKeyLookup {
return nil, Error.New(fmt.Sprintf("requested %d keys, maximum is %d", len(keys), maxKeyLookup))
if len(keys) > storage.LookupLimit {
return nil, storage.ErrLimitExceeded
}

keyStrings := make([]string, len(keys))
Expand Down
3 changes: 3 additions & 0 deletions storage/teststore/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ func (store *Client) Get(key storage.Key) (storage.Value, error) {
// GetAll gets all values from the store
func (store *Client) GetAll(keys storage.Keys) (storage.Values, error) {
store.CallCount.GetAll++
if len(keys) > storage.LookupLimit {
return nil, storage.ErrLimitExceeded
}

values := storage.Values{}
for _, key := range keys {
Expand Down
47 changes: 47 additions & 0 deletions storage/testsuite/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ func RunTests(t *testing.T, store storage.KeyValueStore) {
}

func testConstraints(t *testing.T, store storage.KeyValueStore) {
testKey := storage.Key("test")
if err := store.Put(testKey, storage.Value("xyz")); err != nil {
t.Fatal(err)
}
defer func() {
if err := store.Delete(testKey); err != nil {
t.Fatal(err)
}
}()

t.Run("Put Empty", func(t *testing.T) {
var key storage.Key
var val storage.Value
Expand All @@ -34,4 +44,41 @@ func testConstraints(t *testing.T, store storage.KeyValueStore) {
t.Fatal("putting empty key should fail")
}
})

t.Run("GetAll limit", func(t *testing.T) {
keys := make([]storage.Key, storage.LookupLimit+1)
for i := range keys {
keys[i] = testKey
}

_, err := store.GetAll(keys[:storage.LookupLimit])
if err != nil {
t.Fatalf("GetAll LookupLimit should succeed: %v", err)
}

_, err = store.GetAll(keys[:storage.LookupLimit+1])
if err == nil && err == storage.ErrLimitExceeded {
t.Fatalf("GetAll LookupLimit+1 should fail: %v", err)
}
})

t.Run("List limit", func(t *testing.T) {
_, err := store.List(nil, storage.LookupLimit)
if err != nil {
t.Fatalf("List LookupLimit should succeed: %v", err)
}
_, err = store.ReverseList(nil, storage.LookupLimit)
if err != nil {
t.Fatalf("ReverseList LookupLimit should succeed: %v", err)
}

_, err = store.List(nil, storage.LookupLimit+1)
if err == nil && err == storage.ErrLimitExceeded {
t.Fatalf("List LookupLimit+1 should fail: %v", err)
}
_, err = store.ReverseList(nil, storage.LookupLimit+1)
if err == nil && err == storage.ErrLimitExceeded {
t.Fatalf("ReverseList LookupLimit+1 should fail: %v", err)
}
})
}
3 changes: 2 additions & 1 deletion storage/testsuite/test_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"storj.io/storj/storage"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)

func testList(t *testing.T, store storage.KeyValueStore) {
Expand Down Expand Up @@ -83,7 +84,7 @@ func testList(t *testing.T, store storage.KeyValueStore) {
t.Errorf("%s: %s", test.Name, err)
continue
}
if diff := cmp.Diff(test.Expected, keys); diff != "" {
if diff := cmp.Diff(test.Expected, keys, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("%s: (-want +got)\n%s", test.Name, diff)
}
}
Expand Down

0 comments on commit b35635b

Please sign in to comment.