memdb

package module
v1.3.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2022 License: MPL-2.0 Imports: 14 Imported by: 1,089

README

go-memdb CircleCI

Provides the memdb package that implements a simple in-memory database built on immutable radix trees. The database provides Atomicity, Consistency and Isolation from ACID. Being that it is in-memory, it does not provide durability. The database is instantiated with a schema that specifies the tables and indices that exist and allows transactions to be executed.

The database provides the following:

  • Multi-Version Concurrency Control (MVCC) - By leveraging immutable radix trees the database is able to support any number of concurrent readers without locking, and allows a writer to make progress.

  • Transaction Support - The database allows for rich transactions, in which multiple objects are inserted, updated or deleted. The transactions can span multiple tables, and are applied atomically. The database provides atomicity and isolation in ACID terminology, such that until commit the updates are not visible.

  • Rich Indexing - Tables can support any number of indexes, which can be simple like a single field index, or more advanced compound field indexes. Certain types like UUID can be efficiently compressed from strings into byte indexes for reduced storage requirements.

  • Watches - Callers can populate a watch set as part of a query, which can be used to detect when a modification has been made to the database which affects the query results. This lets callers easily watch for changes in the database in a very general way.

For the underlying immutable radix trees, see go-immutable-radix.

Documentation

The full documentation is available on Godoc.

Example

Below is a simple example of usage

// Create a sample struct
type Person struct {
	Email string
	Name  string
	Age   int
}

// Create the DB schema
schema := &memdb.DBSchema{
	Tables: map[string]*memdb.TableSchema{
		"person": &memdb.TableSchema{
			Name: "person",
			Indexes: map[string]*memdb.IndexSchema{
				"id": &memdb.IndexSchema{
					Name:    "id",
					Unique:  true,
					Indexer: &memdb.StringFieldIndex{Field: "Email"},
				},
				"age": &memdb.IndexSchema{
					Name:    "age",
					Unique:  false,
					Indexer: &memdb.IntFieldIndex{Field: "Age"},
				},
			},
		},
	},
}

// Create a new data base
db, err := memdb.NewMemDB(schema)
if err != nil {
	panic(err)
}

// Create a write transaction
txn := db.Txn(true)

// Insert some people
people := []*Person{
	&Person{"joe@aol.com", "Joe", 30},
	&Person{"lucy@aol.com", "Lucy", 35},
	&Person{"tariq@aol.com", "Tariq", 21},
	&Person{"dorothy@aol.com", "Dorothy", 53},
}
for _, p := range people {
	if err := txn.Insert("person", p); err != nil {
		panic(err)
	}
}

// Commit the transaction
txn.Commit()

// Create read-only transaction
txn = db.Txn(false)
defer txn.Abort()

// Lookup by email
raw, err := txn.First("person", "id", "joe@aol.com")
if err != nil {
	panic(err)
}

// Say hi!
fmt.Printf("Hello %s!\n", raw.(*Person).Name)

// List all the people
it, err := txn.Get("person", "id")
if err != nil {
	panic(err)
}

fmt.Println("All the people:")
for obj := it.Next(); obj != nil; obj = it.Next() {
	p := obj.(*Person)
	fmt.Printf("  %s\n", p.Name)
}

// Range scan over people with ages between 25 and 35 inclusive
it, err = txn.LowerBound("person", "age", 25)
if err != nil {
	panic(err)
}

fmt.Println("People aged 25 - 35:")
for obj := it.Next(); obj != nil; obj = it.Next() {
	p := obj.(*Person)
	if p.Age > 35 {
		break
	}
	fmt.Printf("  %s is aged %d\n", p.Name, p.Age)
}
// Output:
// Hello Joe!
// All the people:
//   Dorothy
//   Joe
//   Lucy
//   Tariq
// People aged 25 - 35:
//   Joe is aged 30
//   Lucy is aged 35

Documentation

Overview

Package memdb provides an in-memory database that supports transactions and MVCC.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotFound is returned when the requested item is not found
	ErrNotFound = fmt.Errorf("not found")
)
View Source
var MapType = reflect.MapOf(reflect.TypeOf(""), reflect.TypeOf("")).Kind()

Functions

func IsIntType added in v1.0.1

func IsIntType(k reflect.Kind) (size int, okay bool)

IsIntType returns whether the passed type is a type of int and the number of bytes needed to encode the type.

func IsUintType

func IsUintType(k reflect.Kind) (size int, okay bool)

IsUintType returns whether the passed type is a type of uint and the number of bytes needed to encode the type.

Types

type BoolFieldIndex added in v1.1.1

type BoolFieldIndex struct {
	Field string
}

BoolFieldIndex is used to extract an boolean field from an object using reflection and builds an index on that field.

func (*BoolFieldIndex) FromArgs added in v1.1.1

func (i *BoolFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*BoolFieldIndex) FromObject added in v1.1.1

func (i *BoolFieldIndex) FromObject(obj interface{}) (bool, []byte, error)

type Change added in v1.1.0

type Change struct {
	Table  string
	Before interface{}
	After  interface{}
	// contains filtered or unexported fields
}

Change describes a mutation to an object in a table.

func (*Change) Created added in v1.1.0

func (m *Change) Created() bool

Created returns true if the mutation describes a new object being inserted.

func (*Change) Deleted added in v1.1.0

func (m *Change) Deleted() bool

Deleted returns true if the mutation describes an existing object being deleted.

func (*Change) Updated added in v1.1.0

func (m *Change) Updated() bool

Updated returns true if the mutation describes an existing object being updated.

type Changes added in v1.1.0

type Changes []Change

Changes describes a set of mutations to memDB tables performed during a transaction.

type CompoundIndex

type CompoundIndex struct {
	Indexes []Indexer

	// AllowMissing results in an index based on only the indexers
	// that return data. If true, you may end up with 2/3 columns
	// indexed which might be useful for an index scan. Otherwise,
	// the CompoundIndex requires all indexers to be satisfied.
	AllowMissing bool
}

CompoundIndex is used to build an index using multiple sub-indexes Prefix based iteration is supported as long as the appropriate prefix of indexers support it. All sub-indexers are only assumed to expect a single argument.

func (*CompoundIndex) FromArgs

func (c *CompoundIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*CompoundIndex) FromObject

func (c *CompoundIndex) FromObject(raw interface{}) (bool, []byte, error)

func (*CompoundIndex) PrefixFromArgs

func (c *CompoundIndex) PrefixFromArgs(args ...interface{}) ([]byte, error)

type CompoundMultiIndex added in v1.0.2

type CompoundMultiIndex struct {
	Indexes []Indexer

	// AllowMissing results in an index based on only the indexers
	// that return data. If true, you may end up with 2/3 columns
	// indexed which might be useful for an index scan. Otherwise,
	// CompoundMultiIndex requires all indexers to be satisfied.
	AllowMissing bool
}

CompoundMultiIndex is used to build an index using multiple sub-indexes.

Unlike CompoundIndex, CompoundMultiIndex can have both SingleIndexer and MultiIndexer sub-indexers. However, each MultiIndexer adds considerable overhead/complexity in terms of the number of indexes created under-the-hood. It is not suggested to use more than one or two, if possible.

Another change from CompoundIndexer is that if AllowMissing is set, not only is it valid to have empty index fields, but it will still create index values up to the first empty index. This means that if you have a value with an empty field, rather than using a prefix for lookup, you can simply pass in less arguments. As an example, if {Foo, Bar} is indexed but Bar is missing for a value and AllowMissing is set, an index will still be created for {Foo} and it is valid to do a lookup passing in only Foo as an argument. Note that the ordering isn't guaranteed -- it's last-insert wins, but this is true if you have two objects that have the same indexes not using AllowMissing anyways.

Because StringMapFieldIndexers can take a varying number of args, it is currently a requirement that whenever it is used, two arguments must _always_ be provided for it. In theory we only need one, except a bug in that indexer means the single-argument version will never work. You can leave the second argument nil, but it will never produce a value. We support this for whenever that bug is fixed, likely in a next major version bump.

Prefix-based indexing is not currently supported.

func (*CompoundMultiIndex) FromArgs added in v1.0.2

func (c *CompoundMultiIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*CompoundMultiIndex) FromObject added in v1.0.2

func (c *CompoundMultiIndex) FromObject(raw interface{}) (bool, [][]byte, error)

type ConditionalIndex

type ConditionalIndex struct {
	Conditional ConditionalIndexFunc
}

ConditionalIndex builds an index based on a condition specified by a passed user function. This function may examine the passed object and return a boolean to encapsulate an arbitrarily complex conditional.

func (*ConditionalIndex) FromArgs

func (c *ConditionalIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*ConditionalIndex) FromObject

func (c *ConditionalIndex) FromObject(obj interface{}) (bool, []byte, error)

type ConditionalIndexFunc

type ConditionalIndexFunc func(obj interface{}) (bool, error)

ConditionalIndexFunc is the required function interface for a ConditionalIndex.

type DBSchema

type DBSchema struct {
	// Tables is the set of tables within this database. The key is the
	// table name and must match the Name in TableSchema.
	Tables map[string]*TableSchema
}

DBSchema is the schema to use for the full database with a MemDB instance.

MemDB will require a valid schema. Schema validation can be tested using the Validate function. Calling this function is recommended in unit tests.

func (*DBSchema) Validate

func (s *DBSchema) Validate() error

Validate validates the schema.

type FieldSetIndex

type FieldSetIndex struct {
	Field string
}

FieldSetIndex is used to extract a field from an object using reflection and builds an index on whether the field is set by comparing it against its type's nil value.

func (*FieldSetIndex) FromArgs

func (f *FieldSetIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*FieldSetIndex) FromObject

func (f *FieldSetIndex) FromObject(obj interface{}) (bool, []byte, error)

type FilterFunc

type FilterFunc func(interface{}) bool

FilterFunc is a function that takes the results of an iterator and returns whether the result should be filtered out.

type FilterIterator

type FilterIterator struct {
	// contains filtered or unexported fields
}

FilterIterator is used to wrap a ResultIterator and apply a filter over it.

func NewFilterIterator

func NewFilterIterator(iter ResultIterator, filter FilterFunc) *FilterIterator

NewFilterIterator wraps a ResultIterator. The filter function is applied to each value returned by a call to iter.Next.

See the documentation for ResultIterator to understand the behaviour of the returned FilterIterator.

func (*FilterIterator) Next

func (f *FilterIterator) Next() interface{}

Next returns the next non-filtered result from the wrapped iterator.

func (*FilterIterator) WatchCh

func (f *FilterIterator) WatchCh() <-chan struct{}

WatchCh returns the watch channel of the wrapped iterator.

type IndexSchema

type IndexSchema struct {
	// Name of the index. This must be unique among a tables set of indexes.
	// This must match the key in the map of Indexes for a TableSchema.
	Name string

	// AllowMissing if true ignores this index if it doesn't produce a
	// value. For example, an index that extracts a field that doesn't
	// exist from a structure.
	AllowMissing bool

	Unique  bool
	Indexer Indexer
}

IndexSchema is the schema for an index. An index defines how a table is queried.

func (*IndexSchema) Validate

func (s *IndexSchema) Validate() error

type Indexer

type Indexer interface {
	// FromArgs is called to build the exact index key from a list of arguments.
	FromArgs(args ...interface{}) ([]byte, error)
}

Indexer is an interface used for defining indexes. Indexes are used for efficient lookup of objects in a MemDB table. An Indexer must also implement one of SingleIndexer or MultiIndexer.

Indexers are primarily responsible for returning the lookup key as a byte slice. The byte slice is the key data in the underlying data storage.

type IntFieldIndex added in v1.0.1

type IntFieldIndex struct {
	Field string
}

IntFieldIndex is used to extract an int field from an object using reflection and builds an index on that field.

func (*IntFieldIndex) FromArgs added in v1.0.1

func (i *IntFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*IntFieldIndex) FromObject added in v1.0.1

func (i *IntFieldIndex) FromObject(obj interface{}) (bool, []byte, error)

type MemDB

type MemDB struct {
	// contains filtered or unexported fields
}

MemDB is an in-memory database providing Atomicity, Consistency, and Isolation from ACID. MemDB doesn't provide Durability since it is an in-memory database.

MemDB provides a table abstraction to store objects (rows) with multiple indexes based on inserted values. The database makes use of immutable radix trees to provide transactions and MVCC.

Objects inserted into MemDB are not copied. It is **extremely important** that objects are not modified in-place after they are inserted since they are stored directly in MemDB. It remains unsafe to modify inserted objects even after they've been deleted from MemDB since there may still be older snapshots of the DB being read from other goroutines.

func NewMemDB

func NewMemDB(schema *DBSchema) (*MemDB, error)

NewMemDB creates a new MemDB with the given schema.

func (*MemDB) DBSchema added in v1.3.3

func (db *MemDB) DBSchema() *DBSchema

DBSchema returns schema in use for introspection.

The method is intended for *read-only* debugging use cases, returned schema should *never be modified in-place*.

func (*MemDB) Snapshot

func (db *MemDB) Snapshot() *MemDB

Snapshot is used to capture a point-in-time snapshot of the database that will not be affected by any write operations to the existing DB.

If MemDB is storing reference-based values (pointers, maps, slices, etc.), the Snapshot will not deep copy those values. Therefore, it is still unsafe to modify any inserted values in either DB.

func (*MemDB) Txn

func (db *MemDB) Txn(write bool) *Txn

Txn is used to start a new transaction in either read or write mode. There can only be a single concurrent writer, but any number of readers.

type MultiIndexer

type MultiIndexer interface {
	// FromObject extracts index values from an object. The return values
	// are the same as a SingleIndexer except there can be multiple index
	// values.
	FromObject(raw interface{}) (bool, [][]byte, error)
}

MultiIndexer is an interface used for defining indexes that generate multiple values per object. Each value is stored as a seperate index pointing to the same object.

For example, an index that extracts the first and last name of a person and allows lookup based on eitherd would be a MultiIndexer. The FromObject of this example would split the first and last name and return both as values.

type PrefixIndexer

type PrefixIndexer interface {
	// PrefixFromArgs is the same as FromArgs for an Indexer except that
	// the index value returned should return all prefix-matched values.
	PrefixFromArgs(args ...interface{}) ([]byte, error)
}

PrefixIndexer is an optional interface on top of an Indexer that allows indexes to support prefix-based iteration.

type ResultIterator

type ResultIterator interface {
	WatchCh() <-chan struct{}
	// Next returns the next result from the iterator. If there are no more results
	// nil is returned.
	Next() interface{}
}

ResultIterator is used to iterate over a list of results from a query on a table.

When a ResultIterator is created from a write transaction, the results from Next will reflect a snapshot of the table at the time the ResultIterator is created. This means that calling Insert or Delete on a transaction while iterating is allowed, but the changes made by Insert or Delete will not be observed in the results returned from subsequent calls to Next. For example if an item is deleted from the index used by the iterator it will still be returned by Next. If an item is inserted into the index used by the iterator, it will not be returned by Next. However, an iterator created after a call to Insert or Delete will reflect the modifications.

When a ResultIterator is created from a write transaction, and there are already modifications to the index used by the iterator, the modification cache of the index will be invalidated. This may result in some additional allocations if the same node in the index is modified again.

type SingleIndexer

type SingleIndexer interface {
	// FromObject extracts the index value from an object. The return values
	// are whether the index value was found, the index value, and any error
	// while extracting the index value, respectively.
	FromObject(raw interface{}) (bool, []byte, error)
}

SingleIndexer is an interface used for defining indexes that generate a single value per object

type StringFieldIndex

type StringFieldIndex struct {
	Field     string
	Lowercase bool
}

StringFieldIndex is used to extract a field from an object using reflection and builds an index on that field.

func (*StringFieldIndex) FromArgs

func (s *StringFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*StringFieldIndex) FromObject

func (s *StringFieldIndex) FromObject(obj interface{}) (bool, []byte, error)

func (*StringFieldIndex) PrefixFromArgs

func (s *StringFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error)

type StringMapFieldIndex

type StringMapFieldIndex struct {
	Field     string
	Lowercase bool
}

StringMapFieldIndex is used to extract a field of type map[string]string from an object using reflection and builds an index on that field.

Note that although FromArgs in theory supports using either one or two arguments, there is a bug: FromObject only creates an index using key/value, and does not also create an index using key. This means a lookup using one argument will never actually work.

It is currently left as-is to prevent backwards compatibility issues.

TODO: Fix this in the next major bump.

func (*StringMapFieldIndex) FromArgs

func (s *StringMapFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

WARNING: Because of a bug in FromObject, this function will never return a value when using the single-argument version.

func (*StringMapFieldIndex) FromObject

func (s *StringMapFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error)

type StringSliceFieldIndex

type StringSliceFieldIndex struct {
	Field     string
	Lowercase bool
}

StringSliceFieldIndex builds an index from a field on an object that is a string slice ([]string). Each value within the string slice can be used for lookup.

func (*StringSliceFieldIndex) FromArgs

func (s *StringSliceFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*StringSliceFieldIndex) FromObject

func (s *StringSliceFieldIndex) FromObject(obj interface{}) (bool, [][]byte, error)

func (*StringSliceFieldIndex) PrefixFromArgs

func (s *StringSliceFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error)

type TableSchema

type TableSchema struct {
	// Name of the table. This must match the key in the Tables map in DBSchema.
	Name string

	// Indexes is the set of indexes for querying this table. The key
	// is a unique name for the index and must match the Name in the
	// IndexSchema.
	Indexes map[string]*IndexSchema
}

TableSchema is the schema for a single table.

func (*TableSchema) Validate

func (s *TableSchema) Validate() error

Validate is used to validate the table schema

type Txn

type Txn struct {
	// contains filtered or unexported fields
}

Txn is a transaction against a MemDB. This can be a read or write transaction.

func (*Txn) Abort

func (txn *Txn) Abort()

Abort is used to cancel this transaction. This is a noop for read transactions, already aborted or commited transactions.

func (*Txn) Changes added in v1.1.0

func (txn *Txn) Changes() Changes

Changes returns the set of object changes that have been made in the transaction so far. If change tracking is not enabled it wil always return nil. It can be called before or after Commit. If it is before Commit it will return all changes made so far which may not be the same as the final Changes. After abort it will always return nil. As with other Txn methods it's not safe to call this from a different goroutine than the one making mutations or committing the transaction. Mutations will appear in the order they were performed in the transaction but multiple operations to the same object will be collapsed so only the effective overall change to that object is present. If transaction operations are dependent (e.g. copy object X to Y then delete X) this might mean the set of mutations is incomplete to verify history, but it is complete in that the net effect is preserved (Y got a new value, X got removed).

func (*Txn) Commit

func (txn *Txn) Commit()

Commit is used to finalize this transaction. This is a noop for read transactions, already aborted or committed transactions.

func (*Txn) Defer

func (txn *Txn) Defer(fn func())

Defer is used to push a new arbitrary function onto a stack which gets called when a transaction is committed and finished. Deferred functions are called in LIFO order, and only invoked at the end of write transactions.

func (*Txn) Delete

func (txn *Txn) Delete(table string, obj interface{}) error

Delete is used to delete a single object from the given table. This object must already exist in the table.

func (*Txn) DeleteAll

func (txn *Txn) DeleteAll(table, index string, args ...interface{}) (int, error)

DeleteAll is used to delete all the objects in a given table matching the constraints on the index

func (*Txn) DeletePrefix

func (txn *Txn) DeletePrefix(table string, prefix_index string, prefix string) (bool, error)

DeletePrefix is used to delete an entire subtree based on a prefix. The given index must be a prefix index, and will be used to perform a scan and enumerate the set of objects to delete. These will be removed from all other indexes, and then a special prefix operation will delete the objects from the given index in an efficient subtree delete operation. This is useful when you have a very large number of objects indexed by the given index, along with a much smaller number of entries in the other indexes for those objects.

func (*Txn) First

func (txn *Txn) First(table, index string, args ...interface{}) (interface{}, error)

First is used to return the first matching object for the given constraints on the index.

Note that all values read in the transaction form a consistent snapshot from the time when the transaction was created.

func (*Txn) FirstWatch

func (txn *Txn) FirstWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error)

FirstWatch is used to return the first matching object for the given constraints on the index along with the watch channel.

Note that all values read in the transaction form a consistent snapshot from the time when the transaction was created.

The watch channel is closed when a subsequent write transaction has updated the result of the query. Since each read transaction operates on an isolated snapshot, a new read transaction must be started to observe the changes that have been made.

If the value of index ends with "_prefix", FirstWatch will perform a prefix match instead of full match on the index. The registered indexer must implement PrefixIndexer, otherwise an error is returned.

func (*Txn) Get

func (txn *Txn) Get(table, index string, args ...interface{}) (ResultIterator, error)

Get is used to construct a ResultIterator over all the rows that match the given constraints of an index. The index values must match exactly (this is not a range-based or prefix-based lookup) by default.

Prefix lookups: if the named index implements PrefixIndexer, you may perform prefix-based lookups by appending "_prefix" to the index name. In this scenario, the index values given in args are treated as prefix lookups. For example, a StringFieldIndex will match any string with the given value as a prefix: "mem" matches "memdb".

See the documentation for ResultIterator to understand the behaviour of the returned ResultIterator.

func (*Txn) GetReverse added in v1.3.0

func (txn *Txn) GetReverse(table, index string, args ...interface{}) (ResultIterator, error)

GetReverse is used to construct a Reverse ResultIterator over all the rows that match the given constraints of an index. The returned ResultIterator's Next() will return the next Previous value.

See the documentation on Get for details on arguments.

See the documentation for ResultIterator to understand the behaviour of the returned ResultIterator.

func (*Txn) Insert

func (txn *Txn) Insert(table string, obj interface{}) error

Insert is used to add or update an object into the given table.

When updating an object, the obj provided should be a copy rather than a value updated in-place. Modifying values in-place that are already inserted into MemDB is not supported behavior.

func (*Txn) Last added in v1.3.0

func (txn *Txn) Last(table, index string, args ...interface{}) (interface{}, error)

Last is used to return the last matching object for the given constraints on the index.

Note that all values read in the transaction form a consistent snapshot from the time when the transaction was created.

func (*Txn) LastWatch added in v1.3.0

func (txn *Txn) LastWatch(table, index string, args ...interface{}) (<-chan struct{}, interface{}, error)

LastWatch is used to return the last matching object for the given constraints on the index along with the watch channel.

Note that all values read in the transaction form a consistent snapshot from the time when the transaction was created.

The watch channel is closed when a subsequent write transaction has updated the result of the query. Since each read transaction operates on an isolated snapshot, a new read transaction must be started to observe the changes that have been made.

If the value of index ends with "_prefix", LastWatch will perform a prefix match instead of full match on the index. The registered indexer must implement PrefixIndexer, otherwise an error is returned.

func (*Txn) LongestPrefix

func (txn *Txn) LongestPrefix(table, index string, args ...interface{}) (interface{}, error)

LongestPrefix is used to fetch the longest prefix match for the given constraints on the index. Note that this will not work with the memdb StringFieldIndex because it adds null terminators which prevent the algorithm from correctly finding a match (it will get to right before the null and fail to find a leaf node). This should only be used where the prefix given is capable of matching indexed entries directly, which typically only applies to a custom indexer. See the unit test for an example.

Note that all values read in the transaction form a consistent snapshot from the time when the transaction was created.

func (*Txn) LowerBound added in v1.0.3

func (txn *Txn) LowerBound(table, index string, args ...interface{}) (ResultIterator, error)

LowerBound is used to construct a ResultIterator over all the the range of rows that have an index value greater than or equal to the provide args. Calling this then iterating until the rows are larger than required allows range scans within an index. It is not possible to watch the resulting iterator since the radix tree doesn't efficiently allow watching on lower bound changes. The WatchCh returned will be nill and so will block forever.

If the value of index ends with "_prefix", LowerBound will perform a prefix match instead of a full match on the index. The registered index must implement PrefixIndexer, otherwise an error is returned.

See the documentation for ResultIterator to understand the behaviour of the returned ResultIterator.

func (*Txn) ReverseLowerBound added in v1.3.0

func (txn *Txn) ReverseLowerBound(table, index string, args ...interface{}) (ResultIterator, error)

ReverseLowerBound is used to construct a Reverse ResultIterator over all the the range of rows that have an index value less than or equal to the provide args. Calling this then iterating until the rows are lower than required allows range scans within an index. It is not possible to watch the resulting iterator since the radix tree doesn't efficiently allow watching on lower bound changes. The WatchCh returned will be nill and so will block forever.

See the documentation for ResultIterator to understand the behaviour of the returned ResultIterator.

func (*Txn) Snapshot added in v1.2.0

func (txn *Txn) Snapshot() *Txn

Snapshot creates a snapshot of the current state of the transaction. Returns a new read-only transaction or nil if the transaction is already aborted or committed.

func (*Txn) TrackChanges added in v1.1.0

func (txn *Txn) TrackChanges()

TrackChanges enables change tracking for the transaction. If called at any point before commit, subsequent mutations will be recorded and can be retrieved using ChangeSet. Once this has been called on a transaction it can't be unset. As with other Txn methods it's not safe to call this from a different goroutine than the one making mutations or committing the transaction.

type UUIDFieldIndex

type UUIDFieldIndex struct {
	Field string
}

UUIDFieldIndex is used to extract a field from an object using reflection and builds an index on that field by treating it as a UUID. This is an optimization to using a StringFieldIndex as the UUID can be more compactly represented in byte form.

func (*UUIDFieldIndex) FromArgs

func (u *UUIDFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*UUIDFieldIndex) FromObject

func (u *UUIDFieldIndex) FromObject(obj interface{}) (bool, []byte, error)

func (*UUIDFieldIndex) PrefixFromArgs

func (u *UUIDFieldIndex) PrefixFromArgs(args ...interface{}) ([]byte, error)

type UintFieldIndex

type UintFieldIndex struct {
	Field string
}

UintFieldIndex is used to extract a uint field from an object using reflection and builds an index on that field.

func (*UintFieldIndex) FromArgs

func (u *UintFieldIndex) FromArgs(args ...interface{}) ([]byte, error)

func (*UintFieldIndex) FromObject

func (u *UintFieldIndex) FromObject(obj interface{}) (bool, []byte, error)

type WatchSet

type WatchSet map[<-chan struct{}]struct{}

WatchSet is a collection of watch channels. The zero value is not usable. Use NewWatchSet to create a WatchSet.

func NewWatchSet

func NewWatchSet() WatchSet

NewWatchSet constructs a new watch set.

func (WatchSet) Add

func (w WatchSet) Add(watchCh <-chan struct{})

Add appends a watchCh to the WatchSet if non-nil.

func (WatchSet) AddWithLimit

func (w WatchSet) AddWithLimit(softLimit int, watchCh <-chan struct{}, altCh <-chan struct{})

AddWithLimit appends a watchCh to the WatchSet if non-nil, and if the given softLimit hasn't been exceeded. Otherwise, it will watch the given alternate channel. It's expected that the altCh will be the same on many calls to this function, so you will exceed the soft limit a little bit if you hit this, but not by much.

This is useful if you want to track individual items up to some limit, after which you watch a higher-level channel (usually a channel from start of an iterator higher up in the radix tree) that will watch a superset of items.

func (WatchSet) Watch

func (w WatchSet) Watch(timeoutCh <-chan time.Time) bool

Watch blocks until one of the channels in the watch set is closed, or timeoutCh sends a value. Returns true if timeoutCh is what caused Watch to unblock.

func (WatchSet) WatchCh added in v1.2.1

func (w WatchSet) WatchCh(ctx context.Context) <-chan error

WatchCh returns a channel that is used to wait for any channel of the watch set to trigger or for the context to be cancelled. WatchCh creates a new goroutine each call, so callers may need to cache the returned channel to avoid creating extra goroutines.

func (WatchSet) WatchCtx

func (w WatchSet) WatchCtx(ctx context.Context) error

WatchCtx blocks until one of the channels in the watch set is closed, or ctx is done (cancelled or exceeds the deadline). WatchCtx returns an error if the ctx causes it to unblock, otherwise returns nil.

WatchCtx should be preferred over Watch.

Directories

Path Synopsis
This tool generates the special-case code for a small number of watchers which runs all the watches in a single select vs.
This tool generates the special-case code for a small number of watchers which runs all the watches in a single select vs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL