Fix blocking I/O on event loop, cache graphviz, optimize DB sync
Move all save_json/load_json/sync_to_db/DB calls off the event loop with asyncio.to_thread to prevent UI freezes. Cache graphviz SVG by DOT source hash (bounded LRU of 20). Replace DELETE-all/re-INSERT in sync_to_db with UPSERT + targeted DELETE. Add DB indexes, COUNT query, and reduce graph poll interval to 0.5s. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -184,11 +184,11 @@ def sync_to_db(db, project_name: str, file_path: Path, data: dict) -> None:
|
||||
# Use a single transaction for atomicity
|
||||
db.conn.execute("BEGIN IMMEDIATE")
|
||||
try:
|
||||
now = time.time()
|
||||
df = db.get_data_file(proj["id"], file_name)
|
||||
top_level = {k: v for k, v in data.items()
|
||||
if k not in (KEY_BATCH_DATA, KEY_HISTORY_TREE)}
|
||||
if not df:
|
||||
now = time.time()
|
||||
cur = db.conn.execute(
|
||||
"INSERT INTO data_files (project_id, name, data_type, top_level, created_at, updated_at) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?)",
|
||||
@@ -198,7 +198,6 @@ def sync_to_db(db, project_name: str, file_path: Path, data: dict) -> None:
|
||||
else:
|
||||
df_id = df["id"]
|
||||
# Update top_level metadata
|
||||
now = time.time()
|
||||
db.conn.execute(
|
||||
"UPDATE data_files SET top_level = ?, updated_at = ? WHERE id = ?",
|
||||
(json.dumps(top_level), now, df_id),
|
||||
@@ -207,23 +206,31 @@ def sync_to_db(db, project_name: str, file_path: Path, data: dict) -> None:
|
||||
# Sync sequences
|
||||
batch_data = data.get(KEY_BATCH_DATA, [])
|
||||
if isinstance(batch_data, list):
|
||||
db.conn.execute("DELETE FROM sequences WHERE data_file_id = ?", (df_id,))
|
||||
new_seq_nums = set()
|
||||
for item in batch_data:
|
||||
if not isinstance(item, dict):
|
||||
continue
|
||||
seq_num = int(item.get(KEY_SEQUENCE_NUMBER, 0))
|
||||
now = time.time()
|
||||
new_seq_nums.add(seq_num)
|
||||
db.conn.execute(
|
||||
"INSERT INTO sequences (data_file_id, sequence_number, data, updated_at) "
|
||||
"VALUES (?, ?, ?, ?) "
|
||||
"ON CONFLICT(data_file_id, sequence_number) DO UPDATE SET data=excluded.data, updated_at=excluded.updated_at",
|
||||
(df_id, seq_num, json.dumps(item), now),
|
||||
)
|
||||
# Remove sequences that no longer exist
|
||||
if new_seq_nums:
|
||||
placeholders = ','.join('?' * len(new_seq_nums))
|
||||
db.conn.execute(
|
||||
f"DELETE FROM sequences WHERE data_file_id = ? AND sequence_number NOT IN ({placeholders})",
|
||||
(df_id, *new_seq_nums),
|
||||
)
|
||||
else:
|
||||
db.conn.execute("DELETE FROM sequences WHERE data_file_id = ?", (df_id,))
|
||||
|
||||
# Sync history tree
|
||||
history_tree = data.get(KEY_HISTORY_TREE)
|
||||
if history_tree and isinstance(history_tree, dict):
|
||||
now = time.time()
|
||||
db.conn.execute(
|
||||
"INSERT INTO history_trees (data_file_id, tree_data, updated_at) "
|
||||
"VALUES (?, ?, ?) "
|
||||
|
||||
Reference in New Issue
Block a user