Registry Internals
Registry Internals
Section titled “Registry Internals”The registry is a versioned, event-driven state store. It maintains complete version history, supports transactions, and propagates changes through the event bus.
Entry Storage
Section titled “Entry Storage”Entries are stored as an ordered slice with a hash map index for O(1) lookups:
type Entry struct { ID ID // namespace:name Kind Kind // Entry type Meta attrs.Bag // Metadata Data payload.Payload // Content}Entry IDs use Go’s unique package for interning—identical IDs share memory.
Version Chain
Section titled “Version Chain”Each version points to its parent. Path computation uses a graph algorithm to find the shortest route between any two versions:
flowchart LR v0[v0] --> v1[v1] --> v2[v2] --> v3[v3] --> vN[vN]ChangeSets
Section titled “ChangeSets”A changeset is an ordered list of operations transforming one state to another:
| Operation | OriginalEntry | Purpose |
|---|---|---|
| Create | nil | Add new entry |
| Update | old value | Modify existing |
| Delete | deleted value | Remove entry |
OriginalEntry enables reversal—updates store the previous value, deletes store what was removed.
Building Deltas
Section titled “Building Deltas”BuildDelta(oldState, newState) generates minimal operations:
- Compare states, identify changes
- Sort deletes in reverse dependency order (dependents first)
- Sort creates/updates in forward dependency order (dependencies first)
Squashing
Section titled “Squashing”Multiple changesets merge by tracking final state per entry:
Create + Update = Create (with updated value)Create + Delete = ∅ (cancel out)Update + Delete = DeleteDelete + Create = UpdateTransactions
Section titled “Transactions”sequenceDiagram participant R as Registry participant B as EventBus participant H as Handlers
R->>B: registry.begin loop Each Operation R->>B: entry.create/update/delete B->>H: dispatch to listeners H-->>B: accept or reject B-->>R: confirmation end alt All accepted R->>B: registry.commit else Any rejected R->>B: registry.discard R->>R: rollback endHandlers have 30 seconds to accept or reject each operation. On rejection, the registry rolls back by computing and applying the inverse delta.
Non-propagating Entries
Section titled “Non-propagating Entries”Some kinds skip the event bus entirely:
registry.entry- Application configsns.requirement- Namespace requirementsns.dependency- Module dependenciesns.definition- Module metadata (readme, license, authors)
Dependency Resolution
Section titled “Dependency Resolution”Entries can declare dependencies on other entries. The resolver extracts dependencies via registered patterns:
resolver.RegisterPattern(registry.DependencyPattern{ Path: "meta.server", AllowWildcard: true,})Dependencies are extracted from entry Meta and Data fields, then used for topological sorting during state transitions.
Version History
Section titled “Version History”History backends:
| Implementation | Use Case |
|---|---|
| SQLite | Production persistence |
| Memory | Testing |
| Nil | No history |
SQLite uses WAL mode with tables for versions, changesets (MessagePack encoded), and metadata.
Navigation
Section titled “Navigation”Path computation finds the shortest route between versions:
Path(v0, v3) = [v1, v2, v3] // Apply changesets forwardPath(v3, v1) = [v2, v1] // Apply reversed changesetsLoadState() replays history from a baseline without creating new versions—used during boot.
Finder
Section titled “Finder”Query engine with LRU caching for searching entries:
| Operator | Prefix | Example |
|---|---|---|
| Glob | (none) | .kind=function.* |
| Regex | ~ | ~meta.path=/api/.* |
| Contains | * | *meta.tags=backend |
| Prefix | ^ | ^meta.name=user |
| Suffix | $ | $meta.path=Handler |
Cache invalidates on version change.