mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-21 06:31:07 +02:00
* Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License. Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUS-1.1 * Fix test that expected exact offset on hcl file --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com> Co-authored-by: Sarah Thompson <sthompson@hashicorp.com> Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
244 lines
5.5 KiB
Go
244 lines
5.5 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package cachememdb
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync/atomic"
|
|
|
|
memdb "github.com/hashicorp/go-memdb"
|
|
)
|
|
|
|
const (
|
|
tableNameIndexer = "indexer"
|
|
)
|
|
|
|
// CacheMemDB is the underlying cache database for storing indexes.
|
|
type CacheMemDB struct {
|
|
db *atomic.Value
|
|
}
|
|
|
|
// New creates a new instance of CacheMemDB.
|
|
func New() (*CacheMemDB, error) {
|
|
db, err := newDB()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c := &CacheMemDB{
|
|
db: new(atomic.Value),
|
|
}
|
|
c.db.Store(db)
|
|
|
|
return c, nil
|
|
}
|
|
|
|
func newDB() (*memdb.MemDB, error) {
|
|
cacheSchema := &memdb.DBSchema{
|
|
Tables: map[string]*memdb.TableSchema{
|
|
tableNameIndexer: {
|
|
Name: tableNameIndexer,
|
|
Indexes: map[string]*memdb.IndexSchema{
|
|
// This index enables fetching the cached item based on the
|
|
// identifier of the index.
|
|
IndexNameID: {
|
|
Name: IndexNameID,
|
|
Unique: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "ID",
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache for
|
|
// a given request path, in a given namespace.
|
|
IndexNameRequestPath: {
|
|
Name: IndexNameRequestPath,
|
|
Unique: false,
|
|
Indexer: &memdb.CompoundIndex{
|
|
Indexes: []memdb.Indexer{
|
|
&memdb.StringFieldIndex{
|
|
Field: "Namespace",
|
|
},
|
|
&memdb.StringFieldIndex{
|
|
Field: "RequestPath",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache
|
|
// belonging to the leases of a given token.
|
|
IndexNameLeaseToken: {
|
|
Name: IndexNameLeaseToken,
|
|
Unique: false,
|
|
AllowMissing: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "LeaseToken",
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache
|
|
// that are tied to the given token, regardless of the
|
|
// entries belonging to the token or belonging to the
|
|
// lease.
|
|
IndexNameToken: {
|
|
Name: IndexNameToken,
|
|
Unique: true,
|
|
AllowMissing: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Token",
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache for
|
|
// the given parent token.
|
|
IndexNameTokenParent: {
|
|
Name: IndexNameTokenParent,
|
|
Unique: false,
|
|
AllowMissing: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "TokenParent",
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache for
|
|
// the given accessor.
|
|
IndexNameTokenAccessor: {
|
|
Name: IndexNameTokenAccessor,
|
|
Unique: true,
|
|
AllowMissing: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "TokenAccessor",
|
|
},
|
|
},
|
|
// This index enables fetching all the entries in cache for
|
|
// the given lease identifier.
|
|
IndexNameLease: {
|
|
Name: IndexNameLease,
|
|
Unique: true,
|
|
AllowMissing: true,
|
|
Indexer: &memdb.StringFieldIndex{
|
|
Field: "Lease",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
db, err := memdb.NewMemDB(cacheSchema)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return db, nil
|
|
}
|
|
|
|
// Get returns the index based on the indexer and the index values provided.
|
|
func (c *CacheMemDB) Get(indexName string, indexValues ...interface{}) (*Index, error) {
|
|
if !validIndexName(indexName) {
|
|
return nil, fmt.Errorf("invalid index name %q", indexName)
|
|
}
|
|
|
|
txn := c.db.Load().(*memdb.MemDB).Txn(false)
|
|
|
|
raw, err := txn.First(tableNameIndexer, indexName, indexValues...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if raw == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
index, ok := raw.(*Index)
|
|
if !ok {
|
|
return nil, errors.New("unable to parse index value from the cache")
|
|
}
|
|
|
|
return index, nil
|
|
}
|
|
|
|
// Set stores the index into the cache.
|
|
func (c *CacheMemDB) Set(index *Index) error {
|
|
if index == nil {
|
|
return errors.New("nil index provided")
|
|
}
|
|
|
|
txn := c.db.Load().(*memdb.MemDB).Txn(true)
|
|
defer txn.Abort()
|
|
|
|
if err := txn.Insert(tableNameIndexer, index); err != nil {
|
|
return fmt.Errorf("unable to insert index into cache: %v", err)
|
|
}
|
|
|
|
txn.Commit()
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetByPrefix returns all the cached indexes based on the index name and the
|
|
// value prefix.
|
|
func (c *CacheMemDB) GetByPrefix(indexName string, indexValues ...interface{}) ([]*Index, error) {
|
|
if !validIndexName(indexName) {
|
|
return nil, fmt.Errorf("invalid index name %q", indexName)
|
|
}
|
|
|
|
indexName = indexName + "_prefix"
|
|
|
|
// Get all the objects
|
|
txn := c.db.Load().(*memdb.MemDB).Txn(false)
|
|
|
|
iter, err := txn.Get(tableNameIndexer, indexName, indexValues...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var indexes []*Index
|
|
for {
|
|
obj := iter.Next()
|
|
if obj == nil {
|
|
break
|
|
}
|
|
index, ok := obj.(*Index)
|
|
if !ok {
|
|
return nil, fmt.Errorf("failed to cast cached index")
|
|
}
|
|
|
|
indexes = append(indexes, index)
|
|
}
|
|
|
|
return indexes, nil
|
|
}
|
|
|
|
// Evict removes an index from the cache based on index name and value.
|
|
func (c *CacheMemDB) Evict(indexName string, indexValues ...interface{}) error {
|
|
index, err := c.Get(indexName, indexValues...)
|
|
if err != nil {
|
|
return fmt.Errorf("unable to fetch index on cache deletion: %v", err)
|
|
}
|
|
|
|
if index == nil {
|
|
return nil
|
|
}
|
|
|
|
txn := c.db.Load().(*memdb.MemDB).Txn(true)
|
|
defer txn.Abort()
|
|
|
|
if err := txn.Delete(tableNameIndexer, index); err != nil {
|
|
return fmt.Errorf("unable to delete index from cache: %v", err)
|
|
}
|
|
|
|
txn.Commit()
|
|
|
|
return nil
|
|
}
|
|
|
|
// Flush resets the underlying cache object.
|
|
func (c *CacheMemDB) Flush() error {
|
|
newDB, err := newDB()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.db.Store(newDB)
|
|
|
|
return nil
|
|
}
|