Skip to content

feat: fast reload optimization — skip Bazel discovery on window reload#20

Merged
monkey666-cr merged 9 commits into
monkey666-cr:mainfrom
runchen0919:feat/fast-reload-optimization
May 20, 2026
Merged

feat: fast reload optimization — skip Bazel discovery on window reload#20
monkey666-cr merged 9 commits into
monkey666-cr:mainfrom
runchen0919:feat/fast-reload-optimization

Conversation

@runchen0919
Copy link
Copy Markdown
Contributor

@runchen0919 runchen0919 commented May 19, 2026

Summary

  • Fast reload path: Skip full Bazel discovery on VS Code window reload by persisting projects in .bazel-projects/ and reusing cached classpath data
  • Batch classpath init: Batch container prefill and classpath initialization to reduce JDT.LS overhead during import
  • Eliminate post-import Searching: Pre-set JDT.LS state before import to avoid redundant workspace indexing
  • Bug fixes: Fix stale artifact handling, deduplicate missing JAR warnings, and eagerly create redb tables to prevent errors on reload

Changes

File Description
BazelProjectImporter.java Fast reload detection, batch import, pre-set JDT state
BazelProjectCreator.java Project persistence in .bazel-projects/, skip redundant creation
BazelClasspathManager.java New batch classpath initialization manager
BazelClasspathContainerInitializer.java Suppress during import, batch prefill support
BazelClasspathContainer.java Skip redundant updates, empty container for stale artifacts
TargetProjectMapping.java Project-target mapping persistence and restore
BazelCommandHandler.java New JNI command routing for fast reload
redb_store.rs Eager table creation, prevent TableDoesNotExist on reload
statusBar.ts Status bar updates for reload progress

Test plan

  • Fresh import of a Bazel project works correctly
  • Window reload (Cmd+Shift+P → Reload Window) uses fast path and skips Bazel discovery
  • Classpath resolution works after fast reload
  • Adding/removing dependencies triggers proper incremental sync
  • No regressions in existing import flow

🤖 Generated with Claude Code

runchen0919 and others added 9 commits May 18, 2026 15:29
…tExist on reload

BazelCache::open() created the database file but never created tables.
Read transactions (used by load_all_classpaths on startup) cannot create
tables in redb, causing "Table 'classpath' does not exist" errors on
every VS Code Reload Window — forcing a full 18s re-import instead of
using cached data.

- Add ensure_tables_exist() called after every Database::create path
- Add TableDoesNotExist defense-in-depth to all read-only methods

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… noise

During reload, identical "Skipping non-existent JAR" warnings were emitted
once per target sharing the same missing dependency (293 warnings for 8
unique JARs). Use a static ConcurrentHashMap-backed set to log each unique
missing path only once. The set is cleared on classpath refresh so warnings
resurface after reimport if the JAR is still missing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…le artifacts

During reload, recoverFromCache() would construct a container from
stale cached entries (JARs cleaned from bazel-out/) and set it even
when all entries were invalid. Now explicitly sets EMPTY container
and logs an info message, preventing JDT from re-invoking initialize()
and making the stale-cache scenario visible in logs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When cached state from a previous session exists (project index +
workspace config + classpath cache files), importToWorkspace() now
restores projects from file caches (~2-3s) instead of running the
full 3-phase Bazel discovery pipeline (~16s). A background Job then
runs the full pipeline asynchronously to pick up any BUILD changes.

Key changes:
- TargetProjectMapping: file-based workspace config persistence,
  project index (_index) for enumerating cached projects, shared
  getStateDir() helper
- BazelClasspathContainerInitializer: always try file cache first
  via tryRecoverFromCache(), regardless of bridge initialization state
- BazelProjectImporter: tryFastReload() fast path + background
  refresh scheduling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rity

Compare computed classpath entries against file cache before calling
JavaCore.setClasspathContainer() — skip the update when entries are
identical, avoiding unnecessary JDT.LS workspace rebuilds. Lower
background sync job priority from BUILD to DECORATE so language
features (completion, go-to-definition) are never preempted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move all Eclipse projects from default location (.metadata/) to a
dedicated .bazel-projects/<projectName>/ directory under the workspace
root. Projects at this location pass JDT.LS's isContainedIn() check
and survive cleanInvalidProjects() across Reload Window, eliminating
the delete-recreate-refresh-reindex cycle.

Key changes:
- Always use custom location at .bazel-projects/ (no more default location)
- Linked source folders work without overlap (project and source in
  different directory trees)
- Standard src roots (src/main/java, src/test/java) use linked folders
- Fast-skip for projects already at correct location (just appendTargets)
- One-time migration for projects at old locations
- Auto-manage .bazel-projects/ in .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-project container initialization with a single batch
JavaCore.setClasspathContainer() call from file cache, reducing
28 workspace sync events to 1. Remove the background sync pipeline
(queryTargets + populateGraph + runAspectBuild + refreshClasspath)
from fast reload since it does 15-40s of work with zero benefit
when BUILD files are unchanged. Incremental sync via
BazelBuildSupport handles BUILD file changes on-demand.

Also optimize the fast-skip path: remove redundant ensureNatures()
call (natures persist in .project file) and add idempotent check
for appendTargets() to avoid unnecessary file I/O.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…emove Java builder

Optimize JDT.LS initialization to eliminate post-Ready "Synchronizing project"
and "Searching..." delays:

- Add IMPORT_IN_PROGRESS flag to skip per-project container initialization
- Add batchSetClasspathContainers() for single JavaCore.setClasspathContainer call
- Add FILE_EXISTS_CACHE to avoid repeated filesystem checks during batch init
- Remove org.eclipse.jdt.core.javabuilder from Bazel projects (redundant with
  Bazel build, and JDT code intelligence uses Java Model not builder output)
- Refactor importToWorkspace() and tryFastReload() to use deferred+batch pattern

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-set JavaCore compiler options and resource filters before JDT.LS
framework code runs, so its later setOptions()/configureFilters() calls
become no-ops and don't trigger a second round of search indexing.
Add waitForIndexesReady workspace command as a safety net so the TS
extension confirms indexes are truly complete before showing ready.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@monkey666-cr monkey666-cr merged commit d49b8c6 into monkey666-cr:main May 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants