Skip to content

chore: enable SI relate feature in cloud client executor.#12790

Open
gyang-google wants to merge 1 commit intogoogleapis:mainfrom
gyang-google:main
Open

chore: enable SI relate feature in cloud client executor.#12790
gyang-google wants to merge 1 commit intogoogleapis:mainfrom
gyang-google:main

Conversation

@gyang-google
Copy link
Copy Markdown

No description provided.

@gyang-google gyang-google requested review from a team as code owners April 14, 2026 09:08
Copy link
Copy Markdown
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 support for repeatable read isolation levels and configurable lock modes (optimistic vs. pessimistic) in read-write transactions. It also refactors Spanner client management to allow multiple timeout configurations via a map and updates the default multiplexed session ratio. The review feedback identifies a critical issue with swallowing InterruptedException in the transaction synchronization logic and highlights a bug in the client caching mechanism where the useMultiplexedSession parameter is ignored, which could lead to returning a client with an incorrect configuration.

Comment on lines +371 to +375
try {
wait();
} catch (InterruptedException e) {
LOGGER.log(Level.INFO, "Interrupted while waiting for RW transaction context.");
}
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.

high

Swallowing InterruptedException is a dangerous practice because it clears the thread's interrupted status without taking appropriate action. This can prevent the thread from responding correctly to cancellation or shutdown requests. The interrupted status should be restored by calling Thread.currentThread().interrupt(). Additionally, since this method must return a valid TransactionContext, throwing a SpannerException is appropriate to signal that the operation was interrupted and cannot proceed.

        try {
          wait();
        } catch (InterruptedException e) {
          LOGGER.log(Level.INFO, "Interrupted while waiting for RW transaction context.");
          Thread.currentThread().interrupt();
          throw SpannerExceptionFactory.newSpannerException(
              ErrorCode.CANCELLED, "Interrupted while waiting for transaction context", e);
        }


private Spanner client;
private Spanner clientWithTimeout;
private Map<Long, Spanner> clientWithTimeoutMap = new HashMap<>();
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.

medium

The clientWithTimeoutMap uses Long (representing timeoutSeconds) as its key. However, the client initialization also depends on the useMultiplexedSession parameter. If the executor is called with different useMultiplexedSession values for the same timeout, the current implementation will return a cached client that may not have the expected configuration. Using a String key that combines both parameters would ensure that clients are correctly isolated by their configuration.

Suggested change
private Map<Long, Spanner> clientWithTimeoutMap = new HashMap<>();
private Map<String, Spanner> clientWithTimeoutMap = new HashMap<>();

Comment on lines +905 to +910
if (clientWithTimeoutMap.containsKey(timeoutSeconds)) {
return clientWithTimeoutMap.get(timeoutSeconds);
}
clientWithTimeout = getClient(timeoutSeconds, useMultiplexedSession);
return clientWithTimeout;
clientWithTimeoutMap.put(timeoutSeconds,
initializeClient(timeoutSeconds, useMultiplexedSession));
return clientWithTimeoutMap.get(timeoutSeconds);
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.

medium

The caching logic here only considers timeoutSeconds. As noted in the map definition, this can lead to returning a client with the wrong useMultiplexedSession configuration if multiple requests with the same timeout but different session settings are processed. The key should incorporate both parameters to ensure correct client retrieval.

    String key = timeoutSeconds + ":" + useMultiplexedSession;
    if (clientWithTimeoutMap.containsKey(key)) {
      return clientWithTimeoutMap.get(key);
    }
    Spanner client = initializeClient(timeoutSeconds, useMultiplexedSession);
    clientWithTimeoutMap.put(key, client);
    return client;

Comment on lines 914 to 918
if (client != null) {
return client;
}
client = getClient(/* timeoutSeconds= */ 0, useMultiplexedSession);
client = initializeClient(/* timeoutSeconds= */ 0, useMultiplexedSession);
return client;
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.

medium

This method caches the client in a single field without considering the useMultiplexedSession parameter. Subsequent calls with a different useMultiplexedSession value will return the previously cached client, which may have the wrong configuration. Delegating to getClientWithTimeout with a timeout of 0 will leverage the keyed caching mechanism and ensure the correct client is used.

    return getClientWithTimeout(0, useMultiplexedSession);

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