[
https://issues.apache.org/jira/browse/DERBY-3844?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Kristian Waagan updated DERBY-3844:
-----------------------------------
Attachment: derby-3844-1a-repro_test.diff
Attaching a repro for the bug.
Even though generating the junk data seems to trigger garbage collection, I
added calls to do gc and finalization for good measure (I'm aware that the call
to do gc may be a no-op).
The trouble in this case is the use of the pattern rs.getBlob(1).blobMethod(),
followed by another operation on the same BLOB field, and combined with
gc/finalization. The result set generates a new Blob object for each call to
getBlob, and this object has a finalize-method closing the source stream (and
unlatching the source page).
Without having studied this in detail, I think there are two main lines of
fixing this:
1) Disallow calling getBlob multiple times on the same column (and the same
row).
2) Make the result set smarter, or somehow make sure the source stream isn't
closed too early.
(1) is the simplest, but may break existing applications (including some of our
own tests for sure). I have not consulted the JDBC spec on this.
(2) is probably harder, may have performance impacts and we run the risk of
introducing resource leaks (this may be cleaned up in commit/rollback anyway).
I think it should be possible to get this right, but it will make the result
set slightly fatter.
The discussion about calling various result set methods multiple times seems
familiar, but I'm not sure we reached consensus the last time...
The Java SE 6 JavaDoc isn't very authoritative:
"For maximum portability, result set columns within each row should be read in
left-to-right order, and each column should be read only once."
Having gotten this far in my post, won't this be a problem anyway if the user
calls Blob.free?
Assuming obtaining multiple Blob-objects for the same BLOB field is allowed,
should a Blob.free affect the other "instances"?
I fear we are about to wander off into the tall weeds, and in my opinion we
should try to improve the situation such that it is clear to the user what is
allowed and what isn't when it comes to LOBs and streams. I don't know how much
stricter we would have to be, and I'm willing to postpone this until 11.0, but
I'd rather do it earlier.
I'm far from having the overview, but note that other situations get us into
trouble too. We already have Jiras logged where queries like "select blob as
b1, blob as b2" cause errors.
> ASSERT failure in BasePage.unlatch() when running LobStreamsTest
> ----------------------------------------------------------------
>
> Key: DERBY-3844
> URL: https://issues.apache.org/jira/browse/DERBY-3844
> Project: Derby
> Issue Type: Bug
> Components: Store
> Affects Versions: 10.5.1.1
> Environment: Solaris 10, AMD Opteron with 2 CPUs, Java(TM) SE Runtime
> Environment (build 1.6.0_06-b02), Derby trunk revision 686755
> Reporter: Knut Anders Hatlen
> Attachments: derby-3844-1a-repro_test.diff
>
>
> I saw this failure when running suites.All to test the patch
> nested_transaction_v2.diff which is posted on DERBY-3693. The failure did not
> occur when I reran the test, and I don't believe the patch should have any
> effect on the code that failed. The ASSERT that is triggered is this one
> (which indicates that we're trying to unlatch a page that's not latched):
> if (SanityManager.DEBUG) {
> SanityManager.ASSERT(isLatched());
> }
> Here's the full stack trace and thread dump:
> 1)
> testBlobWrite3Param(org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest)org.apache.derby.shared.common.sanity.AssertFailure:
> ASSERT FAILED
> at
> org.apache.derby.shared.common.sanity.SanityManager.ASSERT(SanityManager.java:98)
> at
> org.apache.derby.impl.store.raw.data.BasePage.unlatch(BasePage.java:1319)
> at
> org.apache.derby.impl.store.raw.data.OverflowInputStream.fillByteHolder(OverflowInputStream.java:152)
> at
> org.apache.derby.impl.store.raw.data.BufferedByteHolderInputStream.read(BufferedByteHolderInputStream.java:44)
> at java.io.DataInputStream.read(DataInputStream.java:132)
> at
> org.apache.derby.impl.jdbc.PositionedStoreStream.read(PositionedStoreStream.java:106)
> at
> org.apache.derby.impl.jdbc.AutoPositioningStream.read(AutoPositioningStream.java:113)
> at
> org.apache.derby.impl.jdbc.UpdatableBlobStream.read(UpdatableBlobStream.java:194)
> at
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.readBytesFromStream(LobStreamsTest.java:463)
> at
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.compareLob2File(LobStreamsTest.java:488)
> at
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.testBlobWrite3Param(LobStreamsTest.java:130)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
> at
> org.apache.derbyTesting.junit.BaseTestCase.runBare(BaseTestCase.java:104)
> at junit.extensions.TestDecorator.basicRun(TestDecorator.java:24)
> at junit.extensions.TestSetup$1.protect(TestSetup.java:21)
> at junit.extensions.TestSetup.run(TestSetup.java:25)
> at
> org.apache.derbyTesting.junit.BaseTestSetup.run(BaseTestSetup.java:57)
> ---------------
> Stack traces for all live threads:
> Thread name=derby.antiGC id=280 priority=1 state=WAITING isdaemon=true
> java.lang.Object.wait(Native Method)
> java.lang.Object.wait(Object.java:485)
> org.apache.derby.impl.services.monitor.AntiGC.run(BaseMonitor.java:2217)
> java.lang.Thread.run(Thread.java:619)
> Thread name=Signal Dispatcher id=4 priority=9 state=RUNNABLE isdaemon=true
> Thread name=main id=1 priority=5 state=RUNNABLE isdaemon=false
> java.lang.Thread.dumpThreads(Native Method)
> java.lang.Thread.getAllStackTraces(Thread.java:1477)
>
> org.apache.derby.shared.common.sanity.ThreadDump.getStackDumpString(ThreadDump.java:34)
> sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>
> org.apache.derby.shared.common.sanity.AssertFailure$1.run(AssertFailure.java:165)
> java.security.AccessController.doPrivileged(Native Method)
>
> org.apache.derby.shared.common.sanity.AssertFailure.dumpThreads(AssertFailure.java:159)
>
> org.apache.derby.shared.common.sanity.AssertFailure.<init>(AssertFailure.java:82)
>
> org.apache.derby.shared.common.sanity.SanityManager.ASSERT(SanityManager.java:98)
>
> org.apache.derby.impl.store.raw.data.BasePage.unlatch(BasePage.java:1319)
>
> org.apache.derby.impl.store.raw.data.OverflowInputStream.fillByteHolder(OverflowInputStream.java:152)
>
> org.apache.derby.impl.store.raw.data.BufferedByteHolderInputStream.read(BufferedByteHolderInputStream.java:44)
> java.io.DataInputStream.read(DataInputStream.java:132)
>
> org.apache.derby.impl.jdbc.PositionedStoreStream.read(PositionedStoreStream.java:106)
>
> org.apache.derby.impl.jdbc.AutoPositioningStream.read(AutoPositioningStream.java:113)
>
> org.apache.derby.impl.jdbc.UpdatableBlobStream.read(UpdatableBlobStream.java:194)
>
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.readBytesFromStream(LobStreamsTest.java:463)
>
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.compareLob2File(LobStreamsTest.java:488)
>
> org.apache.derbyTesting.functionTests.tests.jdbcapi.LobStreamsTest.testBlobWrite3Param(LobStreamsTest.java:130)
> sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
>
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
>
> org.apache.derbyTesting.junit.BaseTestCase.runBare(BaseTestCase.java:104)
> junit.extensions.TestDecorator.basicRun(TestDecorator.java:24)
> junit.extensions.TestSetup$1.protect(TestSetup.java:21)
> junit.extensions.TestSetup.run(TestSetup.java:25)
> org.apache.derbyTesting.junit.BaseTestSetup.run(BaseTestSetup.java:57)
> Thread name=derby.rawStoreDaemon id=941 priority=5 state=TIMED_WAITING
> isdaemon=true
> java.lang.Object.wait(Native Method)
>
> org.apache.derby.impl.services.daemon.BasicDaemon.rest(BasicDaemon.java:571)
>
> org.apache.derby.impl.services.daemon.BasicDaemon.run(BasicDaemon.java:388)
> java.lang.Thread.run(Thread.java:619)
> Thread name=Timer-3 id=281 priority=5 state=WAITING isdaemon=true
> java.lang.Object.wait(Native Method)
> java.lang.Object.wait(Object.java:485)
> java.util.TimerThread.mainLoop(Timer.java:483)
> java.util.TimerThread.run(Timer.java:462)
> Thread name=Finalizer id=3 priority=8 state=WAITING isdaemon=true
> java.lang.Object.wait(Native Method)
> java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
> java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
> java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
> Thread name=Reference Handler id=2 priority=10 state=WAITING isdaemon=true
> java.lang.Object.wait(Native Method)
> java.lang.Object.wait(Object.java:485)
> java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
> Thread name=derby.rawStoreDaemon id=933 priority=5 state=TIMED_WAITING
> isdaemon=true
> java.lang.Object.wait(Native Method)
>
> org.apache.derby.impl.services.daemon.BasicDaemon.rest(BasicDaemon.java:571)
>
> org.apache.derby.impl.services.daemon.BasicDaemon.run(BasicDaemon.java:388)
> java.lang.Thread.run(Thread.java:619)
> ---------------
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.