
# Mecanismos

## Escolhendo um mecanismo

Os três mecanismos armazenam a mesma coisa: um ID UUIDv7 mais um array de dados,
mas organizam esses dados de formas diferentes no disco. Essa organização determina para que cada mecanismo
é mais indicado:

|            | DocStore | SegmentedLog | Queue |
| ---------- | -------- | ------------ | ----- |
| No disco   | um arquivo JSONC por registro, fragmentado por cauda UUID | segmentos somente de acréscimo com linhas JSON prefixadas pelo comprimento e pela soma de verificação, mais um manifesto | um log de eventos somente de acréscimo |
| Gravação   | substituição atômica de arquivo por registro | acréscimos com soma de verificação; sobrescritas e exclusões acrescentam novas entradas, recuperadas por `compact()` | acréscimo com soma de verificação por evento da fila |
| Leitura    | `get()` por ID, consultas indexadas | leituras com cursor e por intervalo de tempo, `get()` pelo índice de estado | `claim()` na ordem de enfileiramento |
| Ideal para | leituras pontuais e buscas indexadas em coleções de qualquer tamanho | fluxos com muitos acréscimos, até cerca de 1M de registros | distribuição durável de trabalho entre processos |
| Limitação  | varreduras de campos sem índice acima de cerca de 10k registros | regravações frequentes de um único registro (versões antigas ocupam espaço até a compactação) | não é um armazenamento geral de registros; os payloads são descartados quando uma tarefa é concluída |

`DocStore` e `SegmentedLog` compartilham a mesma [consulta fluente API](https://storh.inline0.dev/pt/docs/query-builder): a mesma sequência `where()` funciona nos dois
mecanismos, e apenas a execução muda. `DocStore` pode responder usando seus
índices secundários, enquanto `SegmentedLog` filtra durante a leitura dos segmentos.
`Queue` usa reivindicações, não consultas: os trabalhadores `claim()` o próximo trabalho
em vez de filtrar tarefas.

Regras práticas:

- Registros que você busca, atualiza ou exclui individualmente e consulta por campo:
  `DocStore`. Adicione [índices](https://storh.inline0.dev/pt/docs/indexes) aos campos usados nos filtros.
- Eventos ou versões que você geralmente apenas acrescenta e lê de volta em ordem ou por intervalo
  de tempo: `SegmentedLog`.
- Tarefas encaminhadas de produtores para processos de trabalho: `Queue`. As reivindicações e
  conclusões são seguras para vários processos, e `claimMany()`/`completeMany()`
  amortizam o custo de bloqueio e fsync.
- Junções, pesquisa ou relatórios sobre qualquer coleção: adicione um
  [SQLespelho](https://storh.inline0.dev/pt/docs/sql-mirror). Os arquivos permanecem canônicos; o espelho é uma
  projeção reconstruível em SQLite ou MySQL.

Os mecanismos se combinam: eles compartilham apenas o diretório raiz, então um aplicativo pode
manter conteúdo em um `DocStore`, um registro de auditoria em um `SegmentedLog` e
tarefas em segundo plano em um `Queue` sob a mesma raiz de armazenamento.

## DocStore

`DocStore` serve para leituras pontuais e varreduras simples de registros duráveis. Ele grava
um arquivo JSONC por registro:

```php
$store = new Storh\DocStore($root, 'articles');
$record = $store->put(['slug' => 'hello', 'published' => true]);
$same = $store->get($record->id());
```

Os arquivos de registro são distribuídos em fragmentos pelas UUID últimas letras, para que os picos de gravação de UUIDv7 se espalhem
entre diretórios:

```text
articles/data/2d/018bcfe5-6800-7000-8000-2d5dba6274da.jsonc
```

## SegmentedLog

`SegmentedLog` serve para registros com muitas inserções, leituras por cursor e leituras por intervalo de tempo.
Os registros são gravados no segmento ativo, uma linha por registro no formato
`<byte-length>\t<xxh32>\t<json>` (consulte [Atomicidade](https://storh.inline0.dev/pt/docs/atomicity)). Os
arquivos de segmento usam a extensão `.ndjson`, mas o prefixo de tamanho e checksum
impede que ferramentas NDJSON comuns os leiam; leia os registros usando `stream()` ou
com o construtor de consultas. Segmentos completos são convertidos em segmentos selados com índices esparsos.

```php
$events = new Storh\SegmentedLog($root, 'events');
$events->put(['type' => 'user.created']);
$events->compact();
```

## Fila

`Queue` serve para filas de trabalho duráveis de alta vazão. Enfileirar, reivindicar, concluir,
reenfileirar e limpar grava eventos somente de acréscimo em `queue.log`; o estado da fila é
reproduzido na memória quando ela é aberta. Os métodos em lote amortizam os custos de bloqueio e
flush entre várias tarefas. O log cresce a cada evento; `stats()`
informa seu tamanho atual em bytes.

```php
$queue = new Storh\Queue($root, 'mail');
$queue->enqueue(['to' => 'person@example.test']);
$job = $queue->claim();
```

## Durabilidade e concorrência

storh publica gravações de arquivos usando renomeação atômica no diretório de destino.
Reabrir e `repair()` removem arquivos temporários abandonados cujo processo proprietário já terminou,
enquanto preservam os arquivos temporários de processos de gravação ativos. Os marcadores de gravação tornam essa verificação
constante, então a abertura do armazenamento percorre a coleção somente após uma falha.

`SegmentedLog` e `Queue` gravam linhas de log protegidas por tamanho e checksum. Reabrir
ou reparar trunca as partes finais incompletas até o último evento confirmado e reconstrói o estado em memória
com base no conteúdo durável do log. As gravações no log e na fila são serializadas com
bloqueios do sistema de arquivos.

As alterações de `DocStore` são serializadas com um bloqueio de gravação no nível da coleção, de modo que
os arquivos de registro e os índices secundários sejam atualizados como um limite de consistência entre
processos. Gravações simultâneas em IDs de registro diferentes são seguras sob as mesmas
premissas de renomeação atômica do sistema de arquivos. Gravações simultâneas no mesmo ID seguem a regra de que
vence a última renomeação.

storh descarrega e sincroniza (fsync) os manipuladores de arquivos antes da renomeação ou da conclusão de um acréscimo e
tenta sincronizar (fsync) os diretórios pai após renomeações atômicas. A durabilidade em caso de queda de energia
ainda depende de o sistema de arquivos subjacente e as opções de montagem respeitarem essas
sincronizações.
