Registry Internals
Registry Internals
Seção intitulada “Registry Internals”O registry é um armazenamento de estado versionado e orientado a eventos. Ele mantém histórico completo de versões, suporta transações e propaga mudanças através do event bus.
Armazenamento de Entradas
Seção intitulada “Armazenamento de Entradas”Entradas são armazenadas como um slice ordenado com um índice de hash map para lookups O(1):
type Entry struct { ID ID // namespace:name Kind Kind // Tipo da entrada Meta attrs.Bag // Metadados Data payload.Payload // Conteúdo}IDs de entrada usam o pacote unique do Go para interning - IDs idênticos compartilham memória.
Cadeia de Versões
Seção intitulada “Cadeia de Versões”Cada versão aponta para seu pai. Computação de caminho usa um algoritmo de grafo para encontrar a rota mais curta entre quaisquer duas versões:
flowchart LR v0[v0] --> v1[v1] --> v2[v2] --> v3[v3] --> vN[vN]ChangeSets
Seção intitulada “ChangeSets”Um changeset é uma lista ordenada de operações transformando um estado em outro:
| Operação | OriginalEntry | Propósito |
|---|---|---|
| Create | nil | Adicionar nova entrada |
| Update | valor antigo | Modificar existente |
| Delete | valor deletado | Remover entrada |
OriginalEntry permite reversão - updates armazenam o valor anterior, deletes armazenam o que foi removido.
Construindo Deltas
Seção intitulada “Construindo Deltas”BuildDelta(oldState, newState) gera operações mínimas:
- Comparar estados, identificar mudanças
- Ordenar deletes em ordem reversa de dependência (dependentes primeiro)
- Ordenar creates/updates em ordem direta de dependência (dependências primeiro)
Squashing
Seção intitulada “Squashing”Múltiplos changesets mesclam rastreando estado final por entrada:
Create + Update = Create (com valor atualizado)Create + Delete = vazio (cancelam)Update + Delete = DeleteDelete + Create = UpdateTransações
Seção intitulada “Transações”sequenceDiagram participant R as Registry participant B as EventBus participant H as Handlers
R->>B: registry.begin loop Cada Operação R->>B: entry.create/update/delete B->>H: despachar para listeners H-->>B: aceitar ou rejeitar B-->>R: confirmação end alt Todos aceitos R->>B: registry.commit else Algum rejeitado R->>B: registry.discard R->>R: rollback endHandlers tem 30 segundos para aceitar ou rejeitar cada operação. Em rejeição, o registry faz rollback computando e aplicando o delta inverso.
Entradas que Não Propagam
Seção intitulada “Entradas que Não Propagam”Alguns tipos pulam o event bus completamente:
registry.entry- Configs de aplicaçãons.requirement- Requirements de namespacens.dependency- Dependências de módulons.definition- Metadados do módulo (readme, licença, autores)
Resolução de Dependências
Seção intitulada “Resolução de Dependências”Entradas podem declarar dependências de outras entradas. O resolver extrai dependências via padrões registrados:
resolver.RegisterPattern(registry.DependencyPattern{ Path: "meta.server", AllowWildcard: true,})Dependências são extraídas dos campos Meta e Data da entrada, depois usadas para ordenação topológica durante transições de estado.
Histórico de Versões
Seção intitulada “Histórico de Versões”Backends de histórico:
| Implementação | Caso de Uso |
|---|---|
| SQLite | Persistência de produção |
| Memory | Testes |
| Nil | Sem histórico |
SQLite usa modo WAL com tabelas para versões, changesets (codificados em MessagePack) e metadados.
Navegação
Seção intitulada “Navegação”Computação de caminho encontra a rota mais curta entre versões:
Path(v0, v3) = [v1, v2, v3] // Aplicar changesets para frentePath(v3, v1) = [v2, v1] // Aplicar changesets reversosLoadState() reproduz histórico de um baseline sem criar novas versões - usado durante boot.
Motor de busca com caching LRU para pesquisar entradas:
| Operador | Prefixo | Exemplo |
|---|---|---|
| Glob | (nenhum) | .kind=function.* |
| Regex | ~ | ~meta.path=/api/.* |
| Contains | * | *meta.tags=backend |
| Prefix | ^ | ^meta.name=user |
| Suffix | $ | $meta.path=Handler |
Cache invalida em mudança de versão.