From cabd6b6105c2da23c0d11285a83f39ef60f3d51f Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 2 Jun 2020 14:18:19 -0400 Subject: [PATCH] Update go-memdb and go-lru dependencies --- .../github.com/hashicorp/go-memdb/README.md | 94 +++++++++---- .../github.com/hashicorp/go-memdb/changes.go | 34 +++++ vendor/github.com/hashicorp/go-memdb/index.go | 2 +- vendor/github.com/hashicorp/go-memdb/txn.go | 123 ++++++++++++++++++ vendor/github.com/hashicorp/golang-lru/go.mod | 2 + vendor/github.com/hashicorp/golang-lru/lru.go | 50 +++++-- .../hashicorp/golang-lru/simplelru/lru.go | 16 +++ .../golang-lru/simplelru/lru_interface.go | 7 +- vendor/modules.txt | 4 +- 9 files changed, 296 insertions(+), 36 deletions(-) create mode 100644 vendor/github.com/hashicorp/go-memdb/changes.go diff --git a/vendor/github.com/hashicorp/go-memdb/README.md b/vendor/github.com/hashicorp/go-memdb/README.md index 350f08d7d..f445a756d 100644 --- a/vendor/github.com/hashicorp/go-memdb/README.md +++ b/vendor/github.com/hashicorp/go-memdb/README.md @@ -37,45 +37,57 @@ The full documentation is available on [Godoc](http://godoc.org/github.com/hashi Example ======= -Below is a simple example of usage +Below is a [simple example](https://play.golang.org/p/gCGE9FA4og1) of usage ```go // Create a sample struct type Person struct { - Email string - Name string - Age int + Email string + Name string + Age int } // Create the DB schema schema := &memdb.DBSchema{ - Tables: map[string]*memdb.TableSchema{ - "person": &memdb.TableSchema{ - Name: "person", - Indexes: map[string]*memdb.IndexSchema{ - "id": &memdb.IndexSchema{ - Name: "id", - Unique: true, - Indexer: &memdb.StringFieldIndex{Field: "Email"}, - }, - }, - }, - }, + Tables: map[string]*memdb.TableSchema{ + "person": &memdb.TableSchema{ + Name: "person", + Indexes: map[string]*memdb.IndexSchema{ + "id": &memdb.IndexSchema{ + Name: "id", + Unique: true, + Indexer: &memdb.StringFieldIndex{Field: "Email"}, + }, + "age": &memdb.IndexSchema{ + Name: "age", + Unique: false, + Indexer: &memdb.IntFieldIndex{Field: "Age"}, + }, + }, + }, + }, } // Create a new data base db, err := memdb.NewMemDB(schema) if err != nil { - panic(err) + panic(err) } // Create a write transaction txn := db.Txn(true) -// Insert a new person -p := &Person{"joe@aol.com", "Joe", 30} -if err := txn.Insert("person", p); err != nil { - panic(err) +// Insert some people +people := []*Person{ + &Person{"joe@aol.com", "Joe", 30}, + &Person{"lucy@aol.com", "Lucy", 35}, + &Person{"tariq@aol.com", "Tariq", 21}, + &Person{"dorothy@aol.com", "Dorothy", 53}, +} +for _, p := range people { + if err := txn.Insert("person", p); err != nil { + panic(err) + } } // Commit the transaction @@ -88,11 +100,47 @@ defer txn.Abort() // Lookup by email raw, err := txn.First("person", "id", "joe@aol.com") if err != nil { - panic(err) + panic(err) } // Say hi! -fmt.Printf("Hello %s!", raw.(*Person).Name) +fmt.Printf("Hello %s!\n", raw.(*Person).Name) +// List all the people +it, err := txn.Get("person", "id") +if err != nil { + panic(err) +} + +fmt.Println("All the people:") +for obj := it.Next(); obj != nil; obj = it.Next() { + p := obj.(*Person) + fmt.Printf(" %s\n", p.Name) +} + +// Range scan over people with ages between 25 and 35 inclusive +it, err = txn.LowerBound("person", "age", 25) +if err != nil { + panic(err) +} + +fmt.Println("People aged 25 - 35:") +for obj := it.Next(); obj != nil; obj = it.Next() { + p := obj.(*Person) + if p.Age > 35 { + break + } + fmt.Printf(" %s is aged %d\n", p.Name, p.Age) +} +// Output: +// Hello Joe! +// All the people: +// Dorothy +// Joe +// Lucy +// Tariq +// People aged 25 - 35: +// Joe is aged 30 +// Lucy is aged 35 ``` diff --git a/vendor/github.com/hashicorp/go-memdb/changes.go b/vendor/github.com/hashicorp/go-memdb/changes.go new file mode 100644 index 000000000..35089f5ce --- /dev/null +++ b/vendor/github.com/hashicorp/go-memdb/changes.go @@ -0,0 +1,34 @@ +package memdb + +// Changes describes a set of mutations to memDB tables performed during a +// transaction. +type Changes []Change + +// Change describes a mutation to an object in a table. +type Change struct { + Table string + Before interface{} + After interface{} + + // primaryKey stores the raw key value from the primary index so that we can + // de-duplicate multiple updates of the same object in the same transaction + // but we don't expose this implementation detail to the consumer. + primaryKey []byte +} + +// Created returns true if the mutation describes a new object being inserted. +func (m *Change) Created() bool { + return m.Before == nil && m.After != nil +} + +// Updated returns true if the mutation describes an existing object being +// updated. +func (m *Change) Updated() bool { + return m.Before != nil && m.After != nil +} + +// Deleted returns true if the mutation describes an existing object being +// deleted. +func (m *Change) Deleted() bool { + return m.Before != nil && m.After == nil +} diff --git a/vendor/github.com/hashicorp/go-memdb/index.go b/vendor/github.com/hashicorp/go-memdb/index.go index e368319e5..604dff7e9 100644 --- a/vendor/github.com/hashicorp/go-memdb/index.go +++ b/vendor/github.com/hashicorp/go-memdb/index.go @@ -73,7 +73,7 @@ func (s *StringFieldIndex) FromObject(obj interface{}) (bool, []byte, error) { if isPtr && !fv.IsValid() { val := "" - return true, []byte(val), nil + return false, []byte(val), nil } val := fv.String() diff --git a/vendor/github.com/hashicorp/go-memdb/txn.go b/vendor/github.com/hashicorp/go-memdb/txn.go index 762a81b7c..5325d9f1e 100644 --- a/vendor/github.com/hashicorp/go-memdb/txn.go +++ b/vendor/github.com/hashicorp/go-memdb/txn.go @@ -33,9 +33,25 @@ type Txn struct { rootTxn *iradix.Txn after []func() + // changes is used to track the changes performed during the transaction. If + // it is nil at transaction start then changes are not tracked. + changes Changes + modified map[tableIndex]*iradix.Txn } +// TrackChanges enables change tracking for the transaction. If called at any +// point before commit, subsequent mutations will be recorded and can be +// retrieved using ChangeSet. Once this has been called on a transaction it +// can't be unset. As with other Txn methods it's not safe to call this from a +// different goroutine than the one making mutations or committing the +// transaction. +func (txn *Txn) TrackChanges() { + if txn.changes == nil { + txn.changes = make(Changes, 0, 1) + } +} + // 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. @@ -101,6 +117,7 @@ func (txn *Txn) Abort() { // Clear the txn txn.rootTxn = nil txn.modified = nil + txn.changes = nil // Release the writer lock since this is invalid txn.db.writer.Unlock() @@ -265,6 +282,14 @@ func (txn *Txn) Insert(table string, obj interface{}) error { indexTxn.Insert(val, obj) } } + if txn.changes != nil { + txn.changes = append(txn.changes, Change{ + Table: table, + Before: existing, // might be nil on a create + After: obj, + primaryKey: idVal, + }) + } return nil } @@ -332,6 +357,14 @@ func (txn *Txn) Delete(table string, obj interface{}) error { } } } + if txn.changes != nil { + txn.changes = append(txn.changes, Change{ + Table: table, + Before: existing, + After: nil, // Now nil indicates deletion + primaryKey: idVal, + }) + } return nil } @@ -376,6 +409,19 @@ func (txn *Txn) DeletePrefix(table string, prefix_index string, prefix string) ( if !ok { return false, fmt.Errorf("object missing primary index") } + if txn.changes != nil { + // Record the deletion + idTxn := txn.writableIndex(table, id) + existing, ok := idTxn.Get(idVal) + if ok { + txn.changes = append(txn.changes, Change{ + Table: table, + Before: existing, + After: nil, // Now nil indicates deletion + primaryKey: idVal, + }) + } + } // Remove the object from all the indexes except the given prefix index for name, indexSchema := range tableSchema.Indexes { if name == deletePrefixIndex { @@ -413,6 +459,7 @@ func (txn *Txn) DeletePrefix(table string, prefix_index string, prefix string) ( } } } + } if foundAny { indexTxn := txn.writableIndex(table, deletePrefixIndex) @@ -629,6 +676,82 @@ func (txn *Txn) LowerBound(table, index string, args ...interface{}) (ResultIter return iter, nil } +// objectID is a tuple of table name and the raw internal id byte slice +// converted to a string. It's only converted to a string to make it comparable +// so this struct can be used as a map index. +type objectID struct { + Table string + IndexVal string +} + +// mutInfo stores metadata about mutations to allow collapsing multiple +// mutations to the same object into one. +type mutInfo struct { + firstBefore interface{} + lastIdx int +} + +// Changes returns the set of object changes that have been made in the +// transaction so far. If change tracking is not enabled it wil always return +// nil. It can be called before or after Commit. If it is before Commit it will +// return all changes made so far which may not be the same as the final +// Changes. After abort it will always return nil. As with other Txn methods +// it's not safe to call this from a different goroutine than the one making +// mutations or committing the transaction. Mutations will appear in the order +// they were performed in the transaction but multiple operations to the same +// object will be collapsed so only the effective overall change to that object +// is present. If transaction operations are dependent (e.g. copy object X to Y +// then delete X) this might mean the set of mutations is incomplete to verify +// history, but it is complete in that the net effect is preserved (Y got a new +// value, X got removed). +func (txn *Txn) Changes() Changes { + if txn.changes == nil { + return nil + } + + // De-duplicate mutations by key so all take effect at the point of the last + // write but we keep the mutations in order. + dups := make(map[objectID]mutInfo) + for i, m := range txn.changes { + oid := objectID{ + Table: m.Table, + IndexVal: string(m.primaryKey), + } + // Store the latest mutation index for each key value + mi, ok := dups[oid] + if !ok { + // First entry for key, store the before value + mi.firstBefore = m.Before + } + mi.lastIdx = i + dups[oid] = mi + } + if len(dups) == len(txn.changes) { + // No duplicates found, fast path return it as is + return txn.changes + } + + // Need to remove the duplicates + cs := make(Changes, 0, len(dups)) + for i, m := range txn.changes { + oid := objectID{ + Table: m.Table, + IndexVal: string(m.primaryKey), + } + mi := dups[oid] + if mi.lastIdx == i { + // This was the latest value for this key copy it with the before value in + // case it's different. Note that m is not a pointer so we are not + // modifying the txn.changeSet here - it's already a copy. + m.Before = mi.firstBefore + cs = append(cs, m) + } + } + // Store the de-duped version in case this is called again + txn.changes = cs + return cs +} + func (txn *Txn) getIndexIterator(table, index string, args ...interface{}) (*iradix.Iterator, []byte, error) { // Get the index value to scan indexSchema, val, err := txn.getIndexValue(table, index, args...) diff --git a/vendor/github.com/hashicorp/golang-lru/go.mod b/vendor/github.com/hashicorp/golang-lru/go.mod index 824cb97e8..8ad8826b3 100644 --- a/vendor/github.com/hashicorp/golang-lru/go.mod +++ b/vendor/github.com/hashicorp/golang-lru/go.mod @@ -1 +1,3 @@ module github.com/hashicorp/golang-lru + +go 1.12 diff --git a/vendor/github.com/hashicorp/golang-lru/lru.go b/vendor/github.com/hashicorp/golang-lru/lru.go index 1cbe04b7d..4e5e9d8fd 100644 --- a/vendor/github.com/hashicorp/golang-lru/lru.go +++ b/vendor/github.com/hashicorp/golang-lru/lru.go @@ -37,7 +37,7 @@ func (c *Cache) Purge() { c.lock.Unlock() } -// Add adds a value to the cache. Returns true if an eviction occurred. +// Add adds a value to the cache. Returns true if an eviction occurred. func (c *Cache) Add(key, value interface{}) (evicted bool) { c.lock.Lock() evicted = c.lru.Add(key, value) @@ -71,8 +71,8 @@ func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { return value, ok } -// ContainsOrAdd checks if a key is in the cache without updating the -// recent-ness or deleting it for being stale, and if not, adds the value. +// ContainsOrAdd checks if a key is in the cache without updating the +// recent-ness or deleting it for being stale, and if not, adds the value. // Returns whether found and whether an eviction occurred. func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { c.lock.Lock() @@ -85,18 +85,52 @@ func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { return false, evicted } -// Remove removes the provided key from the cache. -func (c *Cache) Remove(key interface{}) { +// PeekOrAdd checks if a key is in the cache without updating the +// recent-ness or deleting it for being stale, and if not, adds the value. +// Returns whether found and whether an eviction occurred. +func (c *Cache) PeekOrAdd(key, value interface{}) (previous interface{}, ok, evicted bool) { c.lock.Lock() - c.lru.Remove(key) + defer c.lock.Unlock() + + previous, ok = c.lru.Peek(key) + if ok { + return previous, true, false + } + + evicted = c.lru.Add(key, value) + return nil, false, evicted +} + +// Remove removes the provided key from the cache. +func (c *Cache) Remove(key interface{}) (present bool) { + c.lock.Lock() + present = c.lru.Remove(key) c.lock.Unlock() + return +} + +// Resize changes the cache size. +func (c *Cache) Resize(size int) (evicted int) { + c.lock.Lock() + evicted = c.lru.Resize(size) + c.lock.Unlock() + return evicted } // RemoveOldest removes the oldest item from the cache. -func (c *Cache) RemoveOldest() { +func (c *Cache) RemoveOldest() (key interface{}, value interface{}, ok bool) { c.lock.Lock() - c.lru.RemoveOldest() + key, value, ok = c.lru.RemoveOldest() c.lock.Unlock() + return +} + +// GetOldest returns the oldest entry +func (c *Cache) GetOldest() (key interface{}, value interface{}, ok bool) { + c.lock.Lock() + key, value, ok = c.lru.GetOldest() + c.lock.Unlock() + return } // Keys returns a slice of the keys in the cache, from oldest to newest. diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go index 5673773b2..a86c8539e 100644 --- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go +++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru.go @@ -73,6 +73,9 @@ func (c *LRU) Add(key, value interface{}) (evicted bool) { func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { if ent, ok := c.items[key]; ok { c.evictList.MoveToFront(ent) + if ent.Value.(*entry) == nil { + return nil, false + } return ent.Value.(*entry).value, true } return @@ -142,6 +145,19 @@ func (c *LRU) Len() int { return c.evictList.Len() } +// Resize changes the cache size. +func (c *LRU) Resize(size int) (evicted int) { + diff := c.Len() - size + if diff < 0 { + diff = 0 + } + for i := 0; i < diff; i++ { + c.removeOldest() + } + c.size = size + return diff +} + // removeOldest removes the oldest item from the cache. func (c *LRU) removeOldest() { ent := c.evictList.Back() diff --git a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go index 74c707744..92d70934d 100644 --- a/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go +++ b/vendor/github.com/hashicorp/golang-lru/simplelru/lru_interface.go @@ -10,7 +10,7 @@ type LRUCache interface { // updates the "recently used"-ness of the key. #value, isFound Get(key interface{}) (value interface{}, ok bool) - // Check if a key exsists in cache without updating the recent-ness. + // Checks if a key exists in cache without updating the recent-ness. Contains(key interface{}) (ok bool) // Returns key's value without updating the "recently used"-ness of the key. @@ -31,6 +31,9 @@ type LRUCache interface { // Returns the number of items in the cache. Len() int - // Clear all cache entries + // Clears all cache entries. Purge() + + // Resizes cache, returning number evicted + Resize(int) int } diff --git a/vendor/modules.txt b/vendor/modules.txt index bdab239b8..0cb8ea4ab 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -208,7 +208,7 @@ github.com/hashicorp/go-discover/provider/vsphere github.com/hashicorp/go-hclog # github.com/hashicorp/go-immutable-radix v1.1.0 github.com/hashicorp/go-immutable-radix -# github.com/hashicorp/go-memdb v1.0.3 +# github.com/hashicorp/go-memdb v1.1.0 github.com/hashicorp/go-memdb # github.com/hashicorp/go-msgpack v0.5.5 github.com/hashicorp/go-msgpack/codec @@ -230,7 +230,7 @@ github.com/hashicorp/go-syslog github.com/hashicorp/go-uuid # github.com/hashicorp/go-version v1.2.0 github.com/hashicorp/go-version -# github.com/hashicorp/golang-lru v0.5.1 +# github.com/hashicorp/golang-lru v0.5.4 github.com/hashicorp/golang-lru github.com/hashicorp/golang-lru/simplelru # github.com/hashicorp/hcl v1.0.0