chore(spanner): enable SI relate feature in cloud client executor.#12790
chore(spanner): enable SI relate feature in cloud client executor.#12790gyang-google wants to merge 1 commit intogoogleapis:mainfrom
Conversation
There was a problem hiding this comment.
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.
| try { | ||
| wait(); | ||
| } catch (InterruptedException e) { | ||
| LOGGER.log(Level.INFO, "Interrupted while waiting for RW transaction context."); | ||
| } |
There was a problem hiding this comment.
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<>(); |
There was a problem hiding this comment.
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.
| private Map<Long, Spanner> clientWithTimeoutMap = new HashMap<>(); | |
| private Map<String, Spanner> clientWithTimeoutMap = new HashMap<>(); |
| if (clientWithTimeoutMap.containsKey(timeoutSeconds)) { | ||
| return clientWithTimeoutMap.get(timeoutSeconds); | ||
| } | ||
| clientWithTimeout = getClient(timeoutSeconds, useMultiplexedSession); | ||
| return clientWithTimeout; | ||
| clientWithTimeoutMap.put(timeoutSeconds, | ||
| initializeClient(timeoutSeconds, useMultiplexedSession)); | ||
| return clientWithTimeoutMap.get(timeoutSeconds); |
There was a problem hiding this comment.
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;| if (client != null) { | ||
| return client; | ||
| } | ||
| client = getClient(/* timeoutSeconds= */ 0, useMultiplexedSession); | ||
| client = initializeClient(/* timeoutSeconds= */ 0, useMultiplexedSession); | ||
| return client; |
There was a problem hiding this comment.
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);
No description provided.