본문으로 건너뛰기

캐시된 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/에 저장됩니다. 세 가지 인덱스 모드 중 캐시 빌드는 일반적으로 가장 느립니다. 모든 파일을 한 번씩 파싱해야 하기 때문입니다.

빌드에 성공하면 한 줄 요약이 출력됩니다:

Text
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

누락된 캐시를 위한 --fallback scan를 포함해 플래그는 ast-index search와 동일합니다.

한 번의 호출로 여러 사전 준비 캐시를 검색하려면 --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)
저장되는 내용 추출된 사실 (호출 이름, 클래스 이름, 선언) 직렬화된 파싱 트리
빌드 비용 낮음 높음 (모든 항목을 파싱)
빌드 크기 작음 큼
쿼리 경로 사실로 필터링한 다음 후보를 파싱하고 매칭 트리를 역직렬화한 다음 매칭
적합한 경우 알아볼 수 있는 헤드 (호출 이름, 클래스 이름)가 있는 패턴 구별되는 특징이 이름이 아니라 구조인 패턴
부적합한 경우 헤드가 메타변수인 패턴 OS 페이지 캐시에 더 이상 들어가지 않는 트리에 대한 콜드 쿼리

실제로 사실 인덱스는 콜드 쿼리가 가장 빠르고 캐시는 웜 쿼리가 가장 빠릅니다. 워크로드에 맞는 것을 사용하거나 둘 다 빌드한 뒤 도구에서 선택하게 하세요.

프로그래밍 방식 사용

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은 네이티브 AST 검색과 동일한 AstSearchOptions을 받아들이고 같은 list<AstMatch> 형태를 반환합니다. 이미 캐시에 있는 파일에서는 파서 파이프라인을 우회한다는 점만 다릅니다. 여러 인덱스 또는 매니페스트 기반 흐름에는 searchAstCachedMany(...)와 searchAstCachedSet(...)를 사용하세요.

사용 시점

캐시된 AST 모드는 다음과 같은 경우에 적합합니다:

  • 동일한 코드베이스를 대상으로 구조 쿼리를 반복해서 실행합니다.
  • 이전 실행의 병목이 PHP-Parser이었습니다 (프로파일에서 렉서와 파서에 소요된 시간으로 확인 가능).
  • 직렬화된 트리 저장소에 필요한 디스크 공간을 확보할 수 있습니다.

쿼리가 보통 코드베이스의 일부만 대상으로 하고 매치가 알아볼 수 있는 호출 이름이나 클래스 이름에 집중된다면 사실 인덱스가 대체로 더 적합합니다. 쿼리가 코드베이스 전반을 폭넓게 대상으로 하지만 일회성 파싱 비용을 감당할 수 있다면 캐시가 더 유리합니다.