2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-06-13 19:22:32 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package storage
|
|
|
|
|
2018-08-14 16:22:29 +01:00
|
|
|
import (
|
2018-09-05 17:10:35 +01:00
|
|
|
"bytes"
|
2019-06-05 15:23:10 +01:00
|
|
|
"context"
|
2018-09-05 17:10:35 +01:00
|
|
|
"errors"
|
|
|
|
|
2019-11-08 20:40:39 +00:00
|
|
|
"github.com/spacemonkeygo/monkit/v3"
|
2018-08-14 16:22:29 +01:00
|
|
|
"github.com/zeebo/errs"
|
|
|
|
)
|
|
|
|
|
2019-06-05 15:23:10 +01:00
|
|
|
var mon = monkit.Package()
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Delimiter separates nested paths in storage.
|
2018-09-05 17:10:35 +01:00
|
|
|
const Delimiter = '/'
|
|
|
|
|
2019-07-23 20:46:33 +01:00
|
|
|
//ErrKeyNotFound used when something doesn't exist
|
2018-08-14 16:22:29 +01:00
|
|
|
var ErrKeyNotFound = errs.Class("key not found")
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ErrEmptyKey is returned when an empty key is used in Put or in CompareAndSwap.
|
2018-11-15 15:31:33 +00:00
|
|
|
var ErrEmptyKey = errs.Class("empty key")
|
2018-09-05 17:10:35 +01:00
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ErrValueChanged is returned when the current value of the key does not match the oldValue in CompareAndSwap.
|
2019-07-23 20:46:33 +01:00
|
|
|
var ErrValueChanged = errs.Class("value changed")
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ErrEmptyQueue is returned when attempting to Dequeue from an empty queue.
|
2019-01-02 16:00:32 +00:00
|
|
|
var ErrEmptyQueue = errs.Class("empty queue")
|
2018-11-14 21:30:07 +00:00
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ErrLimitExceeded is returned when request limit is exceeded.
|
2018-09-07 10:00:00 +01:00
|
|
|
var ErrLimitExceeded = errors.New("limit exceeded")
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Key is the type for the keys in a `KeyValueStore`.
|
2018-06-13 19:22:32 +01:00
|
|
|
type Key []byte
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Value is the type for the values in a `ValueValueStore`.
|
2018-06-13 19:22:32 +01:00
|
|
|
type Value []byte
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Keys is the type for a slice of keys in a `KeyValueStore`.
|
2018-06-13 19:22:32 +01:00
|
|
|
type Keys []Key
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Values is the type for a slice of Values in a `KeyValueStore`.
|
2018-08-01 15:15:38 +01:00
|
|
|
type Values []Value
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Items keeps all ListItem.
|
2018-08-26 04:00:49 +01:00
|
|
|
type Items []ListItem
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// DefaultLookupLimit is the default lookup limit for storage implementations.
|
2020-01-22 19:00:46 +00:00
|
|
|
const DefaultLookupLimit = 10000
|
2018-09-07 10:00:00 +01:00
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ListItem returns Key, Value, IsPrefix.
|
2018-08-26 04:00:49 +01:00
|
|
|
type ListItem struct {
|
|
|
|
Key Key
|
|
|
|
Value Value
|
|
|
|
IsPrefix bool
|
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// KeyValueStore describes key/value stores like redis and boltdb.
|
2018-06-13 19:22:32 +01:00
|
|
|
type KeyValueStore interface {
|
2020-02-17 07:56:13 +00:00
|
|
|
// Put adds a value to store.
|
2019-06-05 15:23:10 +01:00
|
|
|
Put(context.Context, Key, Value) error
|
2020-02-17 07:56:13 +00:00
|
|
|
// Get gets a value to store.
|
2019-06-05 15:23:10 +01:00
|
|
|
Get(context.Context, Key) (Value, error)
|
2020-02-17 07:56:13 +00:00
|
|
|
// GetAll gets all values from the store.
|
2019-06-05 15:23:10 +01:00
|
|
|
GetAll(context.Context, Keys) (Values, error)
|
2020-02-17 07:56:13 +00:00
|
|
|
// Delete deletes key and the value.
|
2019-06-05 15:23:10 +01:00
|
|
|
Delete(context.Context, Key) error
|
2020-02-17 07:56:13 +00:00
|
|
|
// DeleteMultiple deletes keys and returns nil for.
|
2020-01-28 20:52:04 +00:00
|
|
|
DeleteMultiple(context.Context, []Key) (Items, error)
|
2020-02-17 07:56:13 +00:00
|
|
|
// List lists all keys starting from start and upto limit items.
|
2019-06-05 15:23:10 +01:00
|
|
|
List(ctx context.Context, start Key, limit int) (Keys, error)
|
2020-02-17 07:56:13 +00:00
|
|
|
// Iterate iterates over items based on opts.
|
2019-06-05 15:23:10 +01:00
|
|
|
Iterate(ctx context.Context, opts IterateOptions, fn func(context.Context, Iterator) error) error
|
2020-02-17 07:56:13 +00:00
|
|
|
// CompareAndSwap atomically compares and swaps oldValue with newValue.
|
2019-07-23 20:46:33 +01:00
|
|
|
CompareAndSwap(ctx context.Context, key Key, oldValue, newValue Value) error
|
2020-02-17 07:56:13 +00:00
|
|
|
// Close closes the store.
|
2018-06-13 19:22:32 +01:00
|
|
|
Close() error
|
2020-01-22 19:00:46 +00:00
|
|
|
|
|
|
|
// LookupLimit returns the maximum limit that is allowed.
|
|
|
|
LookupLimit() int
|
2018-06-13 19:22:32 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// IterateOptions contains options for iterator.
|
2018-09-05 17:10:35 +01:00
|
|
|
type IterateOptions struct {
|
2020-02-17 07:56:13 +00:00
|
|
|
// Prefix ensure.
|
2018-09-05 17:10:35 +01:00
|
|
|
Prefix Key
|
2020-02-17 07:56:13 +00:00
|
|
|
// First will be the first item iterator returns or the next item (previous when reverse).
|
2018-09-05 17:10:35 +01:00
|
|
|
First Key
|
2020-02-17 07:56:13 +00:00
|
|
|
// Recurse, do not collapse items based on Delimiter.
|
2018-09-05 17:10:35 +01:00
|
|
|
Recurse bool
|
2020-02-17 07:56:13 +00:00
|
|
|
// The maximum number of elements to be returned.
|
2020-01-19 19:56:51 +00:00
|
|
|
Limit int
|
2018-09-05 17:10:35 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Iterator iterates over a sequence of ListItems.
|
2018-09-05 17:10:35 +01:00
|
|
|
type Iterator interface {
|
2019-04-11 18:32:40 +01:00
|
|
|
// Next prepares the next list item.
|
|
|
|
// It returns true on success, or false if there is no next result row or an error happened while preparing it.
|
2019-06-05 15:23:10 +01:00
|
|
|
Next(ctx context.Context, item *ListItem) bool
|
2018-09-05 17:10:35 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// IteratorFunc implements basic iterator.
|
|
|
|
type IteratorFunc func(ctx context.Context, item *ListItem) bool
|
|
|
|
|
|
|
|
// Next returns the next item.
|
|
|
|
func (next IteratorFunc) Next(ctx context.Context, item *ListItem) bool { return next(ctx, item) }
|
|
|
|
|
|
|
|
// IsZero returns true if the value struct is it's zero value.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (value Value) IsZero() bool {
|
|
|
|
return len(value) == 0
|
2018-06-29 21:06:25 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// IsZero returns true if the key struct is it's zero value.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (key Key) IsZero() bool {
|
|
|
|
return len(key) == 0
|
2018-06-29 21:06:25 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// MarshalBinary implements the encoding.BinaryMarshaler interface for the Value type.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (value Value) MarshalBinary() ([]byte, error) {
|
|
|
|
return value, nil
|
2018-06-13 19:22:32 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// MarshalBinary implements the encoding.BinaryMarshaler interface for the Key type.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (key Key) MarshalBinary() ([]byte, error) {
|
|
|
|
return key, nil
|
2018-06-13 19:22:32 +01:00
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// ByteSlices converts a `Keys` struct to a slice of byte-slices (i.e. `[][]byte`).
|
2018-09-05 17:10:35 +01:00
|
|
|
func (keys Keys) ByteSlices() [][]byte {
|
|
|
|
result := make([][]byte, len(keys))
|
2018-06-13 19:22:32 +01:00
|
|
|
|
2018-09-05 17:10:35 +01:00
|
|
|
for key, val := range keys {
|
|
|
|
result[key] = []byte(val)
|
2018-06-13 19:22:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// String implements the Stringer interface.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (key Key) String() string { return string(key) }
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Strings returns everything as strings.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (keys Keys) Strings() []string {
|
|
|
|
strs := make([]string, 0, len(keys))
|
|
|
|
for _, key := range keys {
|
|
|
|
strs = append(strs, string(key))
|
|
|
|
}
|
|
|
|
return strs
|
2018-06-13 19:22:32 +01:00
|
|
|
}
|
2018-08-26 04:00:49 +01:00
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// GetKeys gets all the Keys in []ListItem and converts them to Keys.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (items Items) GetKeys() Keys {
|
|
|
|
if len(items) == 0 {
|
2018-08-26 04:00:49 +01:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var keys Keys
|
2018-09-05 17:10:35 +01:00
|
|
|
for _, item := range items {
|
2018-08-26 04:00:49 +01:00
|
|
|
keys = append(keys, item.Key)
|
|
|
|
}
|
|
|
|
return keys
|
|
|
|
}
|
2018-09-05 17:10:35 +01:00
|
|
|
|
|
|
|
// Len is the number of elements in the collection.
|
|
|
|
func (items Items) Len() int { return len(items) }
|
|
|
|
|
|
|
|
// Less reports whether the element with
|
|
|
|
// index i should sort before the element with index j.
|
|
|
|
func (items Items) Less(i, k int) bool { return items[i].Less(items[k]) }
|
|
|
|
|
|
|
|
// Swap swaps the elements with indexes i and j.
|
|
|
|
func (items Items) Swap(i, k int) { items[i], items[k] = items[k], items[i] }
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Less returns whether item should be sorted before b.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (item ListItem) Less(b ListItem) bool { return item.Key.Less(b.Key) }
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Less returns whether key should be sorted before b.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (key Key) Less(b Key) bool { return bytes.Compare([]byte(key), []byte(b)) < 0 }
|
|
|
|
|
2020-02-17 07:56:13 +00:00
|
|
|
// Equal returns whether key and b are equal.
|
2018-09-05 17:10:35 +01:00
|
|
|
func (key Key) Equal(b Key) bool { return bytes.Equal([]byte(key), []byte(b)) }
|