"""ASV benchmarks for ChangeSet persistence overhead. Measures the cost of persisting ChangeEntry records and retrieving them via the SqliteChangeSetStore, simulating typical plan execution workloads. """ from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from cleveragents.domain.models.core.change import ( ChangeEntry, ChangeOperation, ) from cleveragents.infrastructure.database.changeset_repository import ( ChangeSetEntryRepository, SqliteChangeSetStore, ) from cleveragents.infrastructure.database.models import Base def _make_factory() -> tuple[sessionmaker[Session], object]: """Create an in-memory SQLite engine + session factory.""" engine = create_engine( "sqlite:///:memory:", echo=False, connect_args={"check_same_thread": False}, ) Base.metadata.create_all(engine) factory: sessionmaker[Session] = sessionmaker(bind=engine) return factory, engine def _make_entry(plan_id: str, idx: int) -> ChangeEntry: return ChangeEntry( plan_id=plan_id, resource_id="res-001", tool_name="file-write", operation=ChangeOperation.CREATE, path=f"src/file_{idx}.py", after_hash=f"hash_{idx:06d}", ) class TimeChangeSetPersistence: """Benchmark suite for ChangeSet persistence operations.""" timeout = 60.0 def setup(self) -> None: self.factory, self.engine = _make_factory() self.store = SqliteChangeSetStore(self.factory) self.plan_id = "bench-plan-001" self.changeset_id = self.store.start(self.plan_id) # Pre-populate for retrieval benchmarks for i in range(50): entry = _make_entry(self.plan_id, i) self.store.record(self.changeset_id, entry) session = self.factory() session.commit() session.close() def time_record_single_entry(self) -> None: """Time recording a single ChangeEntry.""" entry = _make_entry(self.plan_id, 999) self.store.record(self.changeset_id, entry) def time_get_changeset_50_entries(self) -> None: """Time retrieving a changeset with 50 entries.""" self.store.get(self.changeset_id) def time_summarize_changeset(self) -> None: """Time computing summary for a changeset.""" self.store.summarize(self.changeset_id) def time_start_changeset(self) -> None: """Time starting a new empty changeset.""" self.store.start("bench-plan-new") class TimeEntryRepositoryBulk: """Benchmark bulk entry operations.""" timeout = 60.0 def setup(self) -> None: self.factory, self.engine = _make_factory() self.repo = ChangeSetEntryRepository(self.factory) def time_save_100_entries(self) -> None: """Time saving 100 entries sequentially.""" for i in range(100): entry = _make_entry("bench-bulk", i) self.repo.save_entry(f"cs-bulk-{i % 5}", entry) def time_retrieve_by_plan(self) -> None: """Time retrieving all entries for a plan.""" self.repo.get_entries_for_plan("bench-bulk")