Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/cli/commands/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,22 @@ def _maybe_refresh_index(cwd: Path, cfg) -> None:
if building_marker.exists():
logger.info("index.skip_async_build_in_progress")
return
workers = getattr(cfg, "index_build_workers", 0)
batch_size = getattr(cfg, "index_build_batch_size", 1000)
try:
from state.file_index import IndexBuilder, _last_indexed_sha

if not db_path.exists():
IndexBuilder.build_full(cwd, db_path)
IndexBuilder.build_full(
cwd, db_path, workers=workers, batch_size=batch_size
)
else:
IndexBuilder.build_incremental(
cwd, db_path, since_sha=_last_indexed_sha(db_path)
cwd,
db_path,
since_sha=_last_indexed_sha(db_path),
workers=workers,
batch_size=batch_size,
)
except Exception as exc: # noqa: BLE001 - never block on index failure
logger.warning("index.refresh_failed", err=str(exc))
Expand Down
11 changes: 10 additions & 1 deletion src/cli/commands/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,10 @@ def init(platform: str, force: bool, inline: bool, rebuild_index: bool) -> None:
str(cwd),
"--db",
str(db_path),
"--workers",
str(cfg.index_build_workers),
"--batch-size",
str(cfg.index_build_batch_size),
]
subprocess.Popen( # noqa: S603 - executable is sys.executable
cmd,
Expand All @@ -221,7 +225,12 @@ def init(platform: str, force: bool, inline: bool, rebuild_index: bool) -> None:
)
else:
with console.status("Building file/symbol index..."):
stats = IndexBuilder.build_full(cwd, db_path)
stats = IndexBuilder.build_full(
cwd,
db_path,
workers=cfg.index_build_workers,
batch_size=cfg.index_build_batch_size,
)
index_summary = (
f"{stats.file_count} files, {stats.symbol_count} symbols "
f"({stats.duration_ms} ms)"
Expand Down
12 changes: 10 additions & 2 deletions src/cli/commands/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,22 @@ def _maybe_refresh_index(cwd: Path, cfg) -> None:
if building_marker.exists():
logger.info("index.skip_async_build_in_progress")
return
workers = getattr(cfg, "index_build_workers", 0)
batch_size = getattr(cfg, "index_build_batch_size", 1000)
try:
from state.file_index import IndexBuilder, _last_indexed_sha

if not db_path.exists():
IndexBuilder.build_full(cwd, db_path)
IndexBuilder.build_full(
cwd, db_path, workers=workers, batch_size=batch_size
)
else:
IndexBuilder.build_incremental(
cwd, db_path, since_sha=_last_indexed_sha(db_path)
cwd,
db_path,
since_sha=_last_indexed_sha(db_path),
workers=workers,
batch_size=batch_size,
)
except Exception as exc: # noqa: BLE001 - never block on index failure
logger.warning("index.refresh_failed", err=str(exc))
Expand Down
12 changes: 10 additions & 2 deletions src/cli/commands/resume.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,22 @@ def _maybe_refresh_index(cwd: Path, cfg) -> None:
if building_marker.exists():
logger.info("index.skip_async_build_in_progress")
return
workers = getattr(cfg, "index_build_workers", 0)
batch_size = getattr(cfg, "index_build_batch_size", 1000)
try:
from state.file_index import IndexBuilder, _last_indexed_sha

if not db_path.exists():
IndexBuilder.build_full(cwd, db_path)
IndexBuilder.build_full(
cwd, db_path, workers=workers, batch_size=batch_size
)
else:
IndexBuilder.build_incremental(
cwd, db_path, since_sha=_last_indexed_sha(db_path)
cwd,
db_path,
since_sha=_last_indexed_sha(db_path),
workers=workers,
batch_size=batch_size,
)
except Exception as exc: # noqa: BLE001 - never block on index failure
logger.warning("index.refresh_failed", err=str(exc))
Expand Down
27 changes: 20 additions & 7 deletions src/config/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -1030,13 +1030,26 @@ class AutodevConfig(BaseModel):
index_full_rebuild_threshold_files: int = Field(
default=5000, ge=100, le=100_000
)
# On huge repos (``RepoCapacity.is_huge``) the initial full build can
# take minutes. When True (default), ``autodev init`` spawns the
# builder in a background subprocess and returns immediately; the
# ``.autodev/index.db.building`` marker file signals to the per-trigger
# incremental hook that it should skip until the build completes.
# Set False to force synchronous initial build even on huge repos.
index_huge_repo_async_init: bool = True
# Number of worker processes used by ``IndexBuilder.build_full`` to
# parse files in parallel (the parse stage is CPU- and GIL-bound, so
# processes, not threads). ``0`` (default) = ``os.cpu_count() or 1``;
# ``1`` forces the serial in-process parse. Workers feed a single
# bulk-loading sqlite writer in the parent.
index_build_workers: int = Field(default=0, ge=0)
# Files per write transaction during a full bulk build. Bounds the WAL
# so a huge repo doesn't accumulate one giant single-transaction blob
# (the pre-parallel builder produced a ~600 MB WAL that only flushed at
# the end). Lower it on memory-constrained hosts.
index_build_batch_size: int = Field(default=1000, ge=1)
# On huge repos (``RepoCapacity.is_huge``) the initial full build used
# to take minutes, so it was spawned in a background subprocess. Now
# that the build is parallel + bulk-loaded it is fast enough to run
# synchronously, so the default is False (sync). Set True to restore
# the opt-in async escape hatch: ``autodev init`` spawns the builder in
# a background subprocess and returns immediately; the
# ``.autodev/index.db.building`` marker signals the per-trigger
# incremental hook to skip until the build completes.
index_huge_repo_async_init: bool = False

# v0.30.0 Bug 5: cross-task infrastructure-failure circuit breaker.
# Counts adapter failures whose ``subtype`` is in
Expand Down
Loading
Loading