Treci la conținut

Căutare AST memorată în cache

Căutarea AST memorată în cache este un mod complementar cu cache încălzit pentru indexul de fapte. În loc să stocheze fapte extrase și să analizeze din nou fișierele potrivite, cache-ul stochează pe disc arbori analizați serializați. Interogările ulterioare deserializa arborii și rulează direct potrivitorul, omițând complet fluxul PHP-Parser.

Cache-ul este disponibil prin subcomanda greph-index ast-cache CLI și metodele fațadei Greph::buildAstCache() / Greph::searchAstCached(). Permite și căutarea în mai multe indexuri și seturi susținute de manifest.

Construirea cache-ului

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

În mod implicit, cache-ul este stocat în <root>/.greph-ast-cache/. Construirea cache-ului este, de regulă, cea mai lentă dintre cele trei moduri de indexare, deoarece fiecare fișier trebuie analizat o dată.

O construire reușită afișează un rezumat pe o singură linie:

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

Numărul arborilor din cache este de obicei puțin mai mic decât numărul fișierelor, deoarece fișierele care nu pot fi analizate (și sunt omise fără notificare) nu generează o intrare în cache. Transmiteți --strict-parse în comanda de căutare dacă doriți să fie afișate erorile de analizare.

Reîmprospătarea cache-ului

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

refresh parcurge din nou rădăcina indexată, analizează din nou fișierele modificate și rescrie doar arborii din cache care s-au schimbat.

Profilurile ciclului de viață sunt identice cu celelalte moduri încălzite:

  • static: nu verifică niciodată actualitatea și nu modifică automat
  • manual-refresh: raportează starea învechită în stats, dar nu reîmprospătează niciodată în timpul căutării
  • opportunistic-refresh: reîmprospătează în timpul căutării doar când setul modificat este sub pragurile configurate
  • strict-stale-check: respinge căutările învechite în loc să reîmprospăteze

Interogarea cache-ului

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

Setul de opțiuni este identic cu ast-index search, inclusiv --fallback scan pentru cache-urile lipsă.

Repetați --index-dir pentru a căuta în mai multe cache-uri încălzite printr-un singur apel:

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

Seturi de cache susținute de manifest

Dacă folosiți deja seturi încălzite cu nume, același manifest poate ghida căutarea AST memorată în 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)' .

Diagnosticarea planificatorului

--trace-plan raportează deciziile planificatorului AST memorat în cache către stderr, inclusiv:

  • ce cache-uri încălzite au fost căutate
  • dacă a rulat logica de reîmprospătare a datelor învechite
  • numărul de fișiere candidate după restrângerea la nivel de fișier
  • câte arbori din cache au fost deserializați pentru potrivirea structurală exactă

Indexul de fapte vs. cache

Ambele moduri accelerează căutarea AST, dar optimizează tipuri diferite de sarcini.

Aspect Index de fapte (ast-index) Cache (ast-cache)
Ce se stochează Fapte extrase (nume de apeluri, nume de clase, declarații) Arbori analizați serializați
Costul construirii Mai mic Mai mare (analizează tot)
Dimensiunea construirii Mai mică Mai mare
Fluxul interogării Filtrează după fapte, apoi analizează și compară candidații Deserializați arborele, apoi comparați
Potrivit pentru Tipare cu un început recognoscibil (nume de apel, nume de clasă) Tipare a căror caracteristică distinctivă este structurală, nu nominală
Cel mai puțin potrivit pentru Tipare al căror început este o metavariabilă Interogări la rece pe un arbore care nu mai încape în cache-ul de pagini al sistemului de operare

În practică, indexul de fapte oferă cea mai rapidă interogare la rece, iar cache-ul oferă cea mai rapidă interogare la cald. Folosiți-l pe cel care se potrivește sarcinilor dvs. sau construiți-le pe ambele și lăsați instrumentele dvs. să aleagă.

Utilizare programatică

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 acceptă aceleași AstSearchOptions ca și căutarea AST nativă și returnează aceeași structură list<AstMatch>. Singura diferență este că fluxul parserului este ocolit pentru fișierele care se află deja în cache. Pentru fluxuri cu mai mulți indici sau bazate pe manifest, folosiți searchAstCachedMany(...) și searchAstCachedSet(...).

Când să îl folosiți

Modul AST din cache este potrivit când:

  • Rulați interogări structurale repetate asupra aceleiași baze de cod.
  • Blocajul în rulările anterioare a fost PHP-Parser (vizibil în profiluri ca timp petrecut în lexer și parser).
  • Aveți suficient spațiu pe disc pentru stocarea arborilor serializați.

Dacă interogările dvs. vizează de obicei o mică parte a bazei de cod, iar potrivirile se concentrează în jurul unor nume de apeluri sau de clase recognoscibile, indexul de fapte este de obicei o alegere mai potrivită. Dacă interogările dvs. acoperă o mare parte a bazei de cod, dar puteți suporta costul unei analize inițiale, cache-ul este alegerea mai bună.