Skip to content

test(spanner): unflake ConnectionAsyncApiAbortedTest - #14785

Open
sakthivelmanii wants to merge 4 commits into
mainfrom
unflake-connectionasyncapiabortedtest
Open

sakthivelmanii wants to merge 4 commits into
mainfrom
unflake-connectionasyncapiabortedtest

Conversation

@sakthivelmanii

@sakthivelmanii sakthivelmanii commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Problem

  • A client race condition in the Connection API occurs when an unawaited asynchronous statement aborts and fails with AbortedDueToConcurrentModificationException before the application thread calls commitAsync().
  • ConnectionImpl.hasTransactionalChanges() incorrectly returns false because it requires the state to be STARTED.
  • This causes commitAsync() to take the 'nothing to commit' no-op branch, silently swallowing the aborted exception.
  • Additionally, the commitAsync() thread could overwrite the ABORTED state with COMMITTING, bypassing the aborted exception check.

Solution

  • Scope the aborted transaction check to commit only to preserve public API semantics.
  • Update checkAborted() to check the non-null abortedException.
  • Add a new deterministic regression test.

Fixes a client race condition in the Connection API where an unawaited asynchronous statement aborts and fails with AbortedDueToConcurrentModificationException before the application thread calls commitAsync(). ConnectionImpl.hasTransactionalChanges() incorrectly returned false because it required the state to be STARTED, causing commitAsync() to take the 'nothing to commit' no-op branch and silently swallow the aborted exception. Additionally, commitAsync()'s thread could overwrite the ABORTED state with COMMITTING, bypassing the aborted exception check. This fix scopes the aborted transaction check to commit only, avoiding alterations to public API behavior, updates checkAborted() to key on the non-null abortedException, and adds a regression test.
@sakthivelmanii
sakthivelmanii requested review from a team as code owners October 27, 2026 11:51
@sakthivelmanii
sakthivelmanii enabled auto-merge (squash) October 27, 2026 11:51
@sakthivelmanii

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 ensures that committing a transaction that has been aborted due to an asynchronous statement failure returns the abort error instead of silently succeeding. It introduces a check for aborted transactions in ConnectionImpl and updates ReadWriteTransaction to check for the presence of an aborted exception directly, as the transaction state might be overwritten during commit. A corresponding integration test has been added to verify this behavior. I have no feedback to provide as there are no review comments.

@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 ensures that committing an aborted transaction fails instead of silently succeeding, particularly when an asynchronous statement aborts before commit is called. It introduces isCurrentTransactionAborted() and updates transaction state checks. The reviewer identified a critical issue where calling rollback on an aborted transaction would be blocked by the new condition, leaving the connection stuck in an aborted state. The reviewer suggested allowing both commit and rollback to proceed when the transaction is aborted.

@sakthivelmanii

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 ensures that committing an aborted transaction returns the abort error instead of silently succeeding, particularly when an asynchronous statement aborts before the commit is called. It introduces checks for aborted transactions in ConnectionImpl and ReadWriteTransaction, and adds a corresponding integration test. The review feedback suggests allowing both commit and rollback to proceed when a transaction is aborted to ensure client-side state is properly cleared, and recommends simplifying the new test assertions using assertThrows.

@sakthivelmanii

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 ensures that committing an aborted transaction fails with an abort error instead of silently succeeding, which can happen when an asynchronous statement aborts before commit is called. It introduces a check for aborted transactions in ConnectionImpl and refactors state checks in ReadWriteTransaction to rely on abortedException. Additionally, a new test is added to verify this behavior. Feedback on the changes includes removing an unused static import in the test file and refactoring the new test to use the more idiomatic assertThrows instead of the try-catch-fail pattern.

@sakthivelmanii

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 ensures that committing a transaction aborted by an asynchronous statement fails with an abort error instead of silently succeeding. It updates ConnectionImpl and ReadWriteTransaction to check for aborted states during commit and rollback, and adds a corresponding integration test. However, a critical concurrency issue was identified in ReadWriteTransaction.java: removing the volatile read of state before checking abortedException violates the Java Memory Model, which may lead to threads reading a stale null value. To resolve this, abortedException should be declared as volatile.

@sakthivelmanii

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 ensures that committing a transaction that has been aborted (for example, when an asynchronous statement aborts before commit is called) fails with an abort error instead of silently succeeding. It introduces a helper method isCurrentTransactionAborted in ConnectionImpl and refactors ReadWriteTransaction to check abortedException directly rather than relying solely on the UnitOfWorkState.ABORTED state, which can be overwritten. Additionally, a unit test has been added to verify this behavior. I have no feedback to provide as there are no review comments to evaluate.

This branch has not been deployed

No deployments
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