perf(영구저장): 343-2 도엽 3D 면 열쇠 · 지표면 모델 id 유지 · 비용면 메모리 기억 · 추천 노선 열쇠 · 횡단 상세 ETag
- 도엽 3D 면 — 결과 옆 dtm_sheet_{방식}.key.json(등고선 이름:mtime:크기 · 노선 · CRS · 격자 · 여유 · 스무딩 · 화면 상자 · ALGO) 같으면 건너뜀
- 지표면 모델 — (방식 · 필터 · 파일) + 파일 지문 같으면 행 id 살려 고쳐 씀 · 이번 결과에 없는 옛 행만 지움
- 비용면 · 계류 메모리 기억(비용면 서명 · 계류 파일 지문 · 좌표계) · 추천 열쇠 = 서명(배열 통째 해시 없앰)
- 추천 저장본 종류(갈래 · 지형)당 최근 2벌 · 꺼내면 최근으로
- 횡단 상세 GET — 측점 파일 안 지움(valid_cross_names) · 본문 해시 ETag 304
- 시험 test_343_2_persist_keys 13건
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
This commit is contained in:
@@ -109,12 +109,19 @@ MODE_WEIGHTS = {
|
||||
# 후보 묶음은 갈래와 무관 — 같은 입력이면 다시 짜지 않음(최근 몇 벌만 · 프로세스 메모리)
|
||||
POOL_CACHE_SIZE = 4
|
||||
_POOLS: dict[bytes, Pool] = {}
|
||||
# 비용면 · 계류 기억(요청 사이) — 열쇠 = 프로젝트 · 비용면 서명 · 계류 파일 지문 · 좌표계
|
||||
TERRAIN_CACHE_SIZE = 4
|
||||
_TERRAINS: dict[str, tuple[Terrain, list[list[tuple[float, float]]]]] = {}
|
||||
|
||||
|
||||
def load_terrain_and_streams(
|
||||
project_root: Path, selection: dict[str, Any]
|
||||
) -> tuple[Terrain, list[list[tuple[float, float]]]]:
|
||||
"""지반 격자(탐색 비용면 캐시 그대로)와 이격을 따질 계류(사업지 좌표계)를 읽는다."""
|
||||
"""지반 격자(탐색 비용면 캐시 그대로)와 이격을 따질 계류(사업지 좌표계)를 읽는다.
|
||||
|
||||
같은 입력(비용면 서명 · 계류 파일 지문 · 좌표계)이면 메모리 기억을 그대로 돌려준다 —
|
||||
점 놓을 때마다 npz · geojson 을 다시 읽지 않는다. 돌려준 배열은 고치지 않는다.
|
||||
"""
|
||||
from pyproj import Transformer
|
||||
|
||||
from B04_PreProcess.B04_PreProcess_Router_Watershed import (
|
||||
@@ -122,20 +129,49 @@ def load_terrain_and_streams(
|
||||
_load_features,
|
||||
_reproject_features,
|
||||
)
|
||||
from B05_Profile.B05_Profile_Engine_Solver import _MODELS_SUBDIR, _load_or_build_cost_surface
|
||||
from B05_Profile.B05_Profile_Engine_Solver import (
|
||||
_MODELS_SUBDIR,
|
||||
_cost_surface_signature,
|
||||
_load_or_build_cost_surface,
|
||||
)
|
||||
from common_util.common_util_crs import resolve_project_crs
|
||||
|
||||
x, y, z, valid, *_ = _load_or_build_cost_surface(
|
||||
project_root,
|
||||
project_root / _MODELS_SUBDIR,
|
||||
str(selection.get("source_filter")),
|
||||
str(selection.get("method") or "dtm"),
|
||||
bool(selection.get("smooth")),
|
||||
filter_key = str(selection.get("source_filter"))
|
||||
method = str(selection.get("method") or "dtm")
|
||||
smooth = bool(selection.get("smooth"))
|
||||
models_dir = project_root / _MODELS_SUBDIR
|
||||
stream_path = project_root / "B04_PreProcess" / "processed" / STREAM_FILE
|
||||
crs = resolve_project_crs(project_root)
|
||||
try:
|
||||
stat = stream_path.stat()
|
||||
stream_stamp = f"{stat.st_mtime_ns}:{stat.st_size}"
|
||||
except OSError:
|
||||
stream_stamp = "-"
|
||||
signature = "|".join(
|
||||
(
|
||||
filter_key,
|
||||
_cost_surface_signature(models_dir, filter_key, method, smooth),
|
||||
stream_stamp,
|
||||
str(crs),
|
||||
)
|
||||
)
|
||||
to_metric = Transformer.from_crs("EPSG:4326", resolve_project_crs(project_root), always_xy=True)
|
||||
features = _load_features(project_root / "B04_PreProcess" / "processed", STREAM_FILE)
|
||||
memo_key = f"{project_root}|{signature}"
|
||||
if memo_key in _TERRAINS:
|
||||
return _TERRAINS[memo_key]
|
||||
|
||||
x, y, z, valid, *_ = _load_or_build_cost_surface(
|
||||
project_root, models_dir, filter_key, method, smooth
|
||||
)
|
||||
to_metric = Transformer.from_crs("EPSG:4326", crs, always_xy=True)
|
||||
features = _load_features(stream_path.parent, STREAM_FILE)
|
||||
streams = stream_lines(_reproject_features(features, to_metric))
|
||||
return Terrain(np.asarray(x), np.asarray(y), np.asarray(z), np.asarray(valid)), streams
|
||||
terrain = Terrain(
|
||||
np.asarray(x), np.asarray(y), np.asarray(z), np.asarray(valid), signature=signature
|
||||
)
|
||||
while len(_TERRAINS) >= TERRAIN_CACHE_SIZE:
|
||||
_TERRAINS.pop(next(iter(_TERRAINS)))
|
||||
_TERRAINS[memo_key] = (terrain, streams)
|
||||
return terrain, streams
|
||||
|
||||
|
||||
def _choice_path(project_root: Path) -> Path:
|
||||
@@ -378,8 +414,16 @@ def _pool_key(
|
||||
streams: list[list[tuple[float, float]]],
|
||||
*numbers: float,
|
||||
) -> bytes:
|
||||
"""후보 묶음을 가를 입력 지문 — 지형 · 예상노선 · 계류 · 제약 값."""
|
||||
"""후보 묶음을 가를 입력 지문 — 지형 · 예상노선 · 계류 · 제약 값.
|
||||
|
||||
지형에 입력 지문(`signature` — 비용면 서명 + 계류 파일)이 있으면 배열 통째 해시 대신 씀.
|
||||
"""
|
||||
digest = hashlib.blake2b(digest_size=16)
|
||||
if terrain.signature:
|
||||
digest.update(terrain.signature.encode())
|
||||
digest.update(np.ascontiguousarray(np.asarray(expected)).tobytes())
|
||||
digest.update(repr(numbers).encode())
|
||||
return digest.digest()
|
||||
for array in (terrain.x, terrain.y, terrain.z, terrain.valid, np.asarray(expected)):
|
||||
digest.update(np.ascontiguousarray(array).tobytes())
|
||||
digest.update(repr((streams, numbers)).encode())
|
||||
|
||||
Reference in New Issue
Block a user