SPB Git

spb/findata

Public

raise open-file limit for wide scans; date-only SQL scopes use the catalog too

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Nov 2, 2026) parent 6665d8e Browse files

2 changed files +11 −4

modified infra/scripts/run-under-sshd.sh +1 −1
@@ -26,7 +26,7 @@ if [ -f "$PIDFILE" ]; then
26 26 fi
27 27 fi
28 28 CMD=$(printf '%q ' "$@")
29 −"${SSH[@]}" "cd $(printf '%q' "$WORKDIR") && export PATH=$REMOTE_PATH FINDATA_ROOT=$(printf '%q' "$WORKDIR") PYTHONUNBUFFERED=1 && echo \$\$ > $(printf '%q' "$PIDFILE") && exec $CMD" &
29 +"${SSH[@]}" "ulimit -n 65536 2>/dev/null; cd $(printf '%q' "$WORKDIR") && export PATH=$REMOTE_PATH FINDATA_ROOT=$(printf '%q' "$WORKDIR") PYTHONUNBUFFERED=1 && echo \$\$ > $(printf '%q' "$PIDFILE") && exec $CMD" &
30 30 SSHPID=$!
31 31 stop() {
32 32 REMOTE=$(cat "$PIDFILE" 2>/dev/null)
modified services/ingest/src/findata_ingest/reader.py +10 −3
@@ -21,6 +21,13 @@ from findata_ingest.lake import Lake, live_files
21 21
22 22
23 23 def _con(read_only: bool = True) -> duckdb.DuckDBPyConnection:
24 + import resource
25 + try: # scans over many Parquet files need file descriptors (macOS default soft limit is 256)
26 + soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
27 + if soft < 65536:
28 + resource.setrlimit(resource.RLIMIT_NOFILE, (min(65536, hard), hard))
29 + except (ValueError, OSError):
30 + pass
24 31 con = duckdb.connect(database=":memory:", config={"threads": 4, "memory_limit": "4GB", "TimeZone": "UTC"})
25 32 return con
26 33
@@ -243,12 +250,12 @@ def extract_scope(sql: str) -> dict[str, Any]:
243 250
244 251 def scoped_view_sql(dataset_id: str, kind: str, scope: dict[str, Any], lake: Lake) -> str | None:
245 252 """Explicit file list from the catalog for symbol-scoped statements (fast path). None → use the glob view."""
246 − if not scope["symbols"]:
253 + if not scope["symbols"] and not (scope["start"] or scope["end"]):
247 254 return None
248 255 with connection() as conn:
249 − files = live_files(conn, dataset_id, scope["symbols"], scope["start"], scope["end"])
256 + files = live_files(conn, dataset_id, scope["symbols"] or None, scope["start"], scope["end"])
250 257 if len(files) > 20000:
251 − return None
258 + return None # too broad for an explicit list: directory scan instead
252 259 if not files:
253 260 return "SELECT * FROM (VALUES (NULL)) t(empty) WHERE false"
254 261 lst = ", ".join("'" + str(lake.resolve(f["path"])).replace("'", "''") + "'" for f in files)
255 262
Menu

Theme