Documentation
¶
Overview ¶
Package index coordinates the secondary indexes attached to a labelled property graph.
A Manager owns a set of named indexes (label bitmap, hash exact-match, B+ tree range) and fans out mutations to every index that subscribes to the affected property or label. The fan-out is best-effort sequential: failures in one subscriber do not abort the others (subscribers are independent and idempotent).
Index ¶
- Variables
- type Change
- type ChangeOp
- type Manager
- func (m *Manager) Apply(c Change)
- func (m *Manager) ApplyBatch(changes []Change)
- func (m *Manager) Count() int
- func (m *Manager) CreateIndex(name string, sub Subscriber) error
- func (m *Manager) DropIndex(name string) error
- func (m *Manager) GetIndex(name string) (Subscriber, error)
- func (m *Manager) ListIndexes() []string
- type Serializer
- type Subscriber
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrIndexCorrupted = errors.New("index: serialized form corrupted")
ErrIndexCorrupted is returned by [Serializer.Deserialize] when the serialised form is structurally malformed or its CRC32C trailer does not match the payload. Callers (snapshot recovery in particular) treat this as "rebuild from the LPG" rather than as a fatal error.
var ErrIndexExists = errors.New("index: an index by that name already exists")
ErrIndexExists is returned by Manager.CreateIndex when the name is already in use.
var ErrIndexNotFound = errors.New("index: no index by that name")
ErrIndexNotFound is returned by Manager.DropIndex or Manager.GetIndex when the named index does not exist.
var ErrIndexValueTypeUnsupported = errors.New("index: value type not supported for serialization")
ErrIndexValueTypeUnsupported is returned by a generic index's Serialize / Deserialize methods when the value-type parameter is not in the supported on-disk encoding set (currently: string). Callers can convert their value type to string before registering the index for snapshot durability.
Functions ¶
This section is empty.
Types ¶
type Change ¶
type Change struct {
Op ChangeOp
Node graph.NodeID
Dst graph.NodeID // edge changes only
Property uint32 // 0 when not a property change
Label uint32 // 0 when not a label change
// OldValue and NewValue are present only for property changes.
// They are typed as any so this package stays generic across
// every PropertyValue kind without importing the lpg package.
OldValue any
NewValue any
}
Change describes a single mutation observed by the Manager. Each subscriber inspects the relevant fields and decides whether to update its own state.
Property and Label fields are interned identifiers from the owning graph's registries (lpg.PropertyKeyID / lpg.LabelID), surfaced as uint32 so this package does not import the lpg package and create a cycle.
func (Change) IsEdgeChange ¶
IsEdgeChange reports whether the change concerns an edge.
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager owns the set of named indexes attached to a graph and fans out mutations to every subscriber.
Manager is safe for concurrent use.
Example ¶
ExampleManager shows the Manager lifecycle: register a concrete index under a name, list and count the registered indexes, and reject a duplicate registration with ErrIndexExists.
package main
import (
"errors"
"fmt"
"github.com/FlavioCFOliveira/GoGraph/graph/index"
"github.com/FlavioCFOliveira/GoGraph/graph/index/label"
)
func main() {
m := index.NewManager()
if err := m.CreateIndex("by_label", label.NewNodeIndex()); err != nil {
fmt.Println("unexpected:", err)
}
// Re-registering the same name is rejected.
err := m.CreateIndex("by_label", label.NewNodeIndex())
fmt.Println("duplicate is ErrIndexExists:", errors.Is(err, index.ErrIndexExists))
fmt.Println("count:", m.Count())
fmt.Println("names:", m.ListIndexes())
}
Output: duplicate is ErrIndexExists: true count: 1 names: [by_label]
func (*Manager) Apply ¶
Apply fans c out to every registered subscriber under a read lock so subscribers cannot be unregistered mid-update. The Manager itself does not enforce ordering across subscribers — each subscriber is expected to be order-independent on the change stream it observes.
Example ¶
ExampleManager_Apply shows the Manager fanning a change out to every registered subscriber. The label index observes OpAddNodeLabel events and can then be queried back through GetIndex for the NodeIDs that carry a given label.
package main
import (
"fmt"
"github.com/FlavioCFOliveira/GoGraph/graph"
"github.com/FlavioCFOliveira/GoGraph/graph/index"
"github.com/FlavioCFOliveira/GoGraph/graph/index/label"
)
func main() {
const labelPerson = uint32(7)
m := index.NewManager()
_ = m.CreateIndex("node_labels", label.NewNodeIndex())
// A mutation observed by the owning graph is fanned out to every
// subscriber. Here two nodes acquire the Person label.
m.Apply(index.Change{Op: index.OpAddNodeLabel, Node: graph.NodeID(1), Label: labelPerson})
m.Apply(index.Change{Op: index.OpAddNodeLabel, Node: graph.NodeID(4), Label: labelPerson})
// Recover the concrete index to run a query.
sub, _ := m.GetIndex("node_labels")
idx := sub.(*label.Index)
fmt.Println("kind:", idx.Kind())
fmt.Println("Person count:", idx.Count(labelPerson))
fmt.Println("Person members:", idx.Scan(labelPerson))
}
Output: kind: label Person count: 2 Person members: [1 4]
func (*Manager) ApplyBatch ¶
ApplyBatch fans an ordered slice of changes out to every subscriber in order. The whole batch is applied under one read lock; this is the substrate consumed by future transaction integration (Sprint 3).
func (*Manager) CreateIndex ¶
func (m *Manager) CreateIndex(name string, sub Subscriber) error
CreateIndex registers sub under name. Returns ErrIndexExists when the name is already taken.
func (*Manager) GetIndex ¶
func (m *Manager) GetIndex(name string) (Subscriber, error)
GetIndex returns the subscriber registered under name.
func (*Manager) ListIndexes ¶
ListIndexes returns the names of every currently registered index in unspecified order.
type Serializer ¶
Serializer is implemented by indexes that can persist and restore their internal state through an io.Writer / io.Reader pair. The Manager type-asserts every registered Subscriber to this interface during snapshot writes; subscribers that do not implement Serializer are silently skipped (rebuild-on-restart).
Implementations must:
- Write a fixed self-describing header (magic + format version) so a future format bump can be detected on read.
- Cover the entire on-disk payload with a CRC32C trailer (uint32 little-endian) so corruption surfaces as ErrIndexCorrupted.
- Be safe for concurrent reads from other goroutines while Serialize executes (typically by holding the index's own RLock for the duration of the write).
Deserialize replaces the receiver's state with the contents of r. On any structural problem or CRC mismatch the function returns a wrapped ErrIndexCorrupted and leaves the receiver in its previous state.
type Subscriber ¶
type Subscriber interface {
Apply(Change)
// Kind returns a short stable identifier of the underlying index
// implementation, used for introspection (e.g. "label", "hash",
// "btree").
Kind() string
}
Subscriber is implemented by every concrete index that wishes to receive change events from the Manager. The Apply method must be idempotent: replays of the same change must not produce duplicate state.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package btree provides an order-preserving property index over a constraints.Ordered value type, answering range predicates against the NodeIDs that carry each value.
|
Package btree provides an order-preserving property index over a constraints.Ordered value type, answering range predicates against the NodeIDs that carry each value. |
|
Package hash provides a sharded hash index from arbitrary comparable property values to the set of NodeIDs that carry them, represented as a 64-bit Roaring bitmap.
|
Package hash provides a sharded hash index from arbitrary comparable property values to the set of NodeIDs that carry them, represented as a 64-bit Roaring bitmap. |
|
Package label provides a Roaring-bitmap-backed inverted index from label identifiers to the NodeIDs that carry them.
|
Package label provides a Roaring-bitmap-backed inverted index from label identifiers to the NodeIDs that carry them. |