You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-dev@db.apache.org by "Bryan Pendleton (JIRA)" <de...@db.apache.org> on 2006/02/19 23:15:52 UTC

[jira] Updated: (DERBY-428) NetworkClient PreparedStatement.executeBatch() hangs if batch is too large (ArrayIndexOutOfBoundsException in Network Server)

     [ http://issues.apache.org/jira/browse/DERBY-428?page=all ]

Bryan Pendleton updated DERBY-428:
----------------------------------

    Attachment: b428.java
                derby-428.diff

Attached is a standalone test program, b428.java, for experimenting with the bug, and a patch proposal, derby-428.diff.

The patch contains a server-side change, a client-side change, and a regression test.

The server-side change is to call ensureLength() in DDMWriter.startDDM(). The DDMWriter working buffer is designed to dynamically grow to accomodate the data being written; this dynamic growth is implemented using a coding rule which requires that all DDMWriter internal routines must call ensureLength to communicate the buffer size requirements of that routine prior to writing bytes into the buffer. StartDDM was missing the call to ensureLength. It was just luck that this hadn't caused any problems in the past; this particular bug exposed the problem in startDDM by causing the server to write a tremendous number of very small DDM records in a single correlated chain, which meant that eventually (around batch element 9000), startDDM tried to write past the end of the buffer without calling ensureLength first. Simple change, even if my explanation is not so clear :)

The client-side change is due to the fact that DRDA imposes a hard limit of 65535 elements in a single correlated request because the correlation identifier is a two byte unsigned integer. Without this change, what happens is that the correlation identifier wraps around when we go to write the 65536th element in the batch, and we start breaking DRDA protocol rules since DRDA requires that the correlation IDs in a single request be always increasing. The change in this patch proposal causes the client to throw an exception if it is asked to execute a batch containing more than 65534 elements. The reason for the number 65534, rather than 65535, is that the value 0xFFFF seems to be reserved for some special purpose.

Experimenting with the JCC driver, I discovered that it seems to reserve more than just 0xFFFF, but also 0xFFFE and 0xFFFD as special values; the largest number of elements that I could succcessfully execute in a single batch with the JCC driver is 65532. I don't know what is going on with those special values, unfortunately.

The regression test verifies that we can successfully execute a batch containing 65532 elements with both the Network Client and JCC drivers. The test also verifies that, if we are using the Network Client, then we get the expected exception if we try to execute a batch with more than 65534 elements.

Comments, suggestions, and feedback are welcome!



> NetworkClient PreparedStatement.executeBatch() hangs if batch is too large (ArrayIndexOutOfBoundsException in Network Server)
> -----------------------------------------------------------------------------------------------------------------------------
>
>          Key: DERBY-428
>          URL: http://issues.apache.org/jira/browse/DERBY-428
>      Project: Derby
>         Type: Bug
>   Components: Network Client
>  Environment: Linux atum01 2.4.20-31.9 #1 Tue Apr 13 18:04:23 EDT 2004 i686 i686 i386 GNU/Linux
> Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
> Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode, sharing)
>     Reporter: Bernt M. Johnsen
>     Assignee: Bryan Pendleton
>  Attachments: b428.java, derby-428.diff
>
> When running
>         s.executeUpdate("create table t (i integer)");
>         PreparedStatement p = c.prepareStatement("insert into t values(?)");
>         for (int i=0; i<N; i++) {
>             p.setInt(1,i);
>             p.addBatch();
>         }
>         System.out.println("Ok");
>         p.executeBatch();
> If  N is 9000
> The server reports:
> 524272
> java.lang.ArrayIndexOutOfBoundsException: 524272
>         at org.apache.derby.impl.drda.DDMWriter.startDdm(DDMWriter.java:315)
>         at org.apache.derby.impl.drda.DRDAConnThread.writeSQLCARD(DRDAConnThread.java:4937)
>         at org.apache.derby.impl.drda.DRDAConnThread.writeSQLCARDs(DRDAConnThread.java:4898)
>         at org.apache.derby.impl.drda.DRDAConnThread.writeSQLCARDs(DRDAConnThread.java:4888)
>         at org.apache.derby.impl.drda.DRDAConnThread.checkWarning(DRDAConnThread.java:7239)
>         at org.apache.derby.impl.drda.DRDAConnThread.parseEXCSQLSTT(DRDAConnThread.java:3605)
>         at org.apache.derby.impl.drda.DRDAConnThread.processCommands(DRDAConnThread.java:859)
>         at org.apache.derby.impl.drda.DRDAConnThread.run(DRDAConnThread.java:214)
> agentThread[DRDAConnThread_3,5,main]
> While the client hangs in executeBatch().
> If N is 8000, the client gets the following Exception:
> Exception in thread "main" org.apache.derby.client.am.BatchUpdateException: Non-atomic batch failure.  The batch was submitted, but at least one exception occurred on an individual member of the batch. Use getNextException() to retrieve the exceptions for specific batched elements.
>         at org.apache.derby.client.am.Agent.endBatchedReadChain(Agent.java:267)
>         at org.apache.derby.client.am.PreparedStatement.executeBatchRequestX(PreparedStatement.java:1596)
>         at org.apache.derby.client.am.PreparedStatement.executeBatchX(PreparedStatement.java:1467)
>         at org.apache.derby.client.am.PreparedStatement.executeBatch(PreparedStatement.java:945)
>         at AOIB.main(AOIB.java:24)

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira