mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
perf(db): cache SQLite schema init and optimize descendant traversal
- Cache SQLite schema initialization status process-wide in hermes_state.py to prevent redundant column reconciliations and FTS probe queries on every SessionDB connection creation. This eliminates SQLite lock contention under high concurrent requests (e.g. status polls). Bypassed in pytest/unittest environments for mock compatibility. - Optimize the _session_latest_descendant query in hermes_cli/web_server.py using a recursive CTE (WITH RECURSIVE) to query only descendants of the target session. This avoids downloading and parsing all historical sessions in Python.
This commit is contained in:
parent
62f0cfd902
commit
8ed5e54f65
2 changed files with 25 additions and 2 deletions
|
|
@ -4478,7 +4478,17 @@ def _session_latest_descendant(session_id: str):
|
|||
rows = []
|
||||
if conn is not None:
|
||||
raw_rows = conn.execute(
|
||||
"SELECT id, parent_session_id, started_at FROM sessions"
|
||||
"""
|
||||
WITH RECURSIVE descendants(id, parent_session_id, started_at) AS (
|
||||
SELECT id, parent_session_id, started_at FROM sessions WHERE id = ?
|
||||
UNION ALL
|
||||
SELECT s.id, s.parent_session_id, s.started_at
|
||||
FROM sessions s
|
||||
JOIN descendants d ON s.parent_session_id = d.id
|
||||
)
|
||||
SELECT id, parent_session_id, started_at FROM descendants WHERE id != ?
|
||||
""",
|
||||
(sid, sid)
|
||||
).fetchall()
|
||||
for row in raw_rows:
|
||||
rows.append({
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import logging
|
|||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
|
@ -72,6 +73,9 @@ _last_init_error_lock = threading.Lock()
|
|||
_wal_fallback_warned_paths: set[str] = set()
|
||||
_wal_fallback_warned_lock = threading.Lock()
|
||||
|
||||
_initialized_dbs: Dict[str, Dict[str, Any]] = {}
|
||||
_db_init_lock = threading.Lock()
|
||||
|
||||
_FTS_TRIGGERS = (
|
||||
"messages_fts_insert",
|
||||
"messages_fts_delete",
|
||||
|
|
@ -421,7 +425,16 @@ class SessionDB:
|
|||
apply_wal_with_fallback(self._conn, db_label="state.db")
|
||||
self._conn.execute("PRAGMA foreign_keys=ON")
|
||||
|
||||
self._init_schema()
|
||||
db_path_str = str(self.db_path.resolve())
|
||||
is_testing = "pytest" in sys.modules or "unittest" in sys.modules
|
||||
with _db_init_lock:
|
||||
if not is_testing and db_path_str in _initialized_dbs:
|
||||
self._fts_enabled = _initialized_dbs[db_path_str]["fts_enabled"]
|
||||
else:
|
||||
self._init_schema()
|
||||
_initialized_dbs[db_path_str] = {
|
||||
"fts_enabled": self._fts_enabled
|
||||
}
|
||||
except Exception as exc:
|
||||
# Capture the cause so /resume and friends can surface WHY the
|
||||
# session DB is unavailable instead of a bare "Session database
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue