Skip to content

perf(spanner): avoid allocating empty RequestOptions on read and query paths - #18422

Open
olavloite wants to merge 1 commit into
mainfrom
spanner-avoid-empty-reqopts
Open

olavloite wants to merge 1 commit into
mainfrom
spanner-avoid-empty-reqopts

Conversation

@olavloite

Copy link
Copy Markdown
Contributor

Previously, Snapshot.read(), Snapshot.execute_sql(), Transaction.execute_update(), and Transaction.batch_update() unconditionally initialized an empty RequestOptions message when no options were supplied, even when no transaction tag or client context was present. This empty submessage was then copied into the outgoing ExecuteSqlRequest or ReadRequest.

Avoid allocating RequestOptions on the default execution path when both request_options and transaction_tag are unset. Only construct RequestOptions when an explicit option or transaction tag is provided, while preserving the existing behavior of overriding or clearing tags when request_options is supplied.

@olavloite
olavloite requested a review from a team as a code owner September 18, 2026 12:09

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

Copy link
Copy Markdown
Contributor

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 refactors the handling of request_options and transaction_tag in both synchronous and asynchronous snapshot and transaction implementations, along with updating their unit tests. However, the changes removed the conversion of dictionary-based request_options to RequestOptions objects. As pointed out in the review feedback, this will lead to an AttributeError when attempting to set transaction_tag on a dictionary. To resolve this, request_options must be explicitly converted to a RequestOptions instance when a dictionary is provided.

Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
@olavloite

Copy link
Copy Markdown
Contributor Author

/gemini review

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

Copy link
Copy Markdown
Contributor

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 refactors the handling of request_options and transaction_tag in both synchronous and asynchronous snapshot and transaction classes, alongside updating unit tests. However, the changes introduce a critical regression: removing the conversion of request_options from a dictionary to a RequestOptions object will cause an AttributeError when attempting to access or set transaction_tag on a raw dictionary. This issue is present across multiple files in the codebase. Additionally, several unit test helpers mask this bug by converting dictionaries to RequestOptions objects before invoking the production code, so adding test cases that pass raw dictionaries directly is recommended.

Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
Comment thread packages/google-cloud-spanner/tests/unit/test_snapshot.py Outdated
Comment thread packages/google-cloud-spanner/tests/unit/test_transaction.py Outdated
Comment thread packages/google-cloud-spanner/tests/unit/_async/test_transaction.py Outdated
@olavloite
olavloite force-pushed the spanner-avoid-empty-reqopts branch from a51381a to 9ae7aca Compare September 18, 2026 12:40
@olavloite

Copy link
Copy Markdown
Contributor Author

/gemini review

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

Copy link
Copy Markdown
Contributor

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 refactors the handling of request_options and transaction_tag in both the synchronous and asynchronous implementations of Spanner's Snapshot and Transaction classes, ensuring that RequestOptions are only instantiated when necessary. It also simplifies credential validation in Client and adds corresponding unit tests. However, the reviewer identified a regression in both the sync and async Snapshot.read and Snapshot.execute_sql methods: if _read_only is False and self.transaction_tag is None, any user-provided transaction_tag in request_options is unconditionally overwritten with None. To preserve the original behavior, the code should be updated to only overwrite the tag when self.transaction_tag is explicitly provided.

Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
…y paths

Previously, Snapshot.read(), Snapshot.execute_sql(), Transaction.execute_update(),
and Transaction.batch_update() unconditionally initialized an empty `RequestOptions`
message when no options were supplied, even when no transaction tag or client context
was present. This empty submessage was then copied into the outgoing ExecuteSqlRequest
or ReadRequest.

Avoid allocating `RequestOptions` on the default execution path when both `request_options`
and `transaction_tag` are unset. Only construct `RequestOptions` when an explicit option
or transaction tag is provided, while preserving the existing behavior of overriding
or clearing tags when `request_options` is supplied.
@olavloite
olavloite force-pushed the spanner-avoid-empty-reqopts branch from 9ae7aca to f53eaeb Compare September 18, 2026 12:51
@olavloite

Copy link
Copy Markdown
Contributor Author

/gemini review

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

Copy link
Copy Markdown
Contributor

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 refactors the handling of request_options and transaction_tag in both synchronous and asynchronous snapshot and transaction classes, and updates the corresponding unit tests. However, the changes remove the logic that converts dictionary-based request_options into RequestOptions objects. As pointed out in the review feedback, this will cause AttributeError exceptions when attempting to access or modify transaction_tag on a dictionary. It is recommended to restore the dictionary check and conversion logic across all affected methods.

Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
Comment thread packages/google-cloud-spanner/google/cloud/spanner_v1/snapshot.py
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.

1 participant