
# Buforowane wyszukiwanie AST

Buforowane wyszukiwanie AST to uzupełniający tryb z rozgrzaną pamięcią podręczną, działający obok [indeksu faktów](https://greph.inline0.dev/pl/docs/indexed/ast). 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

```bash
# 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

```bash
./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

```bash
./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`](https://greph.inline0.dev/pl/docs/indexed/ast#querying-the-index), 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:

```bash
./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:

```bash
./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](https://greph.inline0.dev/pl/docs/indexed/ast) zwykle lepiej się sprawdzi. Jeśli zapytania obejmują szeroki zakres bazy kodu, ale możesz ponieść jednorazowy koszt parsowania, lepszy będzie cache.
