You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-user@db.apache.org by Daniel Noll <da...@nuix.com> on 2008/03/04 06:07:55 UTC

NPE getting length of Blob

Hi all.

I have someone seeing the following error under both 10.3.1.4 and 10.3.2.1:

java.lang.NullPointerException
	at org.apache.derby.client.am.PreparedStatement.setIntX(Unknown Source)
	at org.apache.derby.client.am.CallableLocatorProcedures.blobGetLength(Unknown 
Source)
	at org.apache.derby.client.am.Blob.getLocatorLength(Unknown Source)
	at org.apache.derby.client.am.Lob.sqlLength(Unknown Source)
	at org.apache.derby.client.am.Blob.length(Unknown Source)

Has anyone seen something like this before?  What is the cause of the problem?  
The exact same code on the exact same version of Derby doesn't cause the same 
problem over here; could it be something which only happens when unusual 
network conditions are happening, or something which only happens when the 
database meets a certain condition?

Daniel

Re: NPE getting length of Blob

Posted by Narayanan <V....@Sun.COM>.
Daniel John Debrunner wrote:
> Daniel Noll wrote:
>> On Wednesday 05 March 2008 13:54:19 Raymond Kroeker wrote:
>>> Hi Daniel,
>>>
>>>     What appears to be happening is that the same connection is being
>>> returned by getConnection2().  Basically the implementation of the 
>>> pool is
>>> not thread safe.
>>
>> I thought reusing the connection was the entire point of connection 
>> pooling.  Correct me if I'm wrong.
>>
>> I can't see how getConnection2() could return the same object to two 
>> separate requestors, given that:
>>   - the method is synchronized
>>   - it only reuses a connection if it's in the recycledConnections stack
>>   - connections can only get into the stack after a connectionClosed 
>> event.
>>
>> Unless Derby is sending connectionClosed before the connection is 
>> actually closed, I don't see how it could happen.
>
> That sounds similar to DERBY-2142 ...
>
> https://issues.apache.org/jira/browse/DERBY-2142
>
> Dan.
https://issues.apache.org/jira/browse/DERBY-3379 for the client. Guess 
this issue is the reason for the failure.
I agree with the analysis by Raymond.

It works for embedded because DERBY-2142 has been fixed for embedded. 
DERBY-3379 has been opened afresh
for client.

Looks like the issue is being actively worked on. Guess we would expect 
a resolution soon.

Thank you for the effort taken to analyze the issue Daniel and Raymond. 
Thanks for the pointer to the JIRA Dan.

Narayanan

Re: NPE getting length of Blob

Posted by Daniel John Debrunner <dj...@apache.org>.
Daniel Noll wrote:
> On Wednesday 05 March 2008 13:54:19 Raymond Kroeker wrote:
>> Hi Daniel,
>>
>>     What appears to be happening is that the same connection is being
>> returned by getConnection2().  Basically the implementation of the pool is
>> not thread safe.
> 
> I thought reusing the connection was the entire point of connection pooling.  
> Correct me if I'm wrong.
> 
> I can't see how getConnection2() could return the same object to two separate 
> requestors, given that:
>   - the method is synchronized
>   - it only reuses a connection if it's in the recycledConnections stack
>   - connections can only get into the stack after a connectionClosed event.
> 
> Unless Derby is sending connectionClosed before the connection is actually 
> closed, I don't see how it could happen.

That sounds similar to DERBY-2142 ...

https://issues.apache.org/jira/browse/DERBY-2142

Dan.

Re: NPE getting length of Blob

Posted by Daniel Noll <da...@nuix.com>.
On Wednesday 05 March 2008 13:54:19 Raymond Kroeker wrote:
> Hi Daniel,
>
>     What appears to be happening is that the same connection is being
> returned by getConnection2().  Basically the implementation of the pool is
> not thread safe.

I thought reusing the connection was the entire point of connection pooling.  
Correct me if I'm wrong.

I can't see how getConnection2() could return the same object to two separate 
requestors, given that:
  - the method is synchronized
  - it only reuses a connection if it's in the recycledConnections stack
  - connections can only get into the stack after a connectionClosed event.

Unless Derby is sending connectionClosed before the connection is actually 
closed, I don't see how it could happen.

Daniel

Re: NPE getting length of Blob

Posted by Raymond Kroeker <ra...@raykroeker.com>.
Hi Daniel,

    What appears to be happening is that the same connection is being
returned by getConnection2().  Basically the implementation of the pool is
not thread safe.  The NPE is thrown when the statement attempts to access
its internal parameter meta data which is nulled out when the underlying
physical connection is reset (flagged for reuse).  The conclusion is that
the pool implementation is not safely borrowing/returning connections.

    I've had luck using commons-dbcp in conjunction with commons-pool for
server side connection pooling when connecting to a derby database server.

http://commons.apache.org/dbcp
http://commons.apache.org/pool


On Tue, Mar 4, 2008 at 5:52 PM, Daniel Noll <da...@nuix.com> wrote:

> On Wednesday 05 March 2008 12:43:44 Raymond Kroeker wrote:
> > Hi Daniel,
> >     Which pool/version are you using?  Also how are you configuring the
> > pool?  You want to make sure your library is wrapping the connection  or
> > if not; is interfacing with the pooled connection/data source object.
>
> Data source configuration is... (parameters is our own bean for storing
> this
> stuff...)
>
> ClientConnectionPoolDataSource dataSource =
>    new ClientConnectionPoolDataSource();
> dataSource.setServerName(parameters.getHost());
> dataSource.setPortNumber(parameters.getPort());
> dataSource.setDatabaseName(parameters.getPath());
>
> We're using MCPM as the pool manager, it's just a simple connection pool
> manager in a single Java class which uses PooledConnection to do the hard
> stuff.
>
> Relevant code is probably:
>
>  private synchronized Connection getConnection2() throws SQLException {
>    PooledConnection pconn;
>    if (!recycledConnections.empty()) {
>      pconn = recycledConnections.pop();
>    } else {
>      pconn = dataSource.getPooledConnection();
>    }
>    Connection conn = pconn.getConnection();
>    activeConnections++;
>    return conn;
>  }
>
> As it's going via PooledConnection I was expecting it to be reusable after
> closing.  This works in practice for the embedded version anyway.
>
> I've checked the MCPM code and close() is only called during
> disposeConnection
> and certainly not during recycleConnection.
>
> Daniel
>



-- 
---------------------------------------------------------
Raymond Kroeker

Re: NPE getting length of Blob

Posted by Daniel Noll <da...@nuix.com>.
On Wednesday 05 March 2008 12:43:44 Raymond Kroeker wrote:
> Hi Daniel,
>     Which pool/version are you using?  Also how are you configuring the
> pool?  You want to make sure your library is wrapping the connection  or 
> if not; is interfacing with the pooled connection/data source object.

Data source configuration is... (parameters is our own bean for storing this 
stuff...)

ClientConnectionPoolDataSource dataSource =
    new ClientConnectionPoolDataSource();
dataSource.setServerName(parameters.getHost());
dataSource.setPortNumber(parameters.getPort());
dataSource.setDatabaseName(parameters.getPath());

We're using MCPM as the pool manager, it's just a simple connection pool 
manager in a single Java class which uses PooledConnection to do the hard 
stuff.

Relevant code is probably:

  private synchronized Connection getConnection2() throws SQLException {
    PooledConnection pconn;
    if (!recycledConnections.empty()) {
      pconn = recycledConnections.pop();
    } else {
      pconn = dataSource.getPooledConnection();
    }
    Connection conn = pconn.getConnection();
    activeConnections++;
    return conn;
  }

As it's going via PooledConnection I was expecting it to be reusable after 
closing.  This works in practice for the embedded version anyway.

I've checked the MCPM code and close() is only called during disposeConnection 
and certainly not during recycleConnection.

Daniel

Re: NPE getting length of Blob

Posted by Raymond Kroeker <ra...@raykroeker.com>.
Hi Daniel,
    Which pool/version are you using?  Also how are you configuring the
pool?  You want to make sure your library is wrapping the connection  or  if
not; is interfacing with the pooled connection/data source object.

Raymond

On Tue, Mar 4, 2008 at 4:36 PM, Daniel Noll <da...@nuix.com> wrote:

> On Tuesday 04 March 2008 22:36:17 Narayanan wrote:
> > I have tried getting a blob from a result set and tried the length()
> > method on it after the following Scenarios
> >
> > 1) Closing the connection
>
> The underlying problem must be something to do with Connection reuse.  We
> discovered that am.PreparedStatement.parameterMetaData_ was being set to
> null
> in markClosed(), and yet the same PreparedStatement object was being
> reused
> for subsequent blob length queries.  So it would work once and then not
> for
> any subsequent attempts.  Subsequent attempts for the same blob would
> probably work because the result is cached elsewhere but attempts for a
> different blob would use the same cached, invalid PreparedStatement
> object.
>
> Here's who's setting it to null:
>        at
> org.apache.derby.client.am.PreparedStatement.markClosed(
> PreparedStatement.java:2526);
>        at org.apache.derby.client.am.Statement.markClosed(Statement.java
> :1755)
>        at
> org.apache.derby.client.am.Connection.markStatementsClosed(Connection.java
> :879)
>        at org.apache.derby.client.am.Connection.markClosed(Connection.java
> :864)
>        at
> org.apache.derby.client.am.Connection.markClosedForReuse(Connection.java
> :872)
>        at org.apache.derby.client.am.Connection.closeForReuse(
> Connection.java:833)
>        at
> org.apache.derby.client.am.NetConnection.closeForReuse(NetConnection.java
> :1829)
>        at
> org.apache.derby.client.am.LogicalConnection.close(LogicalConnection.java
> :80)
>
> We're calling Connection.close() but it's a connection from a pool, and
> you're
> supposed to close those.
>
> Potential fixes:
>  - Don't set things to null during close methods (it's inherently
> dangerous.)
>  - Check if the statement is closed after checking whether it's null
> (possibly defeats the purpose of caching the statement for the
> connection.)
>
> Anyway now that we know roughly where the problem is, some Derby developer
> will presumably know better than us how to fix it without breaking
> anything
> else.
>
> Daniel
>



-- 
---------------------------------------------------------
Raymond Kroeker

Re: NPE getting length of Blob

Posted by Daniel Noll <da...@nuix.com>.
On Tuesday 04 March 2008 22:36:17 Narayanan wrote:
> I have tried getting a blob from a result set and tried the length()
> method on it after the following Scenarios
>
> 1) Closing the connection

The underlying problem must be something to do with Connection reuse.  We 
discovered that am.PreparedStatement.parameterMetaData_ was being set to null 
in markClosed(), and yet the same PreparedStatement object was being reused 
for subsequent blob length queries.  So it would work once and then not for 
any subsequent attempts.  Subsequent attempts for the same blob would 
probably work because the result is cached elsewhere but attempts for a 
different blob would use the same cached, invalid PreparedStatement object.

Here's who's setting it to null:
	at 
org.apache.derby.client.am.PreparedStatement.markClosed(PreparedStatement.java:2526);
	at org.apache.derby.client.am.Statement.markClosed(Statement.java:1755)
	at 
org.apache.derby.client.am.Connection.markStatementsClosed(Connection.java:879)
	at org.apache.derby.client.am.Connection.markClosed(Connection.java:864)
	at 
org.apache.derby.client.am.Connection.markClosedForReuse(Connection.java:872)
	at org.apache.derby.client.am.Connection.closeForReuse(Connection.java:833)
	at 
org.apache.derby.client.am.NetConnection.closeForReuse(NetConnection.java:1829)
	at 
org.apache.derby.client.am.LogicalConnection.close(LogicalConnection.java:80)

We're calling Connection.close() but it's a connection from a pool, and you're 
supposed to close those.

Potential fixes:
  - Don't set things to null during close methods (it's inherently dangerous.)
  - Check if the statement is closed after checking whether it's null 
(possibly defeats the purpose of caching the statement for the connection.)

Anyway now that we know roughly where the problem is, some Derby developer 
will presumably know better than us how to fix it without breaking anything 
else.

Daniel

Re: NPE getting length of Blob

Posted by Narayanan <V....@Sun.COM>.
Daniel Noll wrote:
> Hi all.
>
> I have someone seeing the following error under both 10.3.1.4 and 10.3.2.1:
>
> java.lang.NullPointerException
> 	at org.apache.derby.client.am.PreparedStatement.setIntX(Unknown Source)
> 	at org.apache.derby.client.am.CallableLocatorProcedures.blobGetLength(Unknown 
> Source)
> 	at org.apache.derby.client.am.Blob.getLocatorLength(Unknown Source)
> 	at org.apache.derby.client.am.Lob.sqlLength(Unknown Source)
> 	at org.apache.derby.client.am.Blob.length(Unknown Source)
>
> Has anyone seen something like this before?  What is the cause of the problem?  
> The exact same code on the exact same version of Derby doesn't cause the same 
> problem over here; could it be something which only happens when unusual 
> network conditions are happening, or something which only happens when the 
> database meets a certain condition?
>
> Daniel
>   
I have tried getting a blob from a result set and tried the length() 
method on it after the following
Scenarios

1) Closing the connection
2) committing the transaction
3) Rolling back the transaction

In the above three I got the expected SQLState.

4) Tried shutting down the network server just before blob.length I get 
the following

Exception in thread "main" java.sql.SQLNonTransientConnectionException: 
Insufficient data while reading from the network - expected a minimum of 
6 bytes and received only -1 bytes. The connection has been terminated.
at 
org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(SQLExceptionFactory40.java:70)
at 
org.apache.derby.client.am.SqlException.getSQLException(SqlException.java:362)
at org.apache.derby.client.am.Blob.length(Blob.java:141)
at javaapplication2.Main.main(Main.java:31)

None of the above scenarios seem to be giving the exception pointed out.

Narayanan

Re: NPE getting length of Blob

Posted by Daniel Noll <da...@nuix.com>.
On Tuesday 04 March 2008 21:14:43 Narayanan wrote:
> Can you give more information about the code that uses this?

It looks like this.  I've omitted some of the code which was present as it was 
calling framework methods anyway.

private long id;

public int read(byte[] b, int off, int len) {
  Connection conn = (get from pool)
  try {
    PreparedStatement ps = conn.prepareStatement("SELECT data FROM binaries 
WHERE id = ?");
    ResultSet rs = null;
    try {
      ps.setLong(1, id);
      rs = ps.executeQuery();
      if (rs.next()) {
        Blob blob = rs.getBlob("data");
        int pos = pointer + 1;
        int length = (int) Math.min(blob.length() - pointer, len);//throws NPE
        if (length == 0) {
          return -1;
        } else {
          byte[] tmp = blob.getBytes(pos, length);
          System.arraycopy(tmp, 0, b, off, length);
          pointer += length;
          return length;
        }
      }
    } finally {
      if (rs != null) rs.close();
      ps.close();
    }
  } finally {
    conn.commit();
    conn.close();
  }
}

This is part of an InputStream implementation so it's being called multiple 
times in a row with different offset and length.

If I try this on a fresh connection by itself, it doesn't occur.  The only 
thing that really seems unique about running it in the application itself is 
that we're accessing it through a connection pool.  I'm still attempting to 
get it to happen standalone so I can open a proper bug record for it.

> Can you check what version is the derby network server? What version is
> the network client?

They are the versions I specified in the previous mail.  In both situations I 
used the same version for the server and the client; I haven't tried one 
version of the server against the other version of the client (nor vice 
versa.)

> This information will be very useful if we try to single step the code
> to find out
> the problem source.

I was able to finally reproduce the problem on my own machine so it isn't 
dependent on the network, and I have confirmed that it isn't dependent on the 
type of data in the database either although since I have only managed to 
reproduce it in our own application, all databases tested have more or less 
the same schema.

The same code on the embedded version does work.  Additionally the same code 
on 10.2.2.0 client/server works fine too.

Daniel

Re: NPE getting length of Blob

Posted by Narayanan <V....@Sun.COM>.
Daniel Noll wrote:
> Hi all.
>
> I have someone seeing the following error under both 10.3.1.4 and 10.3.2.1:
>
> java.lang.NullPointerException
> 	at org.apache.derby.client.am.PreparedStatement.setIntX(Unknown Source)
> 	at org.apache.derby.client.am.CallableLocatorProcedures.blobGetLength(Unknown 
> Source)
> 	at org.apache.derby.client.am.Blob.getLocatorLength(Unknown Source)
> 	at org.apache.derby.client.am.Lob.sqlLength(Unknown Source)
> 	at org.apache.derby.client.am.Blob.length(Unknown Source)
>
> Has anyone seen something like this before?  What is the cause of the problem?  
> The exact same code on the exact same version of Derby doesn't cause the same 
> problem over here; could it be something which only happens when unusual 
> network conditions are happening, or something which only happens when the 
> database meets a certain condition?
>
> Daniel
>   
Can you give more information about the code that uses this?

Can you check what version is the derby network server? What version is 
the network client?

This information will be very useful if we try to single step the code 
to find out
the problem source.

 From the attached information I find it a difficult to speculate on the 
source of the failure :(

Narayanan