From 12da4521366bb4c22c6f0b430c7a4642a4561e98 Mon Sep 17 00:00:00 2001 From: Kyle Havlovitz Date: Mon, 9 Jan 2017 11:23:09 -0800 Subject: [PATCH] vendor: Update go-memdb dependency --- .../github.com/hashicorp/go-memdb/README.md | 2 +- vendor/github.com/hashicorp/go-memdb/index.go | 175 +++++++++++++++++- .../github.com/hashicorp/go-memdb/schema.go | 9 + vendor/github.com/hashicorp/go-memdb/txn.go | 88 ++++++--- vendor/vendor.json | 6 +- 5 files changed, 250 insertions(+), 30 deletions(-) diff --git a/vendor/github.com/hashicorp/go-memdb/README.md b/vendor/github.com/hashicorp/go-memdb/README.md index 203a0af14..675044beb 100644 --- a/vendor/github.com/hashicorp/go-memdb/README.md +++ b/vendor/github.com/hashicorp/go-memdb/README.md @@ -19,7 +19,7 @@ The database provides the following: * Rich Indexing - Tables can support any number of indexes, which can be simple like a single field index, or more advanced compound field indexes. Certain types like - UUID can be efficiently compressed from strings into byte indexes for reduces + UUID can be efficiently compressed from strings into byte indexes for reduced storage requirements. For the underlying immutable radix trees, see [go-immutable-radix](https://github.com/hashicorp/go-immutable-radix). diff --git a/vendor/github.com/hashicorp/go-memdb/index.go b/vendor/github.com/hashicorp/go-memdb/index.go index 7237f33e2..17aa02699 100644 --- a/vendor/github.com/hashicorp/go-memdb/index.go +++ b/vendor/github.com/hashicorp/go-memdb/index.go @@ -9,15 +9,27 @@ import ( // Indexer is an interface used for defining indexes type Indexer interface { - // FromObject is used to extract an index value from an - // object or to indicate that the index value is missing. - FromObject(raw interface{}) (bool, []byte, error) - // ExactFromArgs is used to build an exact index lookup // based on arguments FromArgs(args ...interface{}) ([]byte, error) } +// SingleIndexer is an interface used for defining indexes +// generating a single entry per object +type SingleIndexer interface { + // FromObject is used to extract an index value from an + // object or to indicate that the index value is missing. + FromObject(raw interface{}) (bool, []byte, error) +} + +// MultiIndexer is an interface used for defining indexes +// generating multiple entries per object +type MultiIndexer interface { + // FromObject is used to extract index values from an + // object or to indicate that the index value is missing. + FromObject(raw interface{}) (bool, [][]byte, error) +} + // PrefixIndexer can optionally be implemented for any // indexes that support prefix based iteration. This may // not apply to all indexes. @@ -88,6 +100,155 @@ func (s *StringFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { return val, nil } +// StringSliceFieldIndex is used to extract a field from an object +// using reflection and builds an index on that field. +type StringSliceFieldIndex struct { + Field string + Lowercase bool +} + +func (s *StringSliceFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(s.Field) + if !fv.IsValid() { + return false, nil, + fmt.Errorf("field '%s' for %#v is invalid", s.Field, obj) + } + + if fv.Kind() != reflect.Slice || fv.Type().Elem().Kind() != reflect.String { + return false, nil, fmt.Errorf("field '%s' is not a string slice", s.Field) + } + + length := fv.Len() + vals := make([][]byte, 0, length) + for i := 0; i < fv.Len(); i++ { + val := fv.Index(i).String() + if val == "" { + continue + } + + if s.Lowercase { + val = strings.ToLower(val) + } + + // Add the null character as a terminator + val += "\x00" + vals = append(vals, []byte(val)) + } + if len(vals) == 0 { + return false, nil, nil + } + return true, vals, nil +} + +func (s *StringSliceFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) != 1 { + return nil, fmt.Errorf("must provide only a single argument") + } + arg, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[0]) + } + if s.Lowercase { + arg = strings.ToLower(arg) + } + // Add the null character as a terminator + arg += "\x00" + return []byte(arg), nil +} + +func (s *StringSliceFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error) { + val, err := s.FromArgs(args...) + if err != nil { + return nil, err + } + + // Strip the null terminator, the rest is a prefix + n := len(val) + if n > 0 { + return val[:n-1], nil + } + return val, nil +} + +// StringMapFieldIndex is used to extract a field of type map[string]string +// from an object using reflection and builds an index on that field. +type StringMapFieldIndex struct { + Field string + Lowercase bool +} + +var MapType = reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf("")).Kind() + +func (s *StringMapFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error) { + v := reflect.ValueOf(obj) + v = reflect.Indirect(v) // Dereference the pointer if any + + fv := v.FieldByName(s.Field) + if !fv.IsValid() { + return false, nil, fmt.Errorf("field '%s' for %#v is invalid", s.Field, obj) + } + + if fv.Kind() != MapType { + return false, nil, fmt.Errorf("field '%s' is not a map[string]string", s.Field) + } + + length := fv.Len() + vals := make([][]byte, 0, length) + for _, key := range fv.MapKeys() { + k := key.String() + if k == "" { + continue + } + val := fv.MapIndex(key).String() + + if s.Lowercase { + k = strings.ToLower(k) + val = strings.ToLower(val) + } + + // Add the null character as a terminator + k += "\x00" + val + "\x00" + + vals = append(vals, []byte(k)) + } + if len(vals) == 0 { + return false, nil, nil + } + return true, vals, nil +} + +func (s *StringMapFieldIndex) FromArgs(args ...interface{}) ([]byte, error) { + if len(args) > 2 || len(args) == 0 { + return nil, fmt.Errorf("must provide one or two arguments") + } + key, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[0]) + } + if s.Lowercase { + key = strings.ToLower(key) + } + // Add the null character as a terminator + key += "\x00" + + if len(args) == 2 { + val, ok := args[1].(string) + if !ok { + return nil, fmt.Errorf("argument must be a string: %#v", args[1]) + } + if s.Lowercase { + val = strings.ToLower(val) + } + // Add the null character as a terminator + key += val + "\x00" + } + + return []byte(key), nil +} + // UUIDFieldIndex is used to extract a field from an object // using reflection and builds an index on that field by treating // it as a UUID. This is an optimization to using a StringFieldIndex @@ -270,7 +431,11 @@ type CompoundIndex struct { func (c *CompoundIndex) FromObject(raw interface{}) (bool, []byte, error) { var out []byte - for i, idx := range c.Indexes { + for i, idxRaw := range c.Indexes { + idx, ok := idxRaw.(SingleIndexer) + if !ok { + return false, nil, fmt.Errorf("sub-index %d error: %s", i, "sub-index must be a SingleIndexer") + } ok, val, err := idx.FromObject(raw) if err != nil { return false, nil, fmt.Errorf("sub-index %d error: %v", i, err) diff --git a/vendor/github.com/hashicorp/go-memdb/schema.go b/vendor/github.com/hashicorp/go-memdb/schema.go index 2b8ffb476..26d0fcb99 100644 --- a/vendor/github.com/hashicorp/go-memdb/schema.go +++ b/vendor/github.com/hashicorp/go-memdb/schema.go @@ -46,6 +46,9 @@ func (s *TableSchema) Validate() error { if !s.Indexes["id"].Unique { return fmt.Errorf("id index must be unique") } + if _, ok := s.Indexes["id"].Indexer.(SingleIndexer); !ok { + return fmt.Errorf("id index must be a SingleIndexer") + } for name, index := range s.Indexes { if name != index.Name { return fmt.Errorf("index name mis-match for '%s'", name) @@ -72,5 +75,11 @@ func (s *IndexSchema) Validate() error { if s.Indexer == nil { return fmt.Errorf("missing index function for '%s'", s.Name) } + switch s.Indexer.(type) { + case SingleIndexer: + case MultiIndexer: + default: + return fmt.Errorf("indexer for '%s' must be a SingleIndexer or MultiIndexer", s.Name) + } return nil } diff --git a/vendor/github.com/hashicorp/go-memdb/txn.go b/vendor/github.com/hashicorp/go-memdb/txn.go index 6228677da..fa73c9a3f 100644 --- a/vendor/github.com/hashicorp/go-memdb/txn.go +++ b/vendor/github.com/hashicorp/go-memdb/txn.go @@ -148,7 +148,8 @@ func (txn *Txn) Insert(table string, obj interface{}) error { // Get the primary ID of the object idSchema := tableSchema.Indexes[id] - ok, idVal, err := idSchema.Indexer.FromObject(obj) + idIndexer := idSchema.Indexer.(SingleIndexer) + ok, idVal, err := idIndexer.FromObject(obj) if err != nil { return fmt.Errorf("failed to build primary index: %v", err) } @@ -167,7 +168,19 @@ func (txn *Txn) Insert(table string, obj interface{}) error { indexTxn := txn.writableIndex(table, name) // Determine the new index value - ok, val, err := indexSchema.Indexer.FromObject(obj) + var ( + ok bool + vals [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var val []byte + ok, val, err = indexer.FromObject(obj) + vals = [][]byte{val} + case MultiIndexer: + ok, vals, err = indexer.FromObject(obj) + } if err != nil { return fmt.Errorf("failed to build index '%s': %v", name, err) } @@ -176,28 +189,44 @@ func (txn *Txn) Insert(table string, obj interface{}) error { // This is done by appending the primary key which must // be unique anyways. if ok && !indexSchema.Unique { - val = append(val, idVal...) + for i := range vals { + vals[i] = append(vals[i], idVal...) + } } // Handle the update by deleting from the index first if update { - okExist, valExist, err := indexSchema.Indexer.FromObject(existing) + var ( + okExist bool + valsExist [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var valExist []byte + okExist, valExist, err = indexer.FromObject(existing) + valsExist = [][]byte{valExist} + case MultiIndexer: + okExist, valsExist, err = indexer.FromObject(existing) + } if err != nil { return fmt.Errorf("failed to build index '%s': %v", name, err) } if okExist { - // Handle non-unique index by computing a unique index. - // This is done by appending the primary key which must - // be unique anyways. - if !indexSchema.Unique { - valExist = append(valExist, idVal...) - } + for i, valExist := range valsExist { + // Handle non-unique index by computing a unique index. + // This is done by appending the primary key which must + // be unique anyways. + if !indexSchema.Unique { + valExist = append(valExist, idVal...) + } - // If we are writing to the same index with the same value, - // we can avoid the delete as the insert will overwrite the - // value anyways. - if !bytes.Equal(valExist, val) { - indexTxn.Delete(valExist) + // If we are writing to the same index with the same value, + // we can avoid the delete as the insert will overwrite the + // value anyways. + if i >= len(vals) || !bytes.Equal(valExist, vals[i]) { + indexTxn.Delete(valExist) + } } } } @@ -213,7 +242,9 @@ func (txn *Txn) Insert(table string, obj interface{}) error { } // Update the value of the index - indexTxn.Insert(val, obj) + for _, val := range vals { + indexTxn.Insert(val, obj) + } } return nil } @@ -233,7 +264,8 @@ func (txn *Txn) Delete(table string, obj interface{}) error { // Get the primary ID of the object idSchema := tableSchema.Indexes[id] - ok, idVal, err := idSchema.Indexer.FromObject(obj) + idIndexer := idSchema.Indexer.(SingleIndexer) + ok, idVal, err := idIndexer.FromObject(obj) if err != nil { return fmt.Errorf("failed to build primary index: %v", err) } @@ -253,7 +285,19 @@ func (txn *Txn) Delete(table string, obj interface{}) error { indexTxn := txn.writableIndex(table, name) // Handle the update by deleting from the index first - ok, val, err := indexSchema.Indexer.FromObject(existing) + var ( + ok bool + vals [][]byte + err error + ) + switch indexer := indexSchema.Indexer.(type) { + case SingleIndexer: + var val []byte + ok, val, err = indexer.FromObject(existing) + vals = [][]byte{val} + case MultiIndexer: + ok, vals, err = indexer.FromObject(existing) + } if err != nil { return fmt.Errorf("failed to build index '%s': %v", name, err) } @@ -261,10 +305,12 @@ func (txn *Txn) Delete(table string, obj interface{}) error { // Handle non-unique index by computing a unique index. // This is done by appending the primary key which must // be unique anyways. - if !indexSchema.Unique { - val = append(val, idVal...) + for _, val := range vals { + if !indexSchema.Unique { + val = append(val, idVal...) + } + indexTxn.Delete(val) } - indexTxn.Delete(val) } } return nil diff --git a/vendor/vendor.json b/vendor/vendor.json index b130ac271..668875419 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -396,10 +396,10 @@ "revisionTime": "2016-06-09T02:05:29Z" }, { - "checksumSHA1": "/V57CyN7x2NUlHoOzVL5GgGXX84=", + "checksumSHA1": "ZpTDFeRvXFwIvSHRD8eDYHxaj4Y=", "path": "github.com/hashicorp/go-memdb", - "revision": "98f52f52d7a476958fa9da671354d270c50661a7", - "revisionTime": "2016-03-01T23:01:42Z" + "revision": "d2d2b77acab85aa635614ac17ea865969f56009e", + "revisionTime": "2017-01-07T16:22:14Z" }, { "checksumSHA1": "TNlVzNR1OaajcNi3CbQ3bGbaLGU=",