Кеширано търсене в 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 (в профилите се вижда като време, прекарано в лексикалния анализатор и анализатора).
- Разполагате с достатъчно дисково пространство за хранилището със сериализирани дървета.
Ако заявките ви обикновено обхващат малка част от кодовата база и съвпаденията са съсредоточени около разпознаваеми имена на извиквания или класове, индексът на факти обикновено е по-подходящ. Ако заявките ви обхващат широко кодовата база, но можете да платите еднократната цена за анализиране, кешът е по-добрият избор.