Ga naar de inhoud

Gecachet AST-zoeken

Gecachet AST-zoeken is een aanvullende modus met een opgewarmde cache naast de feitenindex. In plaats van geëxtraheerde feiten op te slaan en gematchte bestanden opnieuw te parsen, bewaart de cache geparste bomen op schijf als geserialiseerde gegevens. Bij volgende zoekopdrachten worden de bomen gedeserialiseerd en wordt de matcher rechtstreeks uitgevoerd, waarbij de PHP-Parser-pipeline volledig wordt overgeslagen.

De cache is beschikbaar via de subopdracht greph-index ast-cache CLI en de facademethoden Greph::buildAstCache() / Greph::searchAstCached(). Je kunt er ook in meerdere indexen en sets op basis van manifesten mee zoeken.

De cache opbouwen

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

De cache wordt standaard opgeslagen op <root>/.greph-ast-cache/. Cache opbouwen duurt doorgaans het langst van de drie indexmodi, omdat elk bestand eenmaal moet worden geparseerd.

Na een geslaagde build wordt een samenvatting van één regel weergegeven:

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

Het aantal gecachte bomen is meestal iets lager dan het aantal bestanden, omdat bestanden die niet kunnen worden geparseerd (en stilzwijgend worden overgeslagen) geen cachevermelding krijgen. Geef --strict-parse op bij de zoekopdracht als je parsefouten wilt zien.

De cache vernieuwen

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

refresh doorloopt de geïndexeerde root opnieuw, parseert gewijzigde bestanden opnieuw en herschrijft alleen de gecachte bomen die zijn veranderd.

Levenscyclusprofielen werken hetzelfde als in de andere modi met opgewarmde caches:

  • static: controleert nooit automatisch of de cache actueel is en wijzigt deze nooit automatisch
  • manual-refresh: meldt een verouderde status in stats, maar vernieuwt de cache nooit tijdens het zoeken
  • opportunistic-refresh: vernieuwt de cache tijdens het zoeken alleen als de gewijzigde set onder de ingestelde drempelwaarden blijft
  • strict-stale-check: weigert verouderde zoekopdrachten in plaats van de cache te vernieuwen

De cache doorzoeken

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

De optieset is identiek aan die van ast-index search, inclusief --fallback scan voor ontbrekende caches.

Herhaal --index-dir om met één aanroep in meerdere opgewarmde caches te zoeken:

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

Cachesets op basis van manifesten

Als je al benoemde opgewarmde sets bijhoudt, kun je met hetzelfde manifest gecacht AST-zoeken uitvoeren:

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)' .

Plannerd diagnostiek

--trace-plan geeft de beslissingen van de gecachte AST-planner door aan stderr, waaronder:

  • welke opgewarmde caches zijn doorzocht
  • of de vernieuwingslogica voor verouderde gegevens is uitgevoerd
  • aantallen kandidaatbestanden na beperking op bestandsniveau
  • hoeveel gecachte bomen zijn gedeserialiseerd voor exacte structurele matching

Cache versus feitenindex

Beide modi versnellen AST-zoeken, maar zijn geoptimaliseerd voor verschillende soorten werk.

Aspect Feitenindex (ast-index) Cache (ast-cache)
Wat wordt opgeslagen Geëxtraheerde feiten (aanroepnamen, klassennamen, declaraties) Geserialiseerde geparseerde bomen
Bouwkosten Lager Hoger (parseert alles)
Bouwgrootte Kleiner Groter
Querypad Filter op feiten, parseer en match daarna kandidaten Deserialiseer de boom en match daarna
Geschikt voor Patronen met een herkenbare kop (aanroepnaam, klassenaam) Patronen waarvan het onderscheidende kenmerk structureel is, niet nominaal
Minder geschikt voor Patronen waarvan de kop een metavariabele is Koude queries op een boom die niet meer in de OS-paginacache past

In de praktijk heeft de feitenindex de snelste koude query en de cache de snelste warme query. Gebruik de optie die bij je workload past, of bouw beide en laat je tooling kiezen.

Programmatisch gebruik

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 accepteert dezelfde AstSearchOptions als native AST-zoekopdrachten en retourneert dezelfde list<AstMatch>-vorm. Het enige verschil is dat de parserpipeline wordt overgeslagen voor bestanden die al in de cache staan. Gebruik voor flows met meerdere indexen of op basis van een manifest searchAstCachedMany(...) en searchAstCachedSet(...).

Wanneer gebruik je deze?

De modus met gecachte AST's is de juiste keuze wanneer:

  • Je herhaaldelijk structurele queries uitvoert op dezelfde codebase.
  • De bottleneck bij je vorige runs PHP-Parser was (in profielen zichtbaar als tijd besteed aan de lexer en parser).
  • Je voldoende schijfruimte hebt voor de opslag van de geserialiseerde boom.

Als je queries doorgaans slechts een klein deel van de codebase raken en de matches zich concentreren rond herkenbare aanroepnamen of klassennamen, past de feitenindex meestal beter. Als je queries zich breed over de codebase uitstrekken, maar je de eenmalige parseerkosten voor lief kunt nemen, wint de cache.