[ 
https://issues.apache.org/jira/browse/CALCITE-5009?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17490697#comment-17490697
 ] 

Istvan Toth edited comment on CALCITE-5009 at 2/11/22, 7:00 AM:
----------------------------------------------------------------

Ultimately, createConnection()
{noformat}
  org.apache.calcite.avatica.AvaticaClientRuntimeException: Remote driver 
error: 
  RuntimeException: Connection already exists: 
e1cbaa54-dd66-461e-8bee-15d6a6296581 at 
  
org.apache.calcite.avatica.remote.Service$ErrorResponse.toException(Service.java:2475)
 at 
  
org.apache.calcite.avatica.remote.RemoteProtobufService._apply(RemoteProtobufService.java:62)
 at 
  
org.apache.calcite.avatica.remote.ProtobufService.apply(ProtobufService.java:81)
 at 
  org.apache.calcite.avatica.remote.RemoteMeta$3.call(RemoteMeta.java:114) at 
  org.apache.calcite.avatica.remote.RemoteMeta$3.call(RemoteMeta.java:110) at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:793)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.openConnection(RemoteMeta.java:109)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.openConnection(AvaticaConnection.java:154)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:797)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.connectionSync(RemoteMeta.java:134)
 at 
  org.apache.calcite.avatica.remote.RemoteMeta$1.call(RemoteMeta.java:88) at 
  org.apache.calcite.avatica.remote.RemoteMeta$1.call(RemoteMeta.java:85) at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:793)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.createStatement(RemoteMeta.java:84)
 at 
  org.apache.calcite.avatica.AvaticaStatement.<init>(AvaticaStatement.java:115) 
at 
  org.apache.calcite.avatica.AvaticaStatement.<init>(AvaticaStatement.java:101) 
at
  
org.apache.calcite.avatica.AvaticaJdbc41Factory$AvaticaJdbc41Statement.<init>(AvaticaJdbc41Factory.java:118)
 at 
  
org.apache.calcite.avatica.AvaticaJdbc41Factory$AvaticaJdbc41Statement.<init>(AvaticaJdbc41Factory.java:114)
 at 
  
org.apache.calcite.avatica.AvaticaJdbc41Factory.newStatement(AvaticaJdbc41Factory.java:76)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:343)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:167)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:63)
 at
  org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:379) at 
<application part deleted> {noformat}

The "Connection already exists" exception is the original problem that I was 
investigating.
I think that it happens above is that as the server side connection is expired, 
multiple client threads try to re-create the connection, and we run into a race 
condition.
While could probably do something  about that race condition (like 
synchronizing the reconnect code), that is a relatively harmless issue.

The more serious problem is that we break transaction handling, which depends 
on the proxied connection object being tightly controlled by the application.

Breaking transactions is the most obvious problem caused by replacing the 
proxied connection object on the sly, but there may be more, mysql's 
LAST_INSERT_ID comes to my mind that may be lost in this case.

We should also check if we do similar transaparent re-create for statement 
objects, and if we do, what, if any problems does that cause.


was (Author: stoty):
Ultimately, createConnection()
{noformat}
  org.apache.calcite.avatica.AvaticaClientRuntimeException: Remote driver 
error: 
  RuntimeException: Connection already exists: 
e1cbaa54-dd66-461e-8bee-15d6a6296581 at 
  
org.apache.calcite.avatica.remote.Service$ErrorResponse.toException(Service.java:2475)
 at 
  
org.apache.calcite.avatica.remote.RemoteProtobufService._apply(RemoteProtobufService.java:62)
 at 
  
org.apache.calcite.avatica.remote.ProtobufService.apply(ProtobufService.java:81)
 at 
  org.apache.calcite.avatica.remote.RemoteMeta$3.call(RemoteMeta.java:114) at 
  org.apache.calcite.avatica.remote.RemoteMeta$3.call(RemoteMeta.java:110) at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:793)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.openConnection(RemoteMeta.java:109)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.openConnection(AvaticaConnection.java:154)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:797)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.connectionSync(RemoteMeta.java:134)
 at 
  org.apache.calcite.avatica.remote.RemoteMeta$1.call(RemoteMeta.java:88) at 
  org.apache.calcite.avatica.remote.RemoteMeta$1.call(RemoteMeta.java:85) at 
  
org.apache.calcite.avatica.AvaticaConnection.invokeWithRetries(AvaticaConnection.java:793)
 at 
  
org.apache.calcite.avatica.remote.RemoteMeta.createStatement(RemoteMeta.java:84)
 at 
  org.apache.calcite.avatica.AvaticaStatement.<init>(AvaticaStatement.java:115) 
at 
  org.apache.calcite.avatica.AvaticaStatement.<init>(AvaticaStatement.java:101) 
at
  
org.apache.calcite.avatica.AvaticaJdbc41Factory$AvaticaJdbc41Statement.<init>(AvaticaJdbc41Factory.java:118)
 at 
  
org.apache.calcite.avatica.AvaticaJdbc41Factory$AvaticaJdbc41Statement.<init>(AvaticaJdbc41Factory.java:114)
 at 
  
org.apache.calcite.avatica.AvaticaJdbc41Factory.newStatement(AvaticaJdbc41Factory.java:76)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:343)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:167)
 at 
  
org.apache.calcite.avatica.AvaticaConnection.createStatement(AvaticaConnection.java:63)
 at
  org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:379) at 
<application part deleted> {noformat}
 

> Make sure transaparent jdbc connection re-creation does not lead to data loss
> -----------------------------------------------------------------------------
>
>                 Key: CALCITE-5009
>                 URL: https://issues.apache.org/jira/browse/CALCITE-5009
>             Project: Calcite
>          Issue Type: Bug
>          Components: avatica
>            Reporter: Istvan Toth
>            Priority: Major
>
> Currently, if the server-side JDBC connection goes away for any reason
>  * Avatica connection cache expiry
>  * LB/HA Failover
>  * Some problem with the "real" connection
> we attempt to create a new "real" JDBC connection, and continue using that 
> instead of the original connection
> [https://github.com/apache/calcite-avatica/blob/fbdcc62745a0e8920db759fb6bdce564d854e407/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java#L796]
> This is fine for most read-only connections, but it can break transaction 
> semantics, which is captured in the "real" connection object.
> {noformat}
> conn.setAutocommit(false)
> stmt = conn.createStatement()
> execute(insert A)
> //Connection lost and object recreated which now proxies a new "real" 
> connection
> execute(insert B)
> conn.commit()
> //We have lost "insert A"{noformat}
> I'm not sure if we synchronize autocommit state of the new connection to the 
> lost one or not, but it's bad either way.
>  
> We should either completely drop this feature, add some logic that avoids it 
> if there is an open transaction and/or only allow it for connections that 
> have the readOnly flag set.



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to