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

Rick Hillegas commented on DERBY-6554:
--------------------------------------

Hi Mike,

Some responses to your comments:

MM> can you comment on why you decided to throw a new exception on self 
deadlock rather than just throw 
MM> deadlock? Just throwing deadlock would solve the problem if it ever leaks 
out, and seems the right choice.
MM> 
MM> But, maybe you need the distinct error for a logic path.

Yes, that is the problem. SequenceUpdater needs to distinguish a SelfDeadlock 
from an ordinary Deadlock.

MM> 
MM> It is hard with java to guarantee that these exceptions which are meant to 
always be caught internally
MM> never leak. I think the only completely safe way is to create something 
different than a StandardException
MM> and then explicitly declare it - but my guess is that is going to be 
painful with such a low level routine
MM> that is likely used by a lot of paths.

I can create a SelfDeadlock subtype of StandardException. StandardException 
already has a few subtypes. But that won't address the performance question.

MM> Trying to think about the compress self deadlock issue.
MM> 
MM> o Before your change is a lock timeout ever raised in the case of 0 wait 
lock request?
MM> 

I don't think so. It appears to me that ConcurrentLockSet.lockObject() returns 
null if you can't get a lock immediately and (AbstractPool.noLockWait(timeout, 
compatibilitySpace) == true). But I don't understand what condition sets up the 
special "else" case in AbstractPool.noLockWait():

{noformat}
    static boolean noLockWait(int timeout, CompatibilitySpace compat) {
        if (timeout == C_LockFactory.NO_WAIT) {
            return true;
        } else {
            LockOwner owner = compat.getOwner();
            return owner != null && owner.noWait();
        }
    }
{noformat}

MM> o Do any of your changes require a self deadlock exception to be raised in 
the case of 0 wait lock request?
MM> 

The requirement is that SequenceUpdater have a way to figure out that 
SelfDeadlock happened. That is, that it was blocked by its own (parent 
transaction) lock rather than by a lock held by another Connection. There are a 
lot of code layers between SequenceUpdater and ConcurrentLockSet. There may be 
some way to signal SelfDeadlock without raising an exception. This would 
involve changes to the ConglomerateController interface and maybe some other 
interfaces.

MM> I with this new lock functionality that sequences will wait for some time 
for the lock now that self deadlock
MM> will return immediately so won't be following the 0 wait lock request code 
path.
MM> 
MM> If possible it would seem better not to raise an exception at all in this 
case where the request to lock
MM> manager asked not to wait at all.

Agreed.

MM> Does the following work/make sense:
MM> 
MM> Change lock manger to continue to return no exception if lock can not be 
granted if lock is 0 wait. Hopefully
MM> this would then limit impact on other parts of the code until they can be 
changed to take advantage of the
MM> new functionality.
MM> 
MM> Change lock manger to always check for self deadlock (if it has the 
available fields to check), if a 
MM> non-0 wait lock can not be granted, and throw exception if it is a self 
deadlock.
MM> 
MM> Change DataDictionaryImpl.java!updateCurrentSequenceValue to always wait 
for the lock, knowing that
MM> it will be a 0 wait if it is a self deadlock, and then change caller to 
catch and retry on appropriate exception
MM> thrown. Not many comments in this routine, but I think all the wait inputs 
and complication was to take
MM> care of the problem being solved by doing self deadlock detection. So maybe 
both caller and this code
MM> can be simplified by always waiting. Not sure how much to wait - either 
user set wait, or internal hard
MM> coded, or some combination of both - for instance may want to wait some in 
internal transaction even if
MM> user has specified 0 wait for user locks

Not sure I follow. I think what you are suggesting is the following:

1) Have SequenceUpdater wait for the smallest non-zero timeout, 1 millisecond. 
The smaller the timeout the better. We want to prevent threads from piling up 
like a train wreck behind a request to allocate a new range of sequence values.

2) Only raise SelfDeadlock if the timeout is non-zero.

I think I would like to try another solution first:

1) Currently, all negative values of derby.locks.waitTimeout are collapsed into 
a single meaning: WaitForever. We can give Integer.MIN_VALUE a special meaning: 
DontWaitButRaiseSelfDeadlockOnFailure

2) The lock manager will raise SelfDeadlock only if the timeout value is 
DontWaitButRaiseSelfDeadlockOnFailure.

3) At least initially, SequenceUpdater will be the only caller who requests a 
lock with a timeout of DontWaitButRaiseSelfDeadlockOnFailure.


> Too much contention followed by assert failure when accessing sequence in 
> transaction that created it
> -----------------------------------------------------------------------------------------------------
>
>                 Key: DERBY-6554
>                 URL: https://issues.apache.org/jira/browse/DERBY-6554
>             Project: Derby
>          Issue Type: Bug
>          Components: SQL
>    Affects Versions: 10.9.1.0, 10.11.0.0, 10.10.2.0
>            Reporter: Knut Anders Hatlen
>         Attachments: D6554.java, D6554_2.java, 
> derby-6554-01-aa-useCreationTransaction.diff, 
> derby-6554-01-ab-useCreationTransaction.diff, 
> derby-6554-01-ac-useCreationTransaction.diff, derby-6554-01-ad-bugfixes.diff, 
> derby-6554-02-aa-selfDeadlock.diff, derby-6554-02-ab-selfDeadlock.diff, 
> derby-6554-02-ac-selfDeadlock.diff, 
> derby-6554-02-ae-selfDeadlock_sps_compress.diff
>
>
> {noformat}
> ij version 10.11
> ij> connect 'jdbc:derby:memory:db;create=true' as c1;
> ij> autocommit off;
> ij> create sequence seq;
> 0 rows inserted/updated/deleted
> ij> values next value for seq;
> 1          
> -----------
> ERROR X0Y84: Too much contention on sequence SEQ. This is probably caused by 
> an uncommitted scan of the SYS.SYSSEQUENCES catalog. Do not query this 
> catalog directly. Instead, use the SYSCS_UTIL.SYSCS_PEEK_AT_SEQUENCE function 
> to view the current value of a query generator.
> ij> rollback;
> ERROR 08003: No current connection.
> ij> connect 'jdbc:derby:memory:db' as c2;
> ij(C2)> autocommit off;
> ij(C2)> create sequence seq;
> 0 rows inserted/updated/deleted
> ij(C2)> values next value for seq;
> 1          
> -----------
> ERROR 38000: The exception 
> 'org.apache.derby.shared.common.sanity.AssertFailure: ASSERT FAILED Identity 
> being changed on a live cacheable. Old uuidString = 
> 0ddd00a9-0145-98ba-79df-000007d88b08' was thrown while evaluating an 
> expression.
> ERROR XJ001: Java exception: 'ASSERT FAILED Identity being changed on a live 
> cacheable. Old uuidString = 0ddd00a9-0145-98ba-79df-000007d88b08: 
> org.apache.derby.shared.common.sanity.AssertFailure'.
> {noformat}



--
This message was sent by Atlassian JIRA
(v6.2#6252)

Reply via email to