From 650ac62098434b9a9d8adc2b80aef7fec3dcfc5b Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 9 Feb 2021 12:37:57 -0500 Subject: [PATCH] state: convert config-entries table to new indexer pattern Using functional indexes to isolate enterprise differentiation and remove reflection. --- agent/consul/state/config_entry.go | 14 +++++--- agent/consul/state/config_entry_oss.go | 36 ++++++++++++++----- agent/consul/state/config_entry_schema.go | 18 ++++------ .../testdata/TestStateStoreSchema.golden | 2 +- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/agent/consul/state/config_entry.go b/agent/consul/state/config_entry.go index 7d58c55375..ac91efec52 100644 --- a/agent/consul/state/config_entry.go +++ b/agent/consul/state/config_entry.go @@ -106,7 +106,7 @@ func configEntryTxn(tx ReadTxn, ws memdb.WatchSet, kind, name string, entMeta *s idx := maxIndexTxn(tx, tableConfigEntries) // Get the existing config entry. - watchCh, existing, err := firstWatchConfigEntryWithTxn(tx, kind, name, entMeta) + watchCh, existing, err := tx.FirstWatch(tableConfigEntries, "id", NewConfigEntryKindName(kind, name, entMeta)) if err != nil { return 0, nil, fmt.Errorf("failed config entry lookup: %s", err) } @@ -175,7 +175,7 @@ func (s *Store) EnsureConfigEntry(idx uint64, conf structs.ConfigEntry) error { // ensureConfigEntryTxn upserts a config entry inside of a transaction. func ensureConfigEntryTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry) error { // Check for existing configuration. - existing, err := firstConfigEntryWithTxn(tx, conf.GetKind(), conf.GetName(), conf.GetEnterpriseMeta()) + existing, err := tx.First(tableConfigEntries, indexID, newConfigEntryQuery(conf)) if err != nil { return fmt.Errorf("failed configuration lookup: %s", err) } @@ -214,7 +214,7 @@ func (s *Store) EnsureConfigEntryCAS(idx, cidx uint64, conf structs.ConfigEntry) defer tx.Abort() // Check for existing configuration. - existing, err := firstConfigEntryWithTxn(tx, conf.GetKind(), conf.GetName(), conf.GetEnterpriseMeta()) + existing, err := tx.First(tableConfigEntries, indexID, newConfigEntryQuery(conf)) if err != nil { return false, fmt.Errorf("failed configuration lookup: %s", err) } @@ -254,9 +254,9 @@ func (s *Store) DeleteConfigEntry(idx uint64, kind, name string, entMeta *struct return tx.Commit() } +// TODO: accept structs.ConfigEntry instead of individual fields func deleteConfigEntryTxn(tx WriteTxn, idx uint64, kind, name string, entMeta *structs.EnterpriseMeta) error { - // Try to retrieve the existing config entry. - existing, err := firstConfigEntryWithTxn(tx, kind, name, entMeta) + existing, err := tx.First(tableConfigEntries, indexID, NewConfigEntryKindName(kind, name, entMeta)) if err != nil { return fmt.Errorf("failed config entry lookup: %s", err) } @@ -1242,3 +1242,7 @@ func NewConfigEntryKindName(kind, name string, entMeta *structs.EnterpriseMeta) ret.EnterpriseMeta.Normalize() return ret } + +func newConfigEntryQuery(c structs.ConfigEntry) ConfigEntryKindName { + return NewConfigEntryKindName(c.GetKind(), c.GetName(), c.GetEnterpriseMeta()) +} diff --git a/agent/consul/state/config_entry_oss.go b/agent/consul/state/config_entry_oss.go index f58913b76c..9ef1d374b2 100644 --- a/agent/consul/state/config_entry_oss.go +++ b/agent/consul/state/config_entry_oss.go @@ -3,22 +3,40 @@ package state import ( + "fmt" + "strings" + memdb "github.com/hashicorp/go-memdb" "github.com/hashicorp/consul/agent/structs" ) -func firstConfigEntryWithTxn(tx ReadTxn, kind, name string, _ *structs.EnterpriseMeta) (interface{}, error) { - return tx.First(tableConfigEntries, "id", kind, name) +func indexFromConfigEntryKindName(arg interface{}) ([]byte, error) { + n, ok := arg.(ConfigEntryKindName) + if !ok { + return nil, fmt.Errorf("invalid type for ConfigEntryKindName query: %T", arg) + } + + var b indexBuilder + b.String(strings.ToLower(n.Kind)) + b.String(strings.ToLower(n.Name)) + return b.Bytes(), nil } -func firstWatchConfigEntryWithTxn( - tx ReadTxn, - kind string, - name string, - _ *structs.EnterpriseMeta, -) (<-chan struct{}, interface{}, error) { - return tx.FirstWatch(tableConfigEntries, "id", kind, name) +func indexFromConfigEntry(raw interface{}) ([]byte, error) { + c, ok := raw.(structs.ConfigEntry) + if !ok { + return nil, fmt.Errorf("type must be structs.ConfigEntry: %T", raw) + } + + if c.GetName() == "" || c.GetKind() == "" { + return nil, errMissingValueForIndex + } + + var b indexBuilder + b.String(strings.ToLower(c.GetKind())) + b.String(strings.ToLower(c.GetName())) + return b.Bytes(), nil } func validateConfigEntryEnterprise(_ ReadTxn, _ structs.ConfigEntry) error { diff --git a/agent/consul/state/config_entry_schema.go b/agent/consul/state/config_entry_schema.go index 6e349a6155..11ad01e4d1 100644 --- a/agent/consul/state/config_entry_schema.go +++ b/agent/consul/state/config_entry_schema.go @@ -1,6 +1,8 @@ package state -import "github.com/hashicorp/go-memdb" +import ( + "github.com/hashicorp/go-memdb" +) const ( tableConfigEntries = "config-entries" @@ -20,17 +22,9 @@ func configTableSchema() *memdb.TableSchema { Name: indexID, AllowMissing: false, Unique: true, - Indexer: &memdb.CompoundIndex{ - Indexes: []memdb.Indexer{ - &memdb.StringFieldIndex{ - Field: "Kind", - Lowercase: true, - }, - &memdb.StringFieldIndex{ - Field: "Name", - Lowercase: true, - }, - }, + Indexer: indexerSingle{ + readIndex: readIndex(indexFromConfigEntryKindName), + writeIndex: writeIndex(indexFromConfigEntry), }, }, indexKind: { diff --git a/agent/consul/state/testdata/TestStateStoreSchema.golden b/agent/consul/state/testdata/TestStateStoreSchema.golden index 04510ece71..83f59d8b61 100644 --- a/agent/consul/state/testdata/TestStateStoreSchema.golden +++ b/agent/consul/state/testdata/TestStateStoreSchema.golden @@ -60,7 +60,7 @@ table=checks table=config-entries index=id unique - indexer=github.com/hashicorp/go-memdb.CompoundIndex Indexes=[github.com/hashicorp/go-memdb.StringFieldIndex Field=Kind Lowercase=true, github.com/hashicorp/go-memdb.StringFieldIndex Field=Name Lowercase=true] AllowMissing=false + indexer=github.com/hashicorp/consul/agent/consul/state.indexerSingle readIndex=github.com/hashicorp/consul/agent/consul/state.indexFromConfigEntryKindName writeIndex=github.com/hashicorp/consul/agent/consul/state.indexFromConfigEntry index=intention-legacy-id unique allow-missing indexer=github.com/hashicorp/consul/agent/consul/state.ServiceIntentionLegacyIDIndex uuidFieldIndex={} index=intention-source allow-missing