Author: jacopoc
Date: Fri Aug 29 16:26:51 2014 New Revision: 1621335 URL: http://svn.apache.org/r1621335 Log: Fixed an issue affecting the thread safeness of the SequenceBank objects. Added two unit tests to confirm the proper behavior of the SequenceUtil class; the second test fails without the fix committed with this revision. Part of OFBIZ-2353. This is just the first pass of my work to refactor the SequenceUtil. Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1621335&r1=1621334&r2=1621335&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java Fri Aug 29 16:26:51 2014 @@ -27,9 +27,16 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; import javax.sql.rowset.serial.SerialBlob; +import org.ofbiz.base.concurrent.ExecutionPool; import org.ofbiz.base.util.Debug; import org.ofbiz.base.util.Observable; import org.ofbiz.base.util.Observer; @@ -38,6 +45,7 @@ import org.ofbiz.base.util.UtilMisc; import org.ofbiz.base.util.UtilXml; import org.ofbiz.entity.Delegator; import org.ofbiz.entity.DelegatorFactory; +import org.ofbiz.entity.GenericDelegator; import org.ofbiz.entity.GenericEntity; import org.ofbiz.entity.GenericEntityException; import org.ofbiz.entity.GenericPK; @@ -56,6 +64,7 @@ import org.ofbiz.entity.transaction.Tran import org.ofbiz.entity.util.EntityFindOptions; import org.ofbiz.entity.util.EntityListIterator; import org.ofbiz.entity.util.EntitySaxReader; +import org.ofbiz.entity.util.SequenceUtil; public class EntityTestSuite extends EntityTestCase { @@ -1069,6 +1078,62 @@ public class EntityTestSuite extends Ent assertNull("Delete TestingType 2", testType); } + public void testSequenceValueItem() { + SequenceUtil sequencer = new SequenceUtil((GenericDelegator)delegator, delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")), + delegator.getModelEntity("SequenceValueItem"), + "seqName", "seqId"); + UUID id = UUID.randomUUID(); + String sequenceName = "BogusSequence" + id.toString(); + for (int i = 10000; i <= 10015; i++) { + Long seqId = sequencer.getNextSeqId(sequenceName, 1, null); + assertEquals(seqId.longValue(), i); + } + sequencer.forceBankRefresh(sequenceName, 1); + Long seqId = sequencer.getNextSeqId(sequenceName, 1, null); + assertEquals(seqId.longValue(), 10020); + } + + public void testSequenceValueItemWithConcurrentThreads() { + final SequenceUtil sequencer = new SequenceUtil((GenericDelegator)delegator, delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")), + delegator.getModelEntity("SequenceValueItem"), + "seqName", "seqId"); + UUID id = UUID.randomUUID(); + final String sequenceName = "BogusSequence" + id.toString(); + final ConcurrentMap<Long, Long> seqIds = new ConcurrentHashMap<Long, Long>(); + final AtomicBoolean duplicateFound = new AtomicBoolean(false); + final AtomicBoolean nullSeqIdReturned = new AtomicBoolean(false); + + List<Future<Void>> futures = new ArrayList<Future<Void>>(); + Callable getSeqIdTask = new Callable() { + public Callable<Void> call() throws Exception { + Long seqId = sequencer.getNextSeqId(sequenceName, 1, null); + if (seqId == null) { + nullSeqIdReturned.set(true); + return null; + } + Long existingValue = seqIds.putIfAbsent(seqId, seqId); + if (existingValue != null) { + duplicateFound.set(true); + } + return null; + } + }; + Callable refreshTask = new Callable() { + public Callable<Void> call() throws Exception { + sequencer.forceBankRefresh(sequenceName, 1); + return null; + } + }; + double probabilityOfRefresh = 0.1; + for (int i = 1; i <= 1000; i++) { + Callable randomTask = Math.random() < probabilityOfRefresh ? refreshTask : getSeqIdTask; + futures.add(ExecutionPool.GLOBAL_FORK_JOIN.submit(randomTask)); + } + ExecutionPool.getAllFutures(futures); + assertFalse("Null sequence id returned", nullSeqIdReturned.get()); + assertFalse("Duplicate sequence id returned", duplicateFound.get()); + } + private final class TestObserver implements Observer { private Observable observable; private Object arg; Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java?rev=1621335&r1=1621334&r2=1621335&view=diff ============================================================================== --- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java (original) +++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java Fri Aug 29 16:26:51 2014 @@ -157,7 +157,7 @@ public class SequenceUtil { } } - private void refresh(long staggerMax) { + private synchronized void refresh(long staggerMax) { this.curSeqId = this.maxSeqId; this.fillBank(staggerMax); } |
Free forum by Nabble | Edit this page |