add locality indexer partitioning (#11016)

* convert `Roles` index to use `indexerSingle`

* split authmethod write indexer to oss and ent

* add index locality

* add locality unit tests

* move intFromBool to be available for oss

* use Bool func

* refactor `aclTokenList` to merge func
This commit is contained in:
Dhia Ayachi 2021-09-13 11:53:00 -04:00 committed by GitHub
parent 63b2cebcb3
commit 11f44dfcf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 21 deletions

View File

@ -711,13 +711,12 @@ func (s *Store) ACLTokenList(ws memdb.WatchSet, local, global bool, policy, role
// all tokens so our checks just ensure that global == local // all tokens so our checks just ensure that global == local
needLocalityFilter := false needLocalityFilter := false
if policy == "" && role == "" && methodName == "" { if policy == "" && role == "" && methodName == "" {
if global == local { if global == local {
iter, err = aclTokenListAll(tx, entMeta) iter, err = aclTokenListAll(tx, entMeta)
} else if global {
iter, err = aclTokenListGlobal(tx, entMeta)
} else { } else {
iter, err = aclTokenListLocal(tx, entMeta) iter, err = aclTokenList(tx, entMeta, local)
} }
} else if policy != "" && role == "" && methodName == "" { } else if policy != "" && role == "" && methodName == "" {
@ -1769,3 +1768,25 @@ func aclAuthMethodDeleteTxn(tx WriteTxn, idx uint64, name string, entMeta *struc
return aclAuthMethodDeleteWithMethod(tx, method, idx) return aclAuthMethodDeleteWithMethod(tx, method, idx)
} }
func aclTokenList(tx ReadTxn, entMeta *structs.EnterpriseMeta, locality bool) (memdb.ResultIterator, error) {
// TODO: accept non-pointer value
if entMeta == nil {
entMeta = structs.DefaultEnterpriseMetaInDefaultPartition()
}
// if the namespace is the wildcard that will also be handled as the local index uses
// the NamespaceMultiIndex instead of the NamespaceIndex
q := BoolQuery{
Value: locality,
EnterpriseMeta: *entMeta,
}
return tx.Get(tableACLTokens, indexLocality, q)
}
// intFromBool returns 1 if cond is true, 0 otherwise.
func intFromBool(cond bool) byte {
if cond {
return 1
}
return 0
}

View File

@ -78,14 +78,6 @@ func aclTokenListAll(tx ReadTxn, _ *structs.EnterpriseMeta) (memdb.ResultIterato
return tx.Get(tableACLTokens, "id") return tx.Get(tableACLTokens, "id")
} }
func aclTokenListLocal(tx ReadTxn, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
return tx.Get(tableACLTokens, "local", true)
}
func aclTokenListGlobal(tx ReadTxn, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
return tx.Get(tableACLTokens, "local", false)
}
func aclTokenListByPolicy(tx ReadTxn, policy string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) { func aclTokenListByPolicy(tx ReadTxn, policy string, _ *structs.EnterpriseMeta) (memdb.ResultIterator, error) {
return tx.Get(tableACLTokens, indexPolicies, Query{Value: policy}) return tx.Get(tableACLTokens, indexPolicies, Query{Value: policy})
} }

View File

@ -20,7 +20,7 @@ const (
indexPolicies = "policies" indexPolicies = "policies"
indexRoles = "roles" indexRoles = "roles"
indexAuthMethod = "authmethod" indexAuthMethod = "authmethod"
indexLocal = "local" indexLocality = "locality"
indexName = "name" indexName = "name"
) )
@ -75,17 +75,13 @@ func tokensTableSchema() *memdb.TableSchema {
writeIndex: writeIndex(indexAuthMethodFromACLToken), writeIndex: writeIndex(indexAuthMethodFromACLToken),
}, },
}, },
indexLocal: { indexLocality: {
Name: indexLocal, Name: indexLocality,
AllowMissing: false, AllowMissing: false,
Unique: false, Unique: false,
Indexer: &memdb.ConditionalIndex{ Indexer: indexerSingle{
Conditional: func(obj interface{}) (bool, error) { readIndex: readIndex(indexFromBoolQuery),
if token, ok := obj.(*structs.ACLToken); ok { writeIndex: writeIndex(indexLocalFromACLToken),
return token.Local, nil
}
return false, nil
},
}, },
}, },
"expires-global": { "expires-global": {
@ -406,3 +402,24 @@ func indexRolesFromACLToken(raw interface{}) ([][]byte, error) {
return vals, nil return vals, nil
} }
func indexFromBoolQuery(raw interface{}) ([]byte, error) {
q, ok := raw.(BoolQuery)
if !ok {
return nil, fmt.Errorf("unexpected type %T for BoolQuery index", raw)
}
var b indexBuilder
b.Bool(q.Value)
return b.Bytes(), nil
}
func indexLocalFromACLToken(raw interface{}) ([]byte, error) {
p, ok := raw.(*structs.ACLToken)
if !ok {
return nil, fmt.Errorf("unexpected type %T for structs.ACLPolicy index", raw)
}
var b indexBuilder
b.Bool(p.Local)
return b.Bytes(), nil
}

View File

@ -133,3 +133,7 @@ func (b *indexBuilder) Raw(v []byte) {
func (b *indexBuilder) Bytes() []byte { func (b *indexBuilder) Bytes() []byte {
return (*bytes.Buffer)(b).Bytes() return (*bytes.Buffer)(b).Bytes()
} }
func (b *indexBuilder) Bool(v bool) {
b.Raw([]byte{intFromBool(v)})
}

View File

@ -96,6 +96,18 @@ type BoolQuery struct {
structs.EnterpriseMeta structs.EnterpriseMeta
} }
// NamespaceOrDefault exists because structs.EnterpriseMeta uses a pointer
// receiver for this method. Remove once that is fixed.
func (q BoolQuery) NamespaceOrDefault() string {
return q.EnterpriseMeta.NamespaceOrDefault()
}
// PartitionOrDefault exists because structs.EnterpriseMeta uses a pointer
// receiver for this method. Remove once that is fixed.
func (q BoolQuery) PartitionOrDefault() string {
return q.EnterpriseMeta.PartitionOrDefault()
}
// KeyValueQuery is a type used to query for both a key and a value that may // KeyValueQuery is a type used to query for both a key and a value that may
// include an enterprise identifier. // include an enterprise identifier.
type KeyValueQuery struct { type KeyValueQuery struct {