Skip to content

fix: skip unnecessary FOR UPDATE locks in append_event when no app/user state delta#4661

Open
yuvrajangadsingh wants to merge 4 commits intogoogle:mainfrom
yuvrajangadsingh:fix/skip-unnecessary-for-update-lock-4655
Open

fix: skip unnecessary FOR UPDATE locks in append_event when no app/user state delta#4661
yuvrajangadsingh wants to merge 4 commits intogoogle:mainfrom
yuvrajangadsingh:fix/skip-unnecessary-for-update-lock-4655

Conversation

@yuvrajangadsingh
Copy link

DatabaseSessionService.append_event() acquires SELECT ... FOR UPDATE on both app_states and user_states unconditionally, even when the event carries no delta for those scopes.

Since app_states is keyed by app_name alone, this means all concurrent append_event calls within the same app serialize on that single row lock. Most events only carry session-scoped state, so this lock contention is unnecessary.

This was partially addressed by #764 which fixed the unnecessary UPDATE (merge) side, but the SELECT ... FOR UPDATE (row-level lock acquisition) still happens unconditionally.

The fix pre-analyzes the event's state delta before the transaction using extract_state_delta() (which only reads from the event object, no side effects) and only passes use_row_level_locking=True for scopes that actually have pending writes.

Added 5 tests covering all combinations: no delta, session-only delta, app-only delta, user-only delta, and both app+user deltas. All 69 session tests pass.

Fixes #4655

…er state delta

DatabaseSessionService.append_event() unconditionally acquires SELECT ... FOR UPDATE
on app_states and user_states even when the event has no delta for those scopes.

Since app_states is keyed by app_name alone, all concurrent append_event calls within
the same app serialize on this single row lock, even when most events only carry
session-scoped state.

Pre-analyze the event's state delta before the transaction and only pass
use_row_level_locking=True for scopes that actually have pending writes.

Fixes google#4655
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request optimizes the DatabaseSessionService.append_event method by making database row-level locking conditional. Previously, SELECT ... FOR UPDATE locks were unconditionally applied to app_states and user_states, leading to unnecessary contention, especially for app_states. The change introduces a pre-analysis step to identify relevant state deltas, ensuring locks are only acquired when actual state modifications are pending, thereby improving concurrency and performance.

Highlights

  • Reduced Database Lock Contention: DatabaseSessionService.append_event now avoids acquiring SELECT ... FOR UPDATE locks on app_states and user_states tables when the incoming event does not contain state deltas for those specific scopes, reducing unnecessary contention.
  • Conditional Row-Level Locking: The append_event method pre-analyzes the event's state_delta using extract_state_delta() to determine if app or user state changes are present, applying use_row_level_locking=True only when necessary.
  • Enhanced Test Coverage: Five new unit tests were added to test_session_service.py to thoroughly validate the conditional locking logic across various scenarios, including no delta, session-only, app-only, user-only, and both app+user deltas.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/google/adk/sessions/database_session_service.py
    • Introduced logic to pre-analyze event state deltas (has_app_delta, has_user_delta) before acquiring locks.
    • Modified calls to _select_required_state to conditionally pass use_row_level_locking based on the presence of app or user state deltas.
  • tests/unittests/sessions/test_session_service.py
    • Added test_append_event_skips_for_update_when_no_app_or_user_delta to verify skipping locks for session-only deltas.
    • Added test_append_event_skips_for_update_when_no_state_delta to verify skipping locks when no state delta is present.
    • Added test_append_event_acquires_for_update_when_app_delta_present to verify acquiring app state lock for app deltas.
    • Added test_append_event_acquires_for_update_when_user_delta_present to verify acquiring user state lock for user deltas.
    • Added test_append_event_acquires_for_update_when_both_deltas_present to verify acquiring both locks for both deltas.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@adk-bot adk-bot added the services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc label Feb 28, 2026
Copy link
Contributor

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

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 introduces a valuable optimization by conditionally acquiring FOR UPDATE locks in append_event only when there are app or user state deltas. This should effectively reduce lock contention and improve performance for events that don't modify shared state. The implementation is clear and the logic for detecting deltas is sound. The addition of comprehensive unit tests covering various delta scenarios is excellent and ensures the new logic is working as expected. I have one suggestion to refactor the new tests to improve maintainability by reducing code duplication.

@yuvrajangadsingh
Copy link
Author

addressed the review feedback in 7c416ae. extracted a lock_spy_harness fixture and collapsed all 5 tests into a single parametrized test.

/gemini review

Copy link
Contributor

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

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 introduces an important optimization by avoiding unnecessary FOR UPDATE locks in append_event when there are no state deltas for app or user scopes. The change correctly pre-analyzes the event's state delta and conditionally applies row-level locking. The new logic is well-covered by a comprehensive set of new unit tests. I have one suggestion to improve code clarity and avoid a repeated function call.

@yuvrajangadsingh
Copy link
Author

addressed the second review comment in 9ec1187. now reusing the pre-analyzed state_deltas variable instead of calling extract_state_delta twice.

/gemini review

Copy link
Contributor

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

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 introduces a valuable optimization to append_event by avoiding unnecessary FOR UPDATE row-level locks when an event lacks app or user state deltas. The implementation correctly pre-analyzes the event's state delta to conditionally apply locks, which should reduce database contention. The change is supported by a comprehensive new test suite that validates the conditional locking logic across various scenarios. My feedback includes a minor suggestion to refactor the state delta analysis for improved readability.

@yuvrajangadsingh
Copy link
Author

done in adb51fb, moved the bool checks inside the if block.

/gemini review

Copy link
Contributor

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

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 introduces a valuable optimization to DatabaseSessionService.append_event() by conditionally acquiring SELECT ... FOR UPDATE locks only when there are state deltas for the app or user scopes. This effectively reduces unnecessary lock contention. The implementation is clean, pre-analyzing the state delta and reusing the result to avoid redundant computations. The accompanying tests are thorough, using a spy to verify the locking behavior across various scenarios, which is excellent.

@yuvrajangadsingh
Copy link
Author

keeping the event.actions and event.actions.state_delta guard as-is. this pattern is used consistently across the codebase (in_memory_session_service.py, sqlite_session_service.py, bigquery_agent_analytics_plugin.py) and changing it here would be inconsistent. the event.actions check is defensive and i'd rather match the existing convention.

same reasoning for .get() vs direct access, both work fine but .get() is more defensive for a dict that's being read outside its creation scope.

/gemini review

Copy link
Contributor

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

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 introduces a well-reasoned optimization to append_event by avoiding unnecessary SELECT ... FOR UPDATE locks on app_states and user_states when an event doesn't contain deltas for those scopes. The implementation correctly pre-analyzes the event's state delta and conditionally applies row-level locking. The code is clean, and the logic is sound. The addition of a new test suite with a spy on the locking mechanism is excellent, providing thorough coverage for all the new conditional logic paths. The changes look solid and effectively address the potential for lock contention.

@yuvrajangadsingh
Copy link
Author

@rusherman implemented the fix you suggested in #4655. let me know if you have any feedback.

@xuanyang15 @ryanaiagent would appreciate a review when you get a chance.

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

Labels

services [Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DatabaseSessionService.append_event: unnecessary FOR UPDATE lock on app_states/user_states when no state delta exists

2 participants