← 목록
기타 2026-07-24 5KB 읽기 4분

크라우니캔버스 검색 스톨 수리 (P0) — 검색.한선/서버.한선 수리 + 권한.한선 잔여 병목 격리

개요

GET /api/검색?q=... 이 매치 다수일 때 수십초~수분 걸리는 P0 스톨 수리 작업. 소유 범위(지시): 서버.한선 + 검색.한선만 수정. 권한.한선은 타 담당 파일이라 미수정.

무엇을 했는지

1) 검색.한선 — JSON 재파싱 제거

  • 검색_질의_핵심(q, out아이디, out제목, out발췌) 신설: 샤드스캔→중복제거→점수산정→
상위 _결과상한(20) 선택까지의 핵심 로직을 JSON 문자열이 아니라 3개 병렬배열(out-파라미터)로 반환.
  • 검색_질의(q)는 기존 JSON 문자열 반환 시그니처를 유지(자체테스트 호환) — 내부만 핵심 함수 위임으로 리팩터.
  • 검색_질의_객체들(q) 신설 — 이미 완성된 "{...}" JSON 객체 문자열 배열을 직접 반환(권한_검색필터가 바로 소비 가능).

2) 서버.한선 — 재파싱 경로 제거

  • _처리검색검색_질의(q) + _JSON최상위배열분해(결과JSON)(per-char 글자() O(n²) 재파싱) 대신
검색_질의_객체들(q)를 직접 호출하도록 변경 → 결과JSON을 다시 쪼개는 단계 자체를 제거.
  • 이제 쓰이지 않게 된 _JSON최상위배열분해 함수 삭제(사용처 재확인 후 제거, 다른 파일 참조 없음).
  • 결과 캡(_결과상한=20)은 검색.한선 쪽에서 이미 적용 유지, 권한_검색필터 호출은 그대로 유지(요구사항 (2) 충족).

3) 라이브 실측 (재현 → 원인 확정 → 정리)

  • POST /api/페이지생성 반복으로 "Today회의" 제목 141건 실제 생성(150회 시도, 9회는 서버 과부하로 실패) 후
GET /api/검색?q=Today 측정: 64.1s → 72.0s → 타임아웃(31.9s 후 000) — P0 스톨 실측 재현(태스크 명세 "7초"보다 실제 더 심각).
  • 오프라인 격리 프로파일(가져오기 검색.한선 단독)로 검색_질의("Today") 단독 호출은 20ms — 검색.한선 자체 로직은 이미 빠름 확인.
  • 검색_질의_객체들() + 권한_검색필터() 조합 오프라인 프로파일: 59.7초, VM 로그 [STR] 조기경고: 문자열 핸들 432000/480000(90%).
  • 20개 동일 가짜 항목만으로 권한_검색필터() 단독 호출: 56.5초 (검색 로직과 무관하게 재현) — 병목이 권한.한선 내부임을 확정.
  • 권한_확인() 단일 호출 1회: 2.77초. 20회 반복: 56.6초 (≈2.8초/회, 선형).
→ 원인: 권한_확인권한_사용자레벨권한_조상체인권한_페이지행권한_PSV읽기권한_PSV파싱검색결과 항목마다(그리고 조상 단계마다) 데이터/페이지.psv 전체(현재 26.6KB/325행)를 매번 새로 읽고 per-char 글자(내용,i) 루프로 재파싱(가드레일 실측 "글자()=매 호출 O(len)"과 결합해 O(n²)) — 이게 실측 스톨의 지배적 원인. 검색.한선/서버.한선 범위 밖(권한.한선 소유 아님)이라 이번 커밋에서 미수정.
  • 테스트로 만든 141개 페이지/색인 항목은 전부 원복: 페이지.psv 325→184행(생성 시 기록해둔 141개 id만
정확히 필터 제거, 동시 작업 중인 타 세션의 신규 id는 건드리지 않음), 검색인덱스_0~3.psv 동일 방식 정리, 잔여 블록 json 없음 확인. 서버.한선 재컴파일(CROWNY_STRICT=1) → 서버.toau 교체 → launchctl kickstart -k gui/$(id -u)/org.crowny.canvas 로 재기동, /health·/api/부팅·/demo 라이브 200 확인.
  • 정리 후 실측: q=Today(현재 6건 매치) 7.07초 — 여전히 300ms 미달. 매치당 ~1.1~1.2초 비용이
권한.한선 잔여 병목에서 그대로 나옴(검색 자체 로직은 20ms대로 이미 해결).

잔여 이슈 (권한.한선 소유 필요 — 이 작업 범위 밖)

  • 권한_검색필터가 항목마다 권한_페이지행을 호출하면서 데이터/페이지.psv를 매번 통째로 재읽기+재파싱함.
권장 수리 방향: (a) 권한_검색필터 호출 1회당 페이지.psv를 1회만 읽어 파싱한 행 배열을 캐시해 항목마다 재사용, 또는 (b) 권한_PSV파싱의 per-char 글자(내용,i) 루프를 검색.한선에 이미 도입한 버퍼패턴 (문자열버퍼+버퍼찾기+버퍼잘라)으로 교체. 이 수리 전엔 검색 API가 매치 건수에 비례해(건당 ~1.1~2.8초) 계속 느림.

관련 파일

  • /Users/ef/crowny-canvas/한선씨/검색.한선 (검색_질의_핵심/검색_질의_객체들 신설)
  • /Users/ef/crowny-canvas/한선씨/서버.한선 (_처리검색 수정, _JSON최상위배열분해 삭제)
  • /Users/ef/crowny-canvas/서버.toau (재컴파일 반영)
  • /Users/ef/crowny-canvas/한선씨/권한.한선 (원인 위치 — 미수정, 타 담당)
  • /Users/ef/crowny-canvas/데이터/페이지.psv, 데이터/검색인덱스_0~3.psv (테스트 데이터 원복 완료)