// KeepLocked indicates whether the sequence lock should be kept for the whole duration of this method.
// Of course the lock should be released in any case when the method returns or throws an exception.
// This is only used if a sequence transaction was begun by the unit of work,
// and will be committed before the unit of work commit.
boolean keepLocked = false;
ConcurrencyManager lock = null;
if (!getOwnerSession().getDatasourceLogin().shouldUseExternalTransactionController() && !writeSession.isInTransaction()) {
// To prevent several threads from simultaneously allocating a separate bunch of
// sequencing numbers each. With keepLocked==true the first thread locks out others
// until it copies the obtained sequence numbers to the global storage.
// Note that this optimization possible only in non-jts case when there is no transaction.
lock = acquireLock(seqName);
try {
sequenceValue = sequencesForName.poll();
if (sequenceValue != null) {
return sequenceValue;
}
writeSession.beginTransaction();//write accessor is set in begin
keepLocked = true;
} finally {
if (!keepLocked) {
lock.release();
}
}
}
Accessor accessor;
Vector localSequencesForName;
if (!keepLocked) {
writeSession.beginTransaction();//write accessor is set in begin
}
try {
accessor = writeSession.getAccessor();
SequencingCallbackImpl seqCallbackImpl = getCallbackImpl(writeSession, accessor);
Map localSequences = seqCallbackImpl.getPreallocatedSequenceValues();
localSequencesForName = (Vector)localSequences.get(seqName);
if ((localSequencesForName == null) || localSequencesForName.isEmpty()) {
localSequencesForName = sequence.getGeneratedVector(null, writeSession);
localSequences.put(seqName, localSequencesForName);
logDebugLocalPreallocation(writeSession, seqName, localSequencesForName, accessor);
}
} catch (RuntimeException ex) {
if (keepLocked) {
lock.release();
}
try {
// make sure to rollback the transaction we've begun
writeSession.rollbackTransaction();
} catch (Exception rollbackException) {
// ignore rollback exception
}
// don't eat the original exception
throw ex;
}
try {
try {
// commitTransaction may copy preallocated sequence numbers
// from localSequences to preallocationHandler: that happens
// if it isn't a nested transaction, and sequencingCallback.afterCommit
// method has been called.
// In this case:
// 1. localSequences corresponding to the accessor
// has been removed from accessorToPreallocated;
// 2. All its members are empty (therefore localSequenceForName is empty).
writeSession.commitTransaction();
} catch (DatabaseException ex) {
try {
// make sure to rollback the transaction we've begun
writeSession.rollbackTransaction();
} catch (Exception rollbackException) {
// ignore rollback exception
}
// don't eat the original exception
throw ex;
}
if (!localSequencesForName.isEmpty()) {
// localSeqencesForName is not empty, that means
// sequencingCallback has not been called.
sequenceValue = localSequencesForName.remove(0);
return sequenceValue;
} else {
// localSeqencesForName is empty, that means
// sequencingCallback has been called.
sequenceValue = sequencesForName.poll();
if (sequenceValue != null) {
return sequenceValue;
}
return getNextValue(sequence, writeSession);
}
} finally {
if(keepLocked) {
lock.release();
}
}
} else {
writeSession.beginTransaction();
try {