Matt Keeler 6c4b83c119
Allow reuse of cache indexes (#20562)
Previously calling `index.New` would return an object with the index information such as the Indexer, whether it was required, and the name of the index as well as a radix tree to store indexed data.

Now the main `Index` type doesn’t contain the radix tree for indexed data. Instead the `IndexedData` method can be used to combine the main `Index` with a radix tree in the `IndexedData` structure.

The cache still only allows configuring the `Index` type and will invoke the `IndexedData` method on the provided indexes to get the structure that the cache can use for actual data management.

All of this makes it now safe to reuse the `index.Index` types.
2024-02-09 13:00:21 -05:00

97 lines
2.0 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package index
import (
"github.com/hashicorp/consul/proto-public/pbresource"
iradix "github.com/hashicorp/go-immutable-radix/v2"
)
type Index struct {
name string
required bool
indexer MultiIndexer
}
func New(name string, i Indexer, opts ...IndexOption) *Index {
if name == "" {
panic("all indexers must have a non-empty name")
}
if i == nil {
panic("no indexer was supplied when creating a new cache Index")
}
var multiIndexer MultiIndexer
switch v := i.(type) {
case SingleIndexer:
multiIndexer = singleIndexWrapper{indexer: v}
case MultiIndexer:
multiIndexer = v
default:
panic("The Indexer must also implement one of the SingleIndexer or MultiIndexer interfaces")
}
idx := &Index{
name: name,
indexer: multiIndexer,
}
for _, opt := range opts {
opt(idx)
}
return idx
}
func (i *Index) Name() string {
return i.name
}
// IndexedData combines the Index with an radix tree for index and resource storage.
func (i *Index) IndexedData() *IndexedData {
return &IndexedData{
Index: i,
tree: iradix.New[[]*pbresource.Resource](),
}
}
// IndexedData is a wrapper around an Index and an radix tree for index and resource storage.
type IndexedData struct {
*Index
tree *iradix.Tree[[]*pbresource.Resource]
}
func (i *IndexedData) Txn() Txn {
return &txn{
inner: i.tree.Txn(),
index: i,
dirty: false,
}
}
func (i *Index) fromArgs(args ...any) ([]byte, error) {
return i.indexer.FromArgs(args...)
}
func (i *Index) fromResource(r *pbresource.Resource) (bool, [][]byte, error) {
return i.indexer.FromResource(r)
}
type singleIndexWrapper struct {
indexer SingleIndexer
}
func (s singleIndexWrapper) FromArgs(args ...any) ([]byte, error) {
return s.indexer.FromArgs(args...)
}
func (s singleIndexWrapper) FromResource(r *pbresource.Resource) (bool, [][]byte, error) {
indexed, val, err := s.indexer.FromResource(r)
if err != nil || !indexed {
return false, nil, err
}
return true, [][]byte{val}, nil
}