diff --git a/vendor/github.com/hashicorp/go-memdb/filter.go b/vendor/github.com/hashicorp/go-memdb/filter.go index 2e3a9b3f7b7..0071ab311a1 100644 --- a/vendor/github.com/hashicorp/go-memdb/filter.go +++ b/vendor/github.com/hashicorp/go-memdb/filter.go @@ -13,17 +13,22 @@ type FilterIterator struct { iter ResultIterator } -func NewFilterIterator(wrap ResultIterator, filter FilterFunc) *FilterIterator { +// NewFilterIterator wraps a ResultIterator. The filter function is applied +// to each value returned by a call to iter.Next. +// +// See the documentation for ResultIterator to understand the behaviour of the +// returned FilterIterator. +func NewFilterIterator(iter ResultIterator, filter FilterFunc) *FilterIterator { return &FilterIterator{ filter: filter, - iter: wrap, + iter: iter, } } // WatchCh returns the watch channel of the wrapped iterator. func (f *FilterIterator) WatchCh() <-chan struct{} { return f.iter.WatchCh() } -// Next returns the next non-filtered result from the wrapped iterator +// Next returns the next non-filtered result from the wrapped iterator. func (f *FilterIterator) Next() interface{} { for { if value := f.iter.Next(); value == nil || !f.filter(value) { diff --git a/vendor/github.com/hashicorp/go-memdb/index.go b/vendor/github.com/hashicorp/go-memdb/index.go index 41c392b5f2f..3b87d94f67b 100644 --- a/vendor/github.com/hashicorp/go-memdb/index.go +++ b/vendor/github.com/hashicorp/go-memdb/index.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "errors" "fmt" + "math/bits" "reflect" "strings" ) @@ -380,8 +381,7 @@ func (u *UintFieldIndex) FromObject(obj interface{}) (bool, []byte, error) { // Get the value and encode it val := fv.Uint() - buf := make([]byte, size) - binary.PutUvarint(buf, val) + buf := encodeUInt(val, size) return true, buf, nil } @@ -403,26 +403,42 @@ func (u *UintFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { } val := v.Uint() - buf := make([]byte, size) - binary.PutUvarint(buf, val) + buf := encodeUInt(val, size) return buf, nil } +func encodeUInt(val uint64, size int) []byte { + buf := make([]byte, size) + + switch size { + case 1: + buf[0] = uint8(val) + case 2: + binary.BigEndian.PutUint16(buf, uint16(val)) + case 4: + binary.BigEndian.PutUint32(buf, uint32(val)) + case 8: + binary.BigEndian.PutUint64(buf, val) + } + + return buf +} + // IsUintType returns whether the passed type is a type of uint and the number // of bytes needed to encode the type. func IsUintType(k reflect.Kind) (size int, okay bool) { switch k { case reflect.Uint: - return binary.MaxVarintLen64, true + return bits.UintSize / 8, true case reflect.Uint8: - return 2, true + return 1, true case reflect.Uint16: - return binary.MaxVarintLen16, true + return 2, true case reflect.Uint32: - return binary.MaxVarintLen32, true + return 4, true case reflect.Uint64: - return binary.MaxVarintLen64, true + return 8, true default: return 0, false } diff --git a/vendor/github.com/hashicorp/go-memdb/memdb.go b/vendor/github.com/hashicorp/go-memdb/memdb.go index 65c92073104..25f6bc89253 100644 --- a/vendor/github.com/hashicorp/go-memdb/memdb.go +++ b/vendor/github.com/hashicorp/go-memdb/memdb.go @@ -10,11 +10,19 @@ import ( "github.com/hashicorp/go-immutable-radix" ) -// MemDB is an in-memory database. +// MemDB is an in-memory database providing Atomicity, Consistency, and +// Isolation from ACID. MemDB doesn't provide Durability since it is an +// in-memory database. // // MemDB provides a table abstraction to store objects (rows) with multiple // indexes based on inserted values. The database makes use of immutable radix // trees to provide transactions and MVCC. +// +// Objects inserted into MemDB are not copied. It is **extremely important** +// that objects are not modified in-place after they are inserted since they +// are stored directly in MemDB. It remains unsafe to modify inserted objects +// even after they've been deleted from MemDB since there may still be older +// snapshots of the DB being read from other goroutines. type MemDB struct { schema *DBSchema root unsafe.Pointer // *iradix.Tree underneath @@ -24,7 +32,7 @@ type MemDB struct { writer sync.Mutex } -// NewMemDB creates a new MemDB with the given schema +// NewMemDB creates a new MemDB with the given schema. func NewMemDB(schema *DBSchema) (*MemDB, error) { // Validate the schema if err := schema.Validate(); err != nil { @@ -50,7 +58,7 @@ func (db *MemDB) getRoot() *iradix.Tree { return root } -// Txn is used to start a new transaction, in either read or write mode. +// Txn is used to start a new transaction in either read or write mode. // There can only be a single concurrent writer, but any number of readers. func (db *MemDB) Txn(write bool) *Txn { if write { @@ -64,9 +72,12 @@ func (db *MemDB) Txn(write bool) *Txn { return txn } -// Snapshot is used to capture a point-in-time snapshot -// of the database that will not be affected by any write -// operations to the existing DB. +// Snapshot is used to capture a point-in-time snapshot of the database that +// will not be affected by any write operations to the existing DB. +// +// If MemDB is storing reference-based values (pointers, maps, slices, etc.), +// the Snapshot will not deep copy those values. Therefore, it is still unsafe +// to modify any inserted values in either DB. func (db *MemDB) Snapshot() *MemDB { clone := &MemDB{ schema: db.schema, diff --git a/vendor/github.com/hashicorp/go-memdb/txn.go b/vendor/github.com/hashicorp/go-memdb/txn.go index 68734e37c86..1a9da1a7102 100644 --- a/vendor/github.com/hashicorp/go-memdb/txn.go +++ b/vendor/github.com/hashicorp/go-memdb/txn.go @@ -52,16 +52,16 @@ func (txn *Txn) TrackChanges() { } } -// readableIndex returns a transaction usable for reading the given -// index in a table. If a write transaction is in progress, we may need -// to use an existing modified txn. +// readableIndex returns a transaction usable for reading the given index in a +// table. If the transaction is a write transaction with modifications, a clone of the +// modified index will be returned. func (txn *Txn) readableIndex(table, index string) *iradix.Txn { // Look for existing transaction if txn.write && txn.modified != nil { key := tableIndex{table, index} exist, ok := txn.modified[key] if ok { - return exist + return exist.Clone() } } @@ -170,7 +170,11 @@ func (txn *Txn) Commit() { } } -// Insert is used to add or update an object into the given table +// Insert is used to add or update an object into the given table. +// +// When updating an object, the obj provided should be a copy rather +// than a value updated in-place. Modifying values in-place that are already +// inserted into MemDB is not supported behavior. func (txn *Txn) Insert(table string, obj interface{}) error { if !txn.write { return fmt.Errorf("cannot insert in read-only transaction") @@ -293,8 +297,8 @@ func (txn *Txn) Insert(table string, obj interface{}) error { return nil } -// Delete is used to delete a single object from the given table -// This object must already exist in the table +// Delete is used to delete a single object from the given table. +// This object must already exist in the table. func (txn *Txn) Delete(table string, obj interface{}) error { if !txn.write { return fmt.Errorf("cannot delete in read-only transaction") @@ -663,15 +667,42 @@ func (txn *Txn) getIndexValue(table, index string, args ...interface{}) (*IndexS return indexSchema, val, err } -// ResultIterator is used to iterate over a list of results -// from a Get query on a table. +// ResultIterator is used to iterate over a list of results from a query on a table. +// +// When a ResultIterator is created from a write transaction, the results from +// Next will reflect a snapshot of the table at the time the ResultIterator is +// created. +// This means that calling Insert or Delete on a transaction while iterating is +// allowed, but the changes made by Insert or Delete will not be observed in the +// results returned from subsequent calls to Next. For example if an item is deleted +// from the index used by the iterator it will still be returned by Next. If an +// item is inserted into the index used by the iterator, it will not be returned +// by Next. However, an iterator created after a call to Insert or Delete will +// reflect the modifications. +// +// When a ResultIterator is created from a write transaction, and there are already +// modifications to the index used by the iterator, the modification cache of the +// index will be invalidated. This may result in some additional allocations if +// the same node in the index is modified again. type ResultIterator interface { WatchCh() <-chan struct{} + // Next returns the next result from the iterator. If there are no more results + // nil is returned. Next() interface{} } -// Get is used to construct a ResultIterator over all the -// rows that match the given constraints of an index. +// Get is used to construct a ResultIterator over all the rows that match the +// given constraints of an index. The index values must match exactly (this +// is not a range-based or prefix-based lookup) by default. +// +// Prefix lookups: if the named index implements PrefixIndexer, you may perform +// prefix-based lookups by appending "_prefix" to the index name. In this +// scenario, the index values given in args are treated as prefix lookups. For +// example, a StringFieldIndex will match any string with the given value +// as a prefix: "mem" matches "memdb". +// +// See the documentation for ResultIterator to understand the behaviour of the +// returned ResultIterator. func (txn *Txn) Get(table, index string, args ...interface{}) (ResultIterator, error) { indexIter, val, err := txn.getIndexIterator(table, index, args...) if err != nil { @@ -691,7 +722,11 @@ func (txn *Txn) Get(table, index string, args ...interface{}) (ResultIterator, e // GetReverse is used to construct a Reverse ResultIterator over all the // rows that match the given constraints of an index. -// The returned ResultIterator's Next() will return the next Previous value +// The returned ResultIterator's Next() will return the next Previous value. +// +// See the documentation on Get for details on arguments. +// See the documentation for ResultIterator to understand the behaviour of the +// returned ResultIterator. func (txn *Txn) GetReverse(table, index string, args ...interface{}) (ResultIterator, error) { indexIter, val, err := txn.getIndexIteratorReverse(table, index, args...) if err != nil { @@ -715,6 +750,9 @@ func (txn *Txn) GetReverse(table, index string, args ...interface{}) (ResultIter // range scans within an index. It is not possible to watch the resulting // iterator since the radix tree doesn't efficiently allow watching on lower // bound changes. The WatchCh returned will be nill and so will block forever. +// +// See the documentation for ResultIterator to understand the behaviour of the +// returned ResultIterator. func (txn *Txn) LowerBound(table, index string, args ...interface{}) (ResultIterator, error) { indexIter, val, err := txn.getIndexIterator(table, index, args...) if err != nil { @@ -738,6 +776,9 @@ func (txn *Txn) LowerBound(table, index string, args ...interface{}) (ResultIter // resulting iterator since the radix tree doesn't efficiently allow watching // on lower bound changes. The WatchCh returned will be nill and so will block // forever. +// +// See the documentation for ResultIterator to understand the behaviour of the +// returned ResultIterator. func (txn *Txn) ReverseLowerBound(table, index string, args ...interface{}) (ResultIterator, error) { indexIter, val, err := txn.getIndexIteratorReverse(table, index, args...) if err != nil { @@ -850,7 +891,7 @@ func (txn *Txn) getIndexIterator(table, index string, args ...interface{}) (*ira indexTxn := txn.readableIndex(table, indexSchema.Name) indexRoot := indexTxn.Root() - // Get an interator over the index + // Get an iterator over the index indexIter := indexRoot.Iterator() return indexIter, val, nil } diff --git a/vendor/modules.txt b/vendor/modules.txt index 99450433ef1..0b17e374e9a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -423,7 +423,7 @@ github.com/hashicorp/go-hclog # github.com/hashicorp/go-immutable-radix v1.3.0 ## explicit github.com/hashicorp/go-immutable-radix -# github.com/hashicorp/go-memdb v1.3.0 +# github.com/hashicorp/go-memdb v1.3.2 ## explicit github.com/hashicorp/go-memdb # github.com/hashicorp/go-msgpack v1.1.5