Buforowane wyszukiwanie AST
Buforowane wyszukiwanie AST to uzupełniający tryb z rozgrzaną pamięcią podręczną, działający obok indeksu faktów. Zamiast przechowywać wyodrębnione fakty i ponownie analizować dopasowane pliki, pamięć podręczna zapisuje na dysku serializowane drzewa składniowe. Kolejne zapytania deserializują drzewa i uruchamiają bezpośrednio mechanizm dopasowujący, całkowicie pomijając potok PHP-Parser.
Pamięć podręczna jest dostępna w podpoleceniu greph-index ast-cache CLI oraz metodach fasady Greph::buildAstCache() / Greph::searchAstCached(). Obsługuje też wyszukiwanie obejmujące wiele indeksów i zestawów opartych na manifeście.
Tworzenie pamięci podręcznej
# 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
Domyślnie pamięć podręczna jest przechowywana w <root>/.greph-ast-cache/. Tworzenie pamięci podręcznej jest zwykle najwolniejszym z trzech trybów indeksowania, ponieważ każdy plik trzeba raz przeanalizować.
Po pomyślnym utworzeniu indeksu wyświetlane jest jednowierszowe podsumowanie:
Built AST cache for 2547 files in .greph-ast-cache (2541 cached trees, +2541 ~0 -0 =0)
Liczba buforowanych drzew jest zwykle nieco niższa niż liczba plików, ponieważ pliki, których nie udało się przeanalizować (i które są pomijane bez powiadomienia), nie tworzą wpisu w pamięci podręcznej. Przekaż --strict-parse do polecenia wyszukiwania, jeśli chcesz, aby błędy analizy zostały zgłoszone.
Odświeżanie pamięci podręcznej
./vendor/bin/greph-index ast-cache refresh .
refresh ponownie przegląda indeksowany katalog główny, analizuje zmienione pliki i przepisuje tylko zmienione buforowane drzewa.
Profile cyklu życia działają tak samo jak w innych trybach z rozgrzaną pamięcią:
static: nigdy automatycznie nie sprawdzaj aktualności ani nie modyfikujmanual-refresh: zgłaszaj nieaktualny stan wstats, ale nigdy nie odświeżaj podczas wyszukiwaniaopportunistic-refresh: odświeżaj podczas wyszukiwania tylko wtedy, gdy zbiór zmian nie przekracza skonfigurowanych progówstrict-stale-check: odrzucaj nieaktualne wyszukiwania zamiast odświeżać
Wyszukiwanie w pamięci podręcznej
./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
Zestaw flag jest identyczny jak w ast-index search, w tym --fallback scan dla brakujących pamięci podręcznych.
Wyszukiwanie w wielu pamięciach podręcznych
Powtórz --index-dir, aby przeszukać kilka rozgrzanych pamięci podręcznych w jednym wywołaniu:
./vendor/bin/greph-index ast-cache search \
--index-dir ../wordpress/.greph-ast-cache \
--index-dir ./.greph-ast-cache \
--show-index-origin \
'array($$$ITEMS)' .
Zestawy pamięci podręcznych oparte na manifeście
Jeśli masz już nazwane zestawy rozgrzanych indeksów, ten sam manifest może służyć do buforowanego wyszukiwania AST:
./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)' .
Diagnostyka planera
--trace-plan raportuje decyzje planera buforowanego AST w stderr, w tym:
- które rozgrzane cache zostały przeszukane
- czy uruchomiono logikę odświeżania nieaktualnych danych
- liczba plików-kandydatów po zawężeniu na poziomie plików
- ile zbuforowanych drzew zdeserializowano w celu dokładnego dopasowania strukturalnego
Indeks faktów a cache
Oba tryby przyspieszają wyszukiwanie AST, ale są zoptymalizowane pod kątem różnych rodzajów zadań.
| Aspekt | Indeks faktów (ast-index) |
Cache (ast-cache) |
|---|---|---|
| Co jest przechowywane | Wyodrębnione fakty (nazwy wywołań, nazwy klas, deklaracje) | Zserializowane drzewa składniowe |
| Koszt budowy | Niższy | Wyższy (parsuje wszystko) |
| Rozmiar | Mniejszy | Większy |
| Ścieżka zapytania | Filtruj według faktów, a następnie parsuj i dopasowuj kandydatów | Deserializuj drzewo, a następnie dopasuj |
| Najlepsze zastosowanie | Wzorce z rozpoznawalnym początkiem (nazwa wywołania, nazwa klasy) | Wzorce, których cecha wyróżniająca jest strukturalna, a nie nominalna |
| Najgorsze zastosowanie | Wzorce, których początek jest metazmienną | Zimne zapytania dotyczące drzewa, które nie mieści się już w cache stron systemu operacyjnego |
W praktyce indeks faktów zapewnia najszybsze zimne zapytania, a cache — najszybsze ciepłe zapytania. Wybierz rozwiązanie odpowiednie dla swojego obciążenia albo zbuduj oba i pozwól swoim narzędziom wybrać.
Użycie programowe
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 przyjmuje te same AstSearchOptions co natywne wyszukiwanie AST i zwraca dane o takim samym kształcie list<AstMatch>. Jedyna różnica polega na tym, że potok parsera jest pomijany dla plików, które są już w cache. W przypadku przepływów pracy z wieloma indeksami lub manifestem użyj searchAstCachedMany(...) i searchAstCachedSet(...).
Kiedy używać
Tryb buforowanego AST sprawdzi się, gdy:
- Wykonujesz powtarzające się zapytania strukturalne w tej samej bazie kodu.
- Wąskim gardłem w poprzednich uruchomieniach było PHP-Parser (w profilach widoczny jako czas spędzony w lexerze i parserze).
- Masz wystarczająco dużo miejsca na dysku, by przechowywać serializowane drzewa.
Jeśli Twoje zapytania zwykle dotyczą niewielkiej części bazy kodu, a dopasowania koncentrują się wokół rozpoznawalnych nazw wywołań lub klas, indeks faktów zwykle lepiej się sprawdzi. Jeśli zapytania obejmują szeroki zakres bazy kodu, ale możesz ponieść jednorazowy koszt parsowania, lepszy będzie cache.