Przejdź do treści

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

Powłoka
# 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:

Text
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

Powłoka
./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 modyfikuj
  • manual-refresh: zgłaszaj nieaktualny stan w stats, ale nigdy nie odświeżaj podczas wyszukiwania
  • opportunistic-refresh: odświeżaj podczas wyszukiwania tylko wtedy, gdy zbiór zmian nie przekracza skonfigurowanych progów
  • strict-stale-check: odrzucaj nieaktualne wyszukiwania zamiast odświeżać

Wyszukiwanie w pamięci podręcznej

Powłoka
./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.

Powtórz --index-dir, aby przeszukać kilka rozgrzanych pamięci podręcznych w jednym wywołaniu:

Powłoka
./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:

Powłoka
./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

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