Each pooled session has a parameter lastUseTime which indicates the timestamp when the session was last used. If we make successive RPC calls within a transaction, this parameter only gets updated at the start of the transaction (when we begin transaction) and does not get updated with subsequent RPC calls. For ex - Consider the below sample
try (TransactionManager manager = client.transactionManager()) {
TransactionContext transaction = manager.begin();
while (true) {
try {
// first RPC
transaction.executeUpdate(UPDATE_STATEMENT);
// second RPC
transaction.executeUpdate(UPDATE_STATEMENT);
manager.commit();
break;
} catch (AbortedException e) {
transaction = manager.resetForRetry();
}
}
}
Bug : In the above example we would expect the timestamp to get updated for each executeUpdate RPC. However that is not the case. We are only updating the timestamp when we invoke manager.begin(). Furthermore, the TransactionContext class does not have access to the PooledSession object.
Impact - While this won't have any major impact when small number of RPCs are clubbed within a transaction, but for cases where we have say 100's or 1000's of RPC clubbed in a single transaction, the over-all transaction may execute for hours. If we don't update the lastUseTime correctly, existing session pool maintenance activities like idle session removal, pinging sessions, etc. may all behave incorrectly as they see a stale timestamp.
Another interface through which RPCs can be chained
TransactionRunner runner = client.readWriteTransaction();
runner.run(
transaction -> {
try (ResultSet resultSet =
transaction.read(
READ_TABLE_NAME,
KeySet.singleKey(Key.of(1L)),
READ_COLUMN_NAMES,
Options.priority(RpcPriority.HIGH))) {
while (resultSet.next()) {}
}
try (ResultSet resultSet =
transaction.read(
READ_TABLE_NAME,
KeySet.singleKey(Key.of(1L)),
READ_COLUMN_NAMES,
Options.priority(RpcPriority.HIGH))) {
while (resultSet.next()) {}
}
return null;
});
While we would expect the timestamp to get updated for each transaction.read call, it only gets updated for runner.run.
Solution Approaches
Approach 1 - #2684
Approach 2 - #2704
Each pooled session has a parameter
lastUseTimewhich indicates the timestamp when the session was last used. If we make successive RPC calls within a transaction, this parameter only gets updated at the start of the transaction (when we begin transaction) and does not get updated with subsequent RPC calls. For ex - Consider the below sampleBug : In the above example we would expect the timestamp to get updated for each
executeUpdateRPC. However that is not the case. We are only updating the timestamp when we invokemanager.begin(). Furthermore, theTransactionContextclass does not have access to thePooledSessionobject.Impact - While this won't have any major impact when small number of RPCs are clubbed within a transaction, but for cases where we have say 100's or 1000's of RPC clubbed in a single transaction, the over-all transaction may execute for hours. If we don't update the
lastUseTimecorrectly, existing session pool maintenance activities like idle session removal, pinging sessions, etc. may all behave incorrectly as they see a stale timestamp.Another interface through which RPCs can be chained
While we would expect the timestamp to get updated for each
transaction.readcall, it only gets updated forrunner.run.Solution Approaches
Approach 1 - #2684
Approach 2 - #2704