[
https://issues.apache.org/jira/browse/DERBY-6975?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
David Sitsky updated DERBY-6975:
--------------------------------
Summary: ERROR 40XL1: A lock could not be obtained within the time
requested (was: Bug in SequenceUpdater.getCurrentValueAndAdvance - break used
instead of continue)
> ERROR 40XL1: A lock could not be obtained within the time requested
> --------------------------------------------------------------------
>
> Key: DERBY-6975
> URL: https://issues.apache.org/jira/browse/DERBY-6975
> Project: Derby
> Issue Type: Bug
> Components: SQL
> Affects Versions: 10.14.1.0
> Reporter: David Sitsky
> Attachments: fix.patch
>
>
> I have an application that sporadically gets this exception when inserting a
> lot of rows using a sequence generator.
> {noformat}
> Caused by: ERROR 40XL1: A lock could not be obtained within the time
> requested
> at
> org.apache.derby.iapi.error.StandardException.newException(StandardException.java)
>
> at
> org.apache.derby.iapi.error.StandardException.newException(StandardException.java)
>
> at
> org.apache.derby.impl.sql.catalog.SequenceUpdater.tooMuchContentionException(SequenceUpdater.java)
>
> at
> org.apache.derby.impl.sql.catalog.SequenceUpdater.getCurrentValueAndAdvance(SequenceUpdater.java)
>
> at
> org.apache.derby.impl.sql.catalog.DataDictionaryImpl.getCurrentValueAndAdvance(DataDictionaryImpl.java)
>
> at
> org.apache.derby.impl.sql.execute.BaseActivation.getCurrentValueAndAdvance(BaseActivation.java)
>
> at
> org.apache.derby.impl.sql.execute.InsertResultSet.getSetAutoincrementValue(InsertResultSet.java)
>
> at
> org.apache.derby.impl.sql.execute.BaseActivation.getSetAutoincrementValue(BaseActivation.java)
>
> at
> org.apache.derby.exe.ac560740aax015fx6bc1x68cax000002339e626a.e0(ac560740aax015fx6bc1x68cax000002339e626a.java)
>
> at
> org.apache.derby.impl.services.reflect.DirectCall.invoke(DirectCall.java)
> at
> org.apache.derby.impl.sql.execute.RowResultSet.getNextRowCore(RowResultSet.java)
>
> at
> org.apache.derby.impl.sql.execute.NormalizeResultSet.getNextRowCore(NormalizeResultSet.java)
>
> at
> org.apache.derby.impl.sql.execute.DMLWriteResultSet.getNextRowCore(DMLWriteResultSet.java)
>
> at
> org.apache.derby.impl.sql.execute.InsertResultSet.getNextRowCore(InsertResultSet.java)
>
> at
> org.apache.derby.impl.sql.execute.InsertResultSet.open(InsertResultSet.java)
> at
> org.apache.derby.impl.sql.GenericPreparedStatement.executeStmt(GenericPreparedStatement.java)
>
> at
> org.apache.derby.impl.sql.GenericPreparedStatement.execute(GenericPreparedStatement.java)
>
> ... 25 more
> {noformat}
> When I look at the code in question, it comes down to this method:
> {code}
> /**
> * <p>
> * Get the next sequence number managed by this generator and advance the
> number. Could raise an
> * exception if the legal range is exhausted and wrap-around is not
> allowed.
> * Only one thread at a time is allowed through here. We do not want a
> race between the
> * two calls to the sequence generator: getCurrentValueAndAdvance() and
> allocateNewRange().
> * </p>
> *
> * @param returnValue This value is stuffed with the new sequence number.
> */
> public synchronized void getCurrentValueAndAdvance
> ( NumberDataValue returnValue ) throws StandardException
> {
> //
> // We may have to try to get a value from the Sequence Generator
> twice.
> // The first attempt may fail because we need to pre-allocate a new
> chunk
> // of values.
> //
> for ( int i = 0; i < 2; i++ )
> {
> //
> // We try to get a sequence number. The SequenceGenerator method
> is synchronized
> // so only one writer should be in there at a time. Lock
> contention is possible if
> // someone has selected from SYSSEQUENCES contrary to our advice.
> In that case,
> // we raise a TOO MUCH CONTENTION exception.
> //
> long[] cvaa = _sequenceGenerator.getCurrentValueAndAdvance();
>
> int status = (int) cvaa[ SequenceGenerator.CVAA_STATUS ];
> long currentValue = cvaa[ SequenceGenerator.CVAA_CURRENT_VALUE ];
> long lastAllocatedValue = cvaa[
> SequenceGenerator.CVAA_LAST_ALLOCATED_VALUE ];
> long numberOfValuesAllocated = cvaa[
> SequenceGenerator.CVAA_NUMBER_OF_VALUES_ALLOCATED ];
>
> switch ( status )
> {
> case SequenceGenerator.RET_OK:
> returnValue.setValue( currentValue );
> return;
>
> case SequenceGenerator.RET_MARK_EXHAUSTED:
> updateCurrentValueOnDisk( currentValue, null );
> returnValue.setValue( currentValue );
> return;
>
> case SequenceGenerator.RET_ALLOCATE_NEW_VALUES:
>
> if ( updateCurrentValueOnDisk( currentValue,
> lastAllocatedValue ) )
> {
> _sequenceGenerator.allocateNewRange( currentValue,
> numberOfValuesAllocated );
> }
> break;
>
> default:
> throw unimplementedFeature();
> }
> }
> //
> // If we get here, then we failed to allocate a new sequence number
> range.
> //
> throw tooMuchContentionException();
> }
> {code}
> If I understand the intent of this code, in the
> SequenceGenerator.RET_ALLOCATE_NEW_VALUES case, we allocate a new sequence
> generator range and then we are meant to re-execute the loop again to use it,
> however since "break" is used we break out of the for loop and throw the
> exception.
> It seems if we replace "break" with 'continue" this will work as expected?
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)