2121import re
2222import sqlite3
2323import tempfile
24+ import threading
25+ from contextlib import contextmanager
2426from pathlib import Path
2527from typing import Any , Iterator
2628
@@ -356,7 +358,8 @@ class LocalRegistry:
356358 SQLite-backed run registry.
357359
358360 Provides efficient storage and querying of run metadata with
359- indexed fields for common query patterns.
361+ indexed fields for common query patterns. Uses thread-local
362+ connection pooling for better performance.
360363
361364 Parameters
362365 ----------
@@ -371,17 +374,18 @@ def __init__(self, root: Path, timeout: float = 30.0) -> None:
371374 self .root .mkdir (parents = True , exist_ok = True )
372375 self .db_path = self .root / "registry.db"
373376 self ._timeout = timeout
377+ self ._local = threading .local ()
374378 self ._init_db ()
375379 logger .debug ("LocalRegistry initialized at %s" , self .db_path )
376380
377- def _get_connection (self ) -> sqlite3 .Connection :
381+ def _create_connection (self ) -> sqlite3 .Connection :
378382 """
379- Get a database connection with standard settings.
383+ Create a new database connection with standard settings.
380384
381385 Returns
382386 -------
383387 sqlite3.Connection
384- Connection with row_factory set to sqlite3.Row.
388+ New connection with row_factory set to sqlite3.Row.
385389 """
386390 conn = sqlite3 .connect (self .db_path , timeout = self ._timeout )
387391 conn .row_factory = sqlite3 .Row
@@ -390,6 +394,28 @@ def _get_connection(self) -> sqlite3.Connection:
390394 conn .execute ("PRAGMA busy_timeout=30000" )
391395 return conn
392396
397+ @contextmanager
398+ def _get_connection (self ):
399+ """
400+ Get a thread-local database connection.
401+
402+ Uses connection pooling per thread for better performance.
403+ Connections are reused within the same thread.
404+
405+ Yields
406+ ------
407+ sqlite3.Connection
408+ Database connection.
409+ """
410+ if not hasattr (self ._local , "conn" ) or self ._local .conn is None :
411+ self ._local .conn = self ._create_connection ()
412+ try :
413+ yield self ._local .conn
414+ self ._local .conn .commit ()
415+ except Exception :
416+ self ._local .conn .rollback ()
417+ raise
418+
393419 def _init_db (self ) -> None :
394420 """Initialize database schema."""
395421 with self ._get_connection () as conn :
@@ -1144,6 +1170,17 @@ def clear_baseline(self, project: str) -> bool:
11441170 return True
11451171 return False
11461172
1173+ def close (self ) -> None :
1174+ """
1175+ Close the thread-local database connection if open.
1176+
1177+ This is optional - connections are automatically closed when
1178+ the thread terminates.
1179+ """
1180+ if hasattr (self ._local , "conn" ) and self ._local .conn is not None :
1181+ self ._local .conn .close ()
1182+ self ._local .conn = None
1183+
11471184
11481185class LocalWorkspace :
11491186 """
@@ -1196,8 +1233,8 @@ def registry(self) -> LocalRegistry:
11961233 return self ._registry
11971234
11981235 def close (self ) -> None :
1199- """Close the workspace (no-op for local storage) ."""
1200- pass
1236+ """Close the workspace and release resources ."""
1237+ self . _registry . close ()
12011238
12021239 def __enter__ (self ) -> LocalWorkspace :
12031240 """Enter context manager."""
0 commit comments