Pular para o conteúdo

Pesquisa de AST em cache

A pesquisa de AST em cache é um modo complementar de cache aquecido ao índice de fatos. Em vez de armazenar fatos extraídos e analisar novamente os arquivos correspondentes, o cache armazena árvores analisadas serializadas em disco. Nas consultas seguintes, as árvores são desserializadas e o mecanismo de correspondência é executado diretamente, ignorando completamente o pipeline PHP-Parser.

O cache está disponível pelo subcomando greph-index ast-cache CLI e pelos métodos de fachada Greph::buildAstCache() / Greph::searchAstCached(). Ele também oferece pesquisa em vários índices e conjuntos respaldados por manifestos.

Criar o cache

Shell
# Full build at the current directory
./vendor/bin/greph-index ast-cache build .

# Use a non-default cache directory
./vendor/bin/greph-index ast-cache build . --index-dir /tmp/greph-ast-cache

# Build a cache that may refresh automatically for small changes
./vendor/bin/greph-index ast-cache build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576

Por padrão, o cache é armazenado em <root>/.greph-ast-cache/. A criação do cache costuma ser a mais lenta entre os três modos de indexação, pois cada arquivo precisa ser analisado uma vez.

Uma criação bem-sucedida exibe um resumo de uma linha:

Text
Built AST cache for 2547 files in .greph-ast-cache (2541 cached trees, +2541 ~0 -0 =0)

A quantidade de árvores em cache costuma ser um pouco menor que a quantidade de arquivos porque arquivos cuja análise falha (e são ignorados silenciosamente) não geram uma entrada no cache. Passe --strict-parse no comando de pesquisa se quiser que os erros de análise sejam exibidos.

Atualizar o cache

Shell
./vendor/bin/greph-index ast-cache refresh .

refresh percorre novamente a raiz indexada, analisa outra vez os arquivos alterados e regrava apenas as árvores em cache que mudaram.

Os perfis de ciclo de vida são iguais aos dos outros modos aquecidos:

  • static: nunca verifica a atualidade nem modifica automaticamente
  • manual-refresh: informa o estado obsoleto em stats, mas nunca atualiza durante a pesquisa
  • opportunistic-refresh: atualiza durante a pesquisa somente quando o conjunto de alterações fica abaixo dos limites configurados
  • strict-stale-check: rejeita pesquisas obsoletas em vez de atualizar

Consultar o cache

Shell
./vendor/bin/greph-index ast-cache search 'new $CLASS()' src
./vendor/bin/greph-index ast-cache search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-cache search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-cache search --fallback scan 'new $CLASS()' src
./vendor/bin/greph-index ast-cache search --trace-plan 'array($$$ITEMS)' src

O conjunto de opções é idêntico ao de ast-index search, incluindo --fallback scan para caches ausentes.

Repita --index-dir para pesquisar em vários caches aquecidos em uma chamada:

Shell
./vendor/bin/greph-index ast-cache search \
  --index-dir ../wordpress/.greph-ast-cache \
  --index-dir ./.greph-ast-cache \
  --show-index-origin \
  'array($$$ITEMS)' .

Conjuntos de caches respaldados por manifesto

Se você já mantém conjuntos aquecidos nomeados, o mesmo manifesto pode executar a pesquisa de AST em cache:

Shell
./vendor/bin/greph-index set build --mode ast-cache
./vendor/bin/greph-index set stats --mode ast-cache --dry-refresh
./vendor/bin/greph-index set search --mode ast-cache --show-index-origin 'array($$$ITEMS)' .

Diagnósticos do planejador

--trace-plan informa as decisões do planejador de AST em cache em stderr, incluindo:

  • quais caches aquecidos foram pesquisados
  • se a lógica de atualização de itens obsoletos foi executada
  • quantidades de arquivos candidatos após a redução no nível dos arquivos
  • quantas árvores em cache foram desserializadas para a correspondência estrutural exata

Cache versus índice de fatos

Ambos os modos aceleram a pesquisa de AST, mas são otimizados para tipos diferentes de trabalho.

Aspecto Índice de fatos (ast-index) Cache (ast-cache)
O que é armazenado Fatos extraídos (nomes de chamadas, nomes de classes, declarações) Árvores analisadas serializadas
Custo de criação Menor Maior (analisa tudo)
Tamanho da criação Menor Maior
Caminho da consulta Filtra pelos fatos e, em seguida, analisa e compara os candidatos Desserializa a árvore e, em seguida, faz a comparação
Ideal para Padrões com um início reconhecível (nome de chamada, nome de classe) Padrões cujo recurso distintivo é estrutural, não nominal
Pior para Padrões cujo início é uma metavariável Consultas frias em uma árvore que já não cabe no cache de páginas do SO

Na prática, o índice de fatos oferece a consulta fria mais rápida, e o cache, a consulta aquecida mais rápida. Use o que melhor se adaptar à sua carga de trabalho ou crie ambos e deixe suas ferramentas escolherem.

Uso programático

PHP
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstCache('.', lifecycle: IndexLifecycleProfile::Static);

$matches = Greph::searchAstCached(
    'array($$$ITEMS)',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);

searchAstCached aceita o mesmo AstSearchOptions da pesquisa AST nativa e retorna a mesma estrutura de list<AstMatch>. A única diferença é que o pipeline do analisador é ignorado para arquivos que já estão no cache. Para fluxos com vários índices ou baseados em manifestos, use searchAstCachedMany(...) e searchAstCachedSet(...).

Quando usar

O modo AST em cache é a ferramenta certa quando:

  • Você executa consultas estruturais repetidas na mesma base de código.
  • O gargalo nas execuções anteriores era PHP-Parser (visível nos perfis como tempo gasto no lexer e no analisador).
  • Você pode reservar espaço em disco para o armazenamento da árvore serializada.

Se suas consultas costumam abranger uma pequena parte da base de código e as correspondências se concentram em nomes de chamadas ou classes reconhecíveis, o índice de fatos costuma ser mais adequado. Se suas consultas abrangem boa parte da base de código e você pode pagar o custo único da análise, o cache é melhor.