Кэшированный поиск по AST
Кэшированный поиск по AST дополняет режим с прогретым кэшем индекса фактов. Вместо хранения извлеченных фактов и повторного анализа найденных файлов кэш сохраняет сериализованные деревья разбора на диске. Последующие запросы десериализуют деревья и запускают средство сопоставления напрямую, полностью пропуская конвейер PHP-Parser.
Кэш доступен через подкоманду greph-index ast-cache CLI и методы фасада Greph::buildAstCache() / Greph::searchAstCached(). Также поддерживается поиск по нескольким индексам и наборам на основе манифеста.
Создание кэша
# 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
По умолчанию кэш хранится в <root>/.greph-ast-cache/. Создание кэша обычно занимает больше всего времени среди трех режимов индексирования, поскольку каждый файл нужно разобрать один раз.
После успешного создания выводится сводка в одну строку:
Built AST cache for 2547 files in .greph-ast-cache (2541 cached trees, +2541 ~0 -0 =0)
Количество кэшированных деревьев обычно немного меньше числа файлов: файлы, которые не удалось разобрать (и которые пропускаются без предупреждения), не попадают в кэш. Передайте --strict-parse в команде поиска, если нужно выводить ошибки разбора.
Обновление кэша
./vendor/bin/greph-index ast-cache refresh .
refresh повторно обходит корневой каталог индекса, заново анализирует измененные файлы и перезаписывает только изменившиеся кэшированные деревья.
Профили жизненного цикла работают так же, как в других прогретых режимах:
static: никогда автоматически не проверяет актуальность и не изменяет данныеmanual-refresh: сообщает об устаревшем состоянии вstats, но не обновляет кэш во время поискаopportunistic-refresh: обновляет кэш во время поиска, только если набор изменений не превышает заданные порогиstrict-stale-check: отклоняет поиск с устаревшими данными вместо обновления
Запросы к кэшу
./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
Набор параметров такой же, как в ast-index search, включая --fallback scan для отсутствующего кэша.
Поиск по кэшу нескольких индексов
Повторите --index-dir, чтобы выполнить запрос сразу к нескольким прогретым кэшам:
./vendor/bin/greph-index ast-cache search \
--index-dir ../wordpress/.greph-ast-cache \
--index-dir ./.greph-ast-cache \
--show-index-origin \
'array($$$ITEMS)' .
Наборы кэшей на основе манифеста
Если вы уже используете именованные наборы прогретых индексов, тот же манифест можно применить для поиска по кэшированному 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)' .
Диагностика планировщика
--trace-plan выводит решения планировщика кэшированного AST в stderr, включая:
- какие прогретые кэши были проверены
- запускалась ли логика обновления устаревших данных
- количество файлов-кандидатов после сужения на уровне файлов
- сколько кэшированных деревьев было десериализовано для точного структурного сопоставления
Кэш и индекс фактов
Оба режима ускоряют поиск по AST, но оптимизированы для разных типов задач.
| Аспект | Индекс фактов (ast-index) |
Кэш (ast-cache) |
|---|---|---|
| Что хранится | Извлеченные факты (имена вызовов, имена классов, объявления) | Сериализованные разобранные деревья |
| Стоимость построения | Ниже | Выше (разбирает всё) |
| Размер при построении | Меньше | Больше |
| Путь запроса | Фильтрация по фактам, затем разбор и сопоставление кандидатов | Десериализация дерева, затем сопоставление |
| Лучше всего подходит для | Шаблонов с распознаваемой начальной частью (имя вызова, имя класса) | Шаблонов, отличительный признак которых структурный, а не именной |
| Хуже всего подходит для | Шаблонов, начальная часть которых — метапеременная | Холодных запросов к дереву, которое больше не помещается в кэш страниц ОС |
На практике индекс фактов обеспечивает самый быстрый холодный запрос, а кэш — самый быстрый прогретый запрос. Выберите вариант, подходящий для вашей нагрузки, или создайте оба и позвольте своим инструментам выбрать.
Программное использование
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 принимает те же AstSearchOptions, что и нативный поиск по AST, и возвращает результаты в той же форме list<AstMatch>. Отличие только в том, что для файлов, уже находящихся в кэше, конвейер парсера обходится. Для потоков с несколькими индексами или на основе манифеста используйте searchAstCachedMany(...) и searchAstCachedSet(...).
Когда использовать
Режим кэшированного AST подходит, когда:
- Вы многократно выполняете структурные запросы к одной и той же кодовой базе.
- Узким местом в предыдущих запусках было PHP-Parser (в профилях видно время, затраченное лексером и парсером).
- Вы можете выделить место на диске для хранилища сериализованных деревьев.
Если ваши запросы обычно охватывают небольшую часть кодовой базы, а совпадения сосредоточены вокруг распознаваемых имен вызовов или классов, индекс фактов обычно подходит лучше. Если запросы охватывают большую часть кодовой базы, но вы готовы один раз заплатить за разбор, лучше использовать кэш.