github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/nomad/state/indexer/indexer.go (about)

     1  package indexer
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"time"
     9  
    10  	"github.com/hashicorp/go-memdb"
    11  )
    12  
    13  var (
    14  	// Ensure the required memdb interfaces are met at compile time.
    15  	_ memdb.Indexer       = SingleIndexer{}
    16  	_ memdb.SingleIndexer = SingleIndexer{}
    17  )
    18  
    19  // SingleIndexer implements both memdb.Indexer and memdb.SingleIndexer. It may
    20  // be used in a memdb.IndexSchema to specify functions that generate the index
    21  // value for memdb.Txn operations.
    22  type SingleIndexer struct {
    23  
    24  	// readIndex is used by memdb for Txn.Get, Txn.First, and other operations
    25  	// that read data.
    26  	ReadIndex
    27  
    28  	// writeIndex is used by memdb for Txn.Insert, Txn.Delete, and other
    29  	// operations that write data to the index.
    30  	WriteIndex
    31  }
    32  
    33  // ReadIndex implements memdb.Indexer. It exists so that a function can be used
    34  // to provide the interface.
    35  //
    36  // Unlike memdb.Indexer, a readIndex function accepts only a single argument. To
    37  // generate an index from multiple values, use a struct type with multiple fields.
    38  type ReadIndex func(arg any) ([]byte, error)
    39  
    40  func (f ReadIndex) FromArgs(args ...interface{}) ([]byte, error) {
    41  	if len(args) != 1 {
    42  		return nil, fmt.Errorf("index supports only a single arg")
    43  	}
    44  	return f(args[0])
    45  }
    46  
    47  var ErrMissingValueForIndex = fmt.Errorf("object is missing a value for this index")
    48  
    49  // WriteIndex implements memdb.SingleIndexer. It exists so that a function
    50  // can be used to provide this interface.
    51  //
    52  // Instead of a bool return value, writeIndex expects errMissingValueForIndex to
    53  // indicate that an index could not be build for the object. It will translate
    54  // this error into a false value to satisfy the memdb.SingleIndexer interface.
    55  type WriteIndex func(raw any) ([]byte, error)
    56  
    57  func (f WriteIndex) FromObject(raw any) (bool, []byte, error) {
    58  	v, err := f(raw)
    59  	if errors.Is(err, ErrMissingValueForIndex) {
    60  		return false, nil, nil
    61  	}
    62  	return err == nil, v, err
    63  }
    64  
    65  // IndexBuilder is a buffer used to construct memdb index values.
    66  type IndexBuilder bytes.Buffer
    67  
    68  // Bytes returns the stored IndexBuilder value as a byte array.
    69  func (b *IndexBuilder) Bytes() []byte { return (*bytes.Buffer)(b).Bytes() }
    70  
    71  // Time is used to write the passed time into the IndexBuilder for use as a
    72  // memdb index value.
    73  func (b *IndexBuilder) Time(t time.Time) {
    74  	val := t.Unix()
    75  	buf := make([]byte, 8)
    76  	binary.BigEndian.PutUint64(buf, uint64(val))
    77  	(*bytes.Buffer)(b).Write(buf)
    78  }