perf(M01): 로직·조합 목록이 마스터를 한 번만 읽고 막힘은 미리 세어 둠 (일감 32)
- `_Store_Cache` 신설 — 자국(시각·크기)이 바뀐 파일만 다시 읽음 · 목록은 검사를 돌리지 않고 세어 둔 막힘을 씀 - 요소·표가 바뀌면 모든 로직을, 로직 파일이 바뀌면 그 파일과 그 로직을 부르던 줄만 다시 셈 - 저장 뒤에는 고친 파일을 바로 다시 읽게 알려 줌 — 저장 직후 목록 2.5초 → 0.06초 - `/logics` 둘째 번부터 2.5초 → 0.02초 · `/combos` 0.3초 → 0.01초 · 켠 뒤 첫 번만 3.4초 - 시험 `test_m01_cache.py` 다섯 — 세어 둔 막힘이 줄마다 검사한 값과 같음 · 거름 그대로 · 저장 직후 비침 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgUhN55Z3BCYhUJTjwTNfj
This commit is contained in:
@@ -24,6 +24,7 @@ import master_copy as mcp # noqa: E402,F401 (`_Store_Make` 가 `store.mcp` 로
|
||||
import master_keys as mk # noqa: E402
|
||||
import master_text as mtx # noqa: E402
|
||||
|
||||
from M01_MasterData import M01_MasterData_Store_Cache as cache # noqa: E402
|
||||
from M01_MasterData.M01_MasterData_Store_Shape import dump, keep_shape # noqa: E402
|
||||
|
||||
FOLDER: Path = cm.MASTER # 시험은 사본 폴더로 바꿈
|
||||
@@ -56,6 +57,17 @@ def read(file: str) -> tuple[dict, str]:
|
||||
return json.loads(raw, parse_float=Decimal, parse_int=Decimal), version_of(raw)
|
||||
|
||||
|
||||
# ── 한 번 읽어 두기(`_Store_Cache`) ────────────────────────────────────
|
||||
def loaded() -> tuple[dict[str, dict], object]:
|
||||
"""(파일 묶음, 색인) — **읽기 전용**. 고칠 것이면 `cm.load` 로 새로 읽을 것."""
|
||||
return cache.loaded(FOLDER)
|
||||
|
||||
|
||||
def blocks() -> dict[str, list[str]]:
|
||||
"""로직 키마다 막힘 까닭 — 미리 세어 둔 값(목록에서 검사를 돌리지 않음)."""
|
||||
return cache.blocks(FOLDER)
|
||||
|
||||
|
||||
def items_key(data: dict) -> str:
|
||||
return "표" if data.get("그룹") in cm.mf.TABLE_GROUPS else "줄"
|
||||
|
||||
@@ -318,9 +330,10 @@ def _logic_files(files: dict[str, dict]):
|
||||
|
||||
|
||||
def logics(sub: str, detail: str, q: str, blocked: int | None, owner: str = "") -> list[dict]:
|
||||
"""로직 목록 — 구분 · 상세구분 · 소유 · 찾기로 거름(장 차례대로 · 파일을 가로지름)."""
|
||||
files = cm.load(folder=FOLDER)
|
||||
whole = cm.mf.Master(files)
|
||||
"""로직 목록 — 구분 · 상세구분 · 소유 · 찾기로 거름(장 차례대로 · 파일을 가로지름).
|
||||
막힘은 미리 세어 둔 값(`blocks`) — 목록에서 줄마다 검사를 돌리지 않음."""
|
||||
files, _ = loaded()
|
||||
why_of = blocks()
|
||||
out = []
|
||||
for name, data in sorted(_logic_files(files), key=lambda f: f[1].get("차례") or 0):
|
||||
for row in data.get("줄") or []:
|
||||
@@ -330,7 +343,7 @@ def logics(sub: str, detail: str, q: str, blocked: int | None, owner: str = "")
|
||||
continue
|
||||
if not _hit(row, q):
|
||||
continue
|
||||
reasons = cm.mf.check_logic(whole, row)[0]
|
||||
reasons = why_of.get(str(row.get("키")), [])
|
||||
if blocked is not None and bool(reasons) != bool(blocked):
|
||||
continue
|
||||
out.append(
|
||||
@@ -358,11 +371,10 @@ def logics(sub: str, detail: str, q: str, blocked: int | None, owner: str = "")
|
||||
|
||||
def logic(key: str) -> dict:
|
||||
"""로직 하나 — 키는 전체에서 하나."""
|
||||
files = cm.load(folder=FOLDER)
|
||||
files, whole = loaded()
|
||||
for name, data in _logic_files(files):
|
||||
for row in data.get("줄") or []:
|
||||
if str(row.get("키")) == key:
|
||||
whole = cm.mf.Master(files)
|
||||
reasons = cm.mf.check_logic(whole, row)[0]
|
||||
_, version = read(name)
|
||||
return {
|
||||
@@ -427,7 +439,7 @@ def elements(group: str, q: str, limit: int) -> dict:
|
||||
if group not in cm.mf.GROUPS:
|
||||
raise StoreError(404, f"없는 그룹 「{group}」")
|
||||
hits = []
|
||||
for name, data in cm.load(folder=FOLDER).items():
|
||||
for name, data in loaded()[0].items():
|
||||
if data.get("그룹") != group:
|
||||
continue
|
||||
for row in data.get(items_key(data)) or []:
|
||||
@@ -491,7 +503,7 @@ def materials(sub: str, detail: str, spec: str, region: str, unit: str, limit: i
|
||||
"""재료 고르기 조건 안 후보 목록 — 화면·테스트 컨테이너가 같이 씀.
|
||||
`unit` = 호표 줄 단위 — 주면 그 단위 줄만(단위가 다르면 다른 물건).
|
||||
`기본` = 시험 계산이 쓸 줄(대표 줄이 없을 때의 첫 줄) · 그 줄을 `items` 맨 앞에 둠."""
|
||||
whole = cm.master(folder=FOLDER)
|
||||
whole = loaded()[1]
|
||||
cond = {"구분": sub, "상세구분": detail or None, "규격": spec or None}
|
||||
env = {cm.mf.REGION: region} if region else {}
|
||||
keys = cm.mf.candidates(whole, cond, env, unit or None)
|
||||
@@ -664,4 +676,5 @@ def save(batch: list[dict]) -> list[dict]:
|
||||
tmp.write_text(text, encoding="utf-8", newline="\n")
|
||||
os.replace(tmp, FOLDER / name)
|
||||
out.append({"file": name, "version": version_of(text.encode("utf-8"))})
|
||||
cache.stale(dict.fromkeys(names)) # 저장 뒤에는 그 파일을 바로 다시 읽게
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user