Vai al contenuto

Ricerca AST memorizzata nella cache

La ricerca AST memorizzata nella cache è una modalità complementare con cache precaricata rispetto all'indice dei fatti. Invece di salvare i fatti estratti e analizzare di nuovo i file corrispondenti, la cache salva su disco gli alberi analizzati serializzati. Le query successive deserializzano gli alberi ed eseguono direttamente il motore di ricerca, saltando del tutto la pipeline PHP-Parser.

La cache è esposta nel sottocomando greph-index ast-cache CLI e nei metodi della facciata Greph::buildAstCache() / Greph::searchAstCached(). Supporta inoltre la ricerca multi-indice e quella nei gruppi definiti da manifest.

Creazione della 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

Per impostazione predefinita, la cache viene salvata in <root>/.greph-ast-cache/. In genere, la creazione della cache è la più lenta delle tre modalità di indicizzazione, perché ogni file deve essere analizzato una volta.

Una creazione riuscita stampa un riepilogo su una riga:

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

Il numero di alberi memorizzati nella cache è di solito leggermente inferiore al numero di file, perché i file che non superano l'analisi (e vengono ignorati senza avviso) non generano una voce nella cache. Passate --strict-parse nel comando di ricerca per visualizzare gli errori di analisi.

Aggiornamento della cache

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

refresh ripercorre la radice indicizzata, analizza di nuovo i file modificati e riscrive solo gli alberi memorizzati nella cache che sono cambiati.

I profili del ciclo di vita corrispondono a quelli delle altre modalità precaricate:

  • static: non verificare mai l'aggiornamento né modificare automaticamente
  • manual-refresh: segnalare i dati obsoleti in stats, senza mai aggiornare durante la ricerca
  • opportunistic-refresh: aggiornare durante la ricerca solo se l'insieme delle modifiche è al di sotto delle soglie configurate
  • strict-stale-check: rifiutare le ricerche con dati obsoleti invece di aggiornarli

Interrogazione della 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

L'insieme di opzioni è identico a quello di ast-index search, inclusa --fallback scan per le cache mancanti.

Ripetete --index-dir per cercare in più cache precaricate con una sola chiamata:

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

Gruppi di cache definiti da manifest

Se usate già gruppi precaricati con nome, lo stesso manifest può gestire la ricerca AST memorizzata nella 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)' .

Diagnostica del pianificatore

--trace-plan riporta le decisioni del pianificatore AST nella cache in stderr, tra cui:

  • quali cache riscaldate sono state cercate
  • se è stata eseguita la logica di aggiornamento dei dati obsoleti
  • il numero di file candidati dopo il filtraggio a livello di file
  • quanti alberi memorizzati nella cache sono stati deserializzati per la corrispondenza strutturale esatta

Cache e indice dei fatti

Entrambe le modalità accelerano la ricerca AST, ma ottimizzano tipi di attività diversi.

Aspetto Indice dei fatti (ast-index) Cache (ast-cache)
Dati archiviati Fatti estratti (nomi di chiamate, nomi di classi, dichiarazioni) Alberi analizzati serializzati
Costo di creazione Inferiore Superiore (analizza tutto)
Dimensioni Minori Maggiori
Percorso della query Filtra in base ai fatti, poi analizza e confronta i candidati Deserializza l’albero, poi lo confronta
Ideale per Pattern con un elemento iniziale riconoscibile (nome di chiamata, nome di classe) Pattern la cui caratteristica distintiva è strutturale, non nominale
Meno indicato per Pattern il cui elemento iniziale è una metavariabile Query a freddo su un albero che non entra più nella cache delle pagine del sistema operativo

In pratica, l’indice dei fatti offre la query a freddo più veloce, mentre la cache offre la query a caldo più veloce. Usate quello più adatto al vostro carico di lavoro, oppure create entrambi e lasciate scegliere ai vostri strumenti.

Uso programmatico

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 accetta gli stessi AstSearchOptions della ricerca AST nativa e restituisce lo stesso formato list<AstMatch>. L’unica differenza è che la pipeline di analisi viene saltata per i file già presenti nella cache. Per flussi di lavoro con più indici o basati su manifest, usate searchAstCachedMany(...) e searchAstCachedSet(...).

Quando usarlo

La modalità AST memorizzata nella cache è lo strumento giusto quando:

  • Eseguite query strutturali ripetute sulla stessa base di codice.
  • Il collo di bottiglia nelle esecuzioni precedenti era PHP-Parser (nei profili si vede il tempo impiegato nel lexer e nel parser).
  • Potete dedicare spazio su disco all’archivio degli alberi serializzati.

Se le vostre query interessano di solito una piccola parte della base di codice e le corrispondenze si concentrano attorno a nomi di chiamate o di classi riconoscibili, l’indice dei fatti è in genere più adatto. Se le query coprono ampiamente la base di codice, ma potete sostenere un costo di analisi una tantum, conviene la cache.