Skip to content

perf(@angular/build): batch last_accessed updates in sqlite cache store - #33801

Merged
alan-agius4 merged 1 commit into
angular:mainfrom
alan-agius4:perf-sqlite-cache-batch
Aug 7, 2026
Merged

perf(@angular/build): batch last_accessed updates in sqlite cache store#33801
alan-agius4 merged 1 commit into
angular:mainfrom
alan-agius4:perf-sqlite-cache-batch

Conversation

@alan-agius4

@alan-agius4 alan-agius4 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Previously, every get() call on SqliteCacheStore immediately executed an UPDATE statement to refresh the last_accessed timestamp for the requested cache key. In SQLite WAL mode, each unbatched UPDATE starts an implicit write transaction, acquiring exclusive write locks on the WAL and causing repeated disk I/O and fsync operations during cache reads.

During parallel builds, this serialized concurrent read operations and introduced unnecessary overhead on hot read paths.

To resolve this:

  • last_accessed updates are buffered in an in-memory Set and flushed inside a single explicit transaction (BEGIN TRANSACTION; ... COMMIT;), periodically debounced (every 500ms or when batch reaches 100 entries) and before pruning on close().
  • Flushes on close() ensure that recently accessed items have their timestamps persisted prior to TTL and LRU size pruning.
  • SQLite PRAGMAs (busy_timeout = 5000, temp_store = MEMORY, mmap_size = 268435456) are tuned to reduce lock contention and leverage memory-mapped I/O.
  • The debounced timer uses unref() to ensure it does not hold the Node.js process event loop open.

@angular-robot angular-robot Bot added area: performance Issues related to performance area: @angular/build labels Aug 7, 2026
@alan-agius4 alan-agius4 added the target: patch This PR is targeted for the next patch release label Aug 7, 2026
@alan-agius4
alan-agius4 force-pushed the perf-sqlite-cache-batch branch from 4733e81 to e2805e9 Compare August 7, 2026 14:27
@alan-agius4
alan-agius4 marked this pull request as ready for review August 7, 2026 14:28
@alan-agius4
alan-agius4 force-pushed the perf-sqlite-cache-batch branch from e2805e9 to 97b7ff9 Compare August 7, 2026 14:28

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the SqliteCacheStore by batching SQLite access updates in a transaction instead of executing them individually on every cache hit. It also configures performance-related SQLite PRAGMAs and ensures pending updates are flushed upon closing. The review feedback suggests using BEGIN IMMEDIATE TRANSACTION; instead of BEGIN TRANSACTION; to prevent potential SQLITE_BUSY errors or deadlocks in concurrent environments.

Comment thread packages/angular/build/src/tools/esbuild/sqlite-cache-store.ts Outdated
Previously, every `get()` call on `SqliteCacheStore` immediately executed an `UPDATE` statement to refresh the `last_accessed` timestamp for the requested cache key. In SQLite WAL mode, each unbatched `UPDATE` starts an implicit write transaction, acquiring exclusive write locks on the WAL and causing repeated disk I/O and fsync operations during cache reads.

During parallel builds, this serialized concurrent read operations and introduced unnecessary overhead on hot read paths.

To resolve this:
- `last_accessed` updates are buffered in an in-memory `Set` and flushed inside a single explicit transaction (`BEGIN TRANSACTION; ... COMMIT;`), periodically debounced (every 500ms or when batch reaches 100 entries) and before pruning on `close()`.
- Flushes on `close()` ensure that recently accessed items have their timestamps persisted prior to TTL and LRU size pruning.
- SQLite PRAGMAs (`busy_timeout = 5000`, `temp_store = MEMORY`, `mmap_size = 268435456`) are tuned to reduce lock contention and leverage memory-mapped I/O.
- The debounced timer uses `unref()` to ensure it does not hold the Node.js process event loop open.
@alan-agius4
alan-agius4 force-pushed the perf-sqlite-cache-batch branch from 97b7ff9 to b370ccf Compare August 7, 2026 14:32
@alan-agius4 alan-agius4 added the action: merge The PR is ready for merge by the caretaker label Aug 7, 2026
@alan-agius4
alan-agius4 merged commit a55a6b7 into angular:main Aug 7, 2026
40 checks passed
@alan-agius4
alan-agius4 deleted the perf-sqlite-cache-batch branch August 7, 2026 14:53
@alan-agius4

Copy link
Copy Markdown
Collaborator Author

This PR was merged into the repository. The changes were merged into the following branches:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

action: merge The PR is ready for merge by the caretaker area: @angular/build area: performance Issues related to performance target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants