You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
(414) |
Apr
(123) |
May
(448) |
Jun
(180) |
Jul
(17) |
Aug
(49) |
Sep
(3) |
Oct
(92) |
Nov
(101) |
Dec
(64) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(132) |
Feb
(230) |
Mar
(146) |
Apr
(146) |
May
|
Jun
|
Jul
(34) |
Aug
(4) |
Sep
(3) |
Oct
(10) |
Nov
(12) |
Dec
(24) |
2008 |
Jan
(6) |
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
(11) |
Nov
(4) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
From: Bryan T. <tho...@us...> - 2007-11-30 21:54:17
|
Update of /cvsroot/cweb/generic-native/src/test/org/CognitiveWeb/generic/core/ndx In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29240/src/test/org/CognitiveWeb/generic/core/ndx Added Files: TestComparators.java Log Message: Work on the bigdata-GOM integration. --- NEW FILE: TestComparators.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Jan 29, 2007 */ package org.CognitiveWeb.generic.core.ndx; import java.util.Arrays; import java.util.Comparator; import junit.framework.TestCase; /** * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestComparators extends TestCase { /** * */ public TestComparators() { } /** * @param arg0 */ public TestComparators(String arg0) { super(arg0); } public void test_intComparator() { final int lmin = Integer.MIN_VALUE; final int lm1 = -1; final int l0 = 0; final int lp1 = 1; final int lmax = Integer.MAX_VALUE; // values out of order. Integer[] vals = new Integer[] {lmax,lm1,lmin,l0,lp1}; Comparator c = new IntegerComparator(); System.err.println("unsorted values: "+Arrays.toString(vals)); Arrays.sort(vals); System.err.println("sorted values : "+Arrays.toString(vals)); assertTrue("kmin<km1", c.compare(lmin, lm1) < 0); assertTrue("km1<k0", c.compare(lm1, l0) < 0); assertTrue("k0<kp1", c.compare(l0, lp1) < 0); assertTrue("kp1<kmax", c.compare(lp1, lmax) < 0); assertTrue("kmin<kmax", c.compare(lmin, lmax) < 0); } public void test_longComparator() { final long lmin = Long.MIN_VALUE; final long lm1 = -1L; final long l0 = 0L; final long lp1 = 1L; final long lmax = Long.MAX_VALUE; // values out of order. Long[] vals = new Long[] {lmax,lm1,lmin,l0,lp1}; Comparator c = new LongComparator(); System.err.println("unsorted values: "+Arrays.toString(vals)); Arrays.sort(vals); System.err.println("sorted values : "+Arrays.toString(vals)); assertTrue("kmin<km1", c.compare(lmin, lm1) < 0); assertTrue("km1<k0", c.compare(lm1, l0) < 0); assertTrue("k0<kp1", c.compare(l0, lp1) < 0); assertTrue("kp1<kmax", c.compare(lp1, lmax) < 0); assertTrue("kmin<kmax", c.compare(lmin, lmax) < 0); } } |
From: Bryan T. <tho...@us...> - 2007-11-30 21:54:13
|
Update of /cvsroot/cweb/generic-native/src/java/org/CognitiveWeb/generic/core In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29240/src/java/org/CognitiveWeb/generic/core Modified Files: LinkSetIndex.java AbstractBTree.java Log Message: Work on the bigdata-GOM integration. Index: AbstractBTree.java =================================================================== RCS file: /cvsroot/cweb/generic-native/src/java/org/CognitiveWeb/generic/core/AbstractBTree.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** AbstractBTree.java 15 Jun 2006 15:46:50 -0000 1.5 --- AbstractBTree.java 30 Nov 2007 21:54:08 -0000 1.6 *************** *** 48,51 **** --- 48,53 ---- import java.io.IOException; + import java.io.ObjectInput; + import java.io.ObjectOutput; import java.util.Comparator; import java.util.Iterator; *************** *** 92,118 **** } - // /** - // * Constructor. - // * - // * @param om - // * The object manager. - // * @param nativeBTreeId - // * The configured persistent jdbm b+tree object. - // * @param coercer - // * @param successor - // * @param comparator - // */ - // - // public AbstractBTree(ObjectManager om, long nativeBTreeId, Coercer coercer, Successor successor, Comparator comparator ) { - // super( om ); - // if (nativeBTreeId == 0L) { - // throw new IllegalArgumentException(); - // } - // _nativeBTreeId = nativeBTreeId; - // _coercer = coercer; - // _successor = successor; - // _comparator = comparator; - // } - /** * Constructor clusters the new object with the <i>container</i>. --- 94,97 ---- *************** *** 179,189 **** * <p> * The {@link Comparator} that imposes the natural ordering inherent in the ! * data type for the coerced keys. * </p> * <p> ! * This must be a {@link Comparator} for {@link ICompositeKey}s iff the ! * index supports duplicate external keys. Such comparators wrap the basic ! * comparator for the data type and a total ordering on the index using the ! * object identifier of the indexed objects to break ties. * </p> */ --- 158,171 ---- * <p> * The {@link Comparator} that imposes the natural ordering inherent in the ! * data type for the coerced keys and <code>null</code> iff the index does ! * not use an application defined comparator (eg, the keys are always ! * byte[]s). * </p> * <p> ! * When non-<code>null</code> this must be a {@link Comparator} for ! * {@link ICompositeKey}s iff the index supports duplicate external keys. ! * Such comparators wrap the basic comparator for the data type and a total ! * ordering on the index using the object identifier of the indexed objects ! * to break ties. * </p> */ *************** *** 325,330 **** * @return A composite key. */ ! ! abstract public ICompositeKey newCompositeKey( Object coercedKey, long oid ); /** --- 307,311 ---- * @return A composite key. */ ! abstract public Object newCompositeKey( Object coercedKey, long oid ); /** *************** *** 343,347 **** return sb.toString(); } ! /** * <p> --- 324,365 ---- return sb.toString(); } ! ! //************************************************************ ! //********************* Externalizable *********************** ! //************************************************************ ! ! /** ! * <p> ! * This class has NO persistent state - concrete classes MUST extend this ! * method to write out any additional persistent state. ! * </p> ! */ ! public void writeExternal(ObjectOutput out) throws IOException { ! ! super.writeExternal(out); ! ! out.writeLong(_nativeBTreeId); ! out.writeObject(_coercer); ! out.writeObject(_successor); ! out.writeObject(_comparator); ! ! } ! ! /** ! * This class has NO persistent state - concrete classes MUST extend this ! * method to read in any additional persistent state. ! */ ! public void readExternal(ObjectInput in) throws IOException, ! ClassNotFoundException { ! ! super.readExternal(in); ! ! _nativeBTreeId = in.readLong(); ! _coercer = (Coercer) in.readObject(); ! _successor = (Successor) in.readObject(); ! _comparator = (Comparator) in.readObject(); ! ! } ! /** * <p> Index: LinkSetIndex.java =================================================================== RCS file: /cvsroot/cweb/generic-native/src/java/org/CognitiveWeb/generic/core/LinkSetIndex.java,v retrieving revision 1.17 retrieving revision 1.18 diff -C2 -d -r1.17 -r1.18 *** LinkSetIndex.java 15 Jun 2006 15:46:50 -0000 1.17 --- LinkSetIndex.java 30 Nov 2007 21:54:08 -0000 1.18 *************** *** 2584,2594 **** try { ! final Object fromKey = coerce(key); ! final Object toKey = getBTree().getSuccessor().successor(fromKey); ! itr = getBTree().iterator(this,getInternalKey(false,fromKey, null), ! getInternalKey(false,toKey, null), true // resolve values. ); } --- 2584,2600 ---- try { ! final Object fromKey = coerce(key); ! final Object toKey = getBTree().getSuccessor().successor(fromKey); ! itr = getBTree().iterator(this, ! getInternalKey(false/* coerce */, fromKey, null/* what */), ! getInternalKey(false/* coerce */, toKey, null/* what */), ! true // resolve values. ); + // itr = getBTree().iterator(this, + // getInternalKey(false,fromKey, null), + // getInternalKey(false,toKey, null), true // resolve values. + // ); } *************** *** 2596,2602 **** catch (NoSuccessorException ex) { ! // Note: Since there is no possible successor to this ! // value, we just return the tail of the map. ! itr = (ILinkSetIndexIterator) getTail(key); --- 2602,2612 ---- catch (NoSuccessorException ex) { ! /* ! * Note: Since there is no possible successor to this value, we just ! * return the tail of the map. ! */ ! ! log.warn("No successor: key="+key); ! itr = (ILinkSetIndexIterator) getTail(key); *************** *** 2641,2646 **** return getBTree().iterator(this, ! getInternalKey(false,fromKey, null), ! getInternalKey(false,toKey, null), true // resolve values. ); --- 2651,2656 ---- return getBTree().iterator(this, ! getInternalKey(false/* coerce */, fromKey, null/* what */), ! getInternalKey(false/* coerce */, toKey, null/* what */), true // resolve values. ); |
From: Bryan T. <tho...@us...> - 2007-11-30 21:54:02
|
Update of /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/ndx In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29214/src/java/org/CognitiveWeb/generic/core/ndx Modified Files: TestStringTypeIndex.java AbstractIndexTest.java TestCharacterTypeIndex.java Log Message: Work on the bigdata-GOM integration. Index: AbstractIndexTest.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/ndx/AbstractIndexTest.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** AbstractIndexTest.java 15 Jun 2006 15:47:01 -0000 1.5 --- AbstractIndexTest.java 30 Nov 2007 21:53:57 -0000 1.6 *************** *** 92,98 **** * value. */ - abstract public class AbstractIndexTest extends GOMProxyTestCase { /** * --- 92,99 ---- * value. */ abstract public class AbstractIndexTest extends GOMProxyTestCase { + protected final Random r = new Random(); + /** * *************** *** 944,947 **** --- 945,1154 ---- /** + * Generator for random keys with an optional class constraint on the + * property values. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id$ + */ + public class KeyGenerator implements IKeyGenerator { + + private final int maxDistinct; + + private final Class cls; + + private final boolean allowNull = false; + + private final Object[] keys; + + /** + * @param maxDistinct + * This parameter governs the maximum #of distinct keys that + * will be produced by the generator. When zero (0), all keys + * will be distinct - this should be used with an index that + * does not allow duplicate keys. When positive, that many + * distinct keys will be pre-generated and keys will be + * selected randomly (with replacement) from that population - + * this should be used with an index that allows duplicate + * keys. + * @param cls + * The type constraint -or- <code>null</code> iff there is + * no type constraint. + */ + public KeyGenerator( int maxDistinct, Class cls ) { + + this.maxDistinct = maxDistinct; + + this.cls = cls; + + if(maxDistinct==0) { + + // all keys are distinct so we do not pre-generate any keys. + + keys = null; + + } else { + + // pre-generate maxDistinct keys. + + keys = new Object[maxDistinct]; + + for (int i = 0; i < maxDistinct; i++) { + + keys[i] = _randomType.nextObject(r, cls, allowNull); + + } + + } + + } + + public Object nextKey() { + + if(keys==null) { + + // random property value of the specified type. + + // return getRandomString(10) + "-" + (counter++); + + return _randomType.nextObject(r, cls, allowNull); + + } else { + + // choosen at random from a fixed population. + + return keys[r.nextInt(maxDistinct)]; + + } + + } + + } + + /** + * Test helper for the ability to drop/add a link set index and the ability + * of the link set index to continue to track the link set as the later is + * cleared and repopulated. + * + * @todo parameterize to test link sets that allow and that do not allow + * duplicate keys (duplicate keys are allowed by the index used in + * this test since that is the default behavior). + */ + protected void doDropAddTest(int ntrials) { + + final ObjectManager om = getNativeObjectManager(); + + final PropertyClass ac = (PropertyClass) om.getPropertyClass( getUniquePropertyName("assoc")); + + final PropertyClass pc = (PropertyClass) om.getPropertyClass( getUniquePropertyName("value")); + + final Class cls = getType(); + + final IKeyGenerator keyGen = new KeyGenerator(ntrials/* maxDistinct */, cls); + + pc.setType( cls ); + + Generic g = new Generic( om ); + + LinkSet linkSet = (LinkSet) g.getLinkSet( ac ); + + LinkSetIndex ndx = (LinkSetIndex) linkSet.getIndex( pc ); + + /* + * Populate the link set. + */ + final int capacity = ntrials; + + Generic ary[] = new Generic[capacity]; + + for( int i=0; i<capacity; i++ ) { + + Generic t = new Generic( om ); + + t.set(ac,g); + + t.set(pc, keyGen.nextKey() ); + + ary[ i ] = t; + + } + + /* + * Verify the index against the link set. + */ + verify(linkSet, ndx); + + /* + * Clear the link set and verify the index against the link set. This + * breaks the links licensing membership in the link set but does not + * cause the link set members to be removed from the database. + */ + linkSet.clear(); + verify(linkSet, ndx); + + /* + * Add all of the objects back into the link set and verify the index + * against the link set. This verifies that the link set index is + * transparently re-created when the link set becomes non-empty. + */ + for( int i=0; i<capacity; i++ ) { + ary[ i ].set(ac, g); + } + verify(linkSet, ndx); + + /* + * Rebuild the index. + */ + ndx.rebuildIndex(); + + /* + * Verify the rebuilt index against the link set. + */ + verify(linkSet, ndx); + + /* + * Verify that we can rebuild the index again (this operation should be + * repeatable if and when desired). + */ + ndx.rebuildIndex(); + + /* + * Verify the rebuilt index against the link set. + */ + verify(linkSet, ndx); + + /* + * Modify a property value and verify that the index is tracking + * updates. + */ + if( true ) { + Generic t = ary[r.nextInt(ary.length)]; + t.set(pc,keyGen.nextKey()); + verify(linkSet, ndx); + } + + /* + * Unlink a link set member and verify that the index is tracking + * updates. + */ + final Generic unlinked; + if( true ) { + Generic t = ary[r.nextInt(ary.length)]; + t.set(ac,null); + verify(linkSet, ndx); + unlinked = t; + } + + /* + * Re-link a link set member and verify that the index is tracking + * updates. + */ + if( true ) { + unlinked.set(ac,g); + verify(linkSet, ndx); + } + + } + + /** * <p> * Test helper for index stress tests. The stress test creates and deletes *************** *** 982,993 **** * an exception or failed assertion. * * @todo The ability to efficiently drop an index requires (a) that it is * isolated within its own segment(s); and (b) that we factor out the * per-object index state into state on a prototype object so that we * do not have to touch each object in the index when we drop the ! * index. (Re-)building an index of course requires a link set scan. ! * There are opportunities for somewhat greater efficiencies if we ! * sort the link set by property value first when using a btree ! * implementation that handles right most additions efficiently. * * @todo Periodically we can change the indexClass metadata before --- 1189,1204 ---- * an exception or failed assertion. * + * @todo parameterize to test link sets that allow and that do not allow + * duplicate keys (duplicate keys are allowed by the index used in + * this test since that is the default behavior). the key generator + * used must be selected based on whether or not duplicate keys will + * be allowed. + * * @todo The ability to efficiently drop an index requires (a) that it is * isolated within its own segment(s); and (b) that we factor out the * per-object index state into state on a prototype object so that we * do not have to touch each object in the index when we drop the ! * index. (Re-)building an index of course requires a link set scan, ! * which should be chunked and use ordered writes for efficiency. * * @todo Periodically we can change the indexClass metadata before *************** *** 1001,1030 **** * abort (rollback to the last time the native transaction counter * reached zero during a commit). - * - * @todo For GOM for Objectivity the stress test should periodically - * rollover the container or database. This can be achieved either by - * limiting the container or database size for the entire test suite - * or by explicitly running the index stress test with smaller - * container and database limits. Once the notion of a GOM database - * within a GDBMS is established, we can explicitly invoke segment - * rollover. A segment is a contiguous linear address space. Segments - * are typically on the order of 200-400M. The Objectivity container - * concept more of less corresponds to a segment. The Objectivity - * database is both a collection of segments and has some namespace - * mechanisms. */ ! ! public void doStressTest( int maxCreated, int maxOps, Op gen, IKeyGenerator keyGen, boolean logOps ) { ! if (maxCreated < 0 || maxOps < 0) { throw new IllegalArgumentException("no stopping condition"); } if (gen == null) { throw new IllegalArgumentException(); } - Random r = new Random(); - ObjectManager om = getNativeObjectManager(); --- 1212,1230 ---- * abort (rollback to the last time the native transaction counter * reached zero during a commit). */ ! public void doStressTest( int maxCreated, int maxOps, Op gen, boolean logOps ) { ! if (maxCreated < 0 && maxOps < 0) { ! throw new IllegalArgumentException("no stopping condition"); + } if (gen == null) { + throw new IllegalArgumentException(); + } ObjectManager om = getNativeObjectManager(); *************** *** 1045,1049 **** * typed. */ ! valueClass.setType( getType() ); /* --- 1245,1254 ---- * typed. */ ! ! final Class cls = getType(); ! ! final IKeyGenerator keyGen = new KeyGenerator(maxCreated/* maxDistinct */, cls); ! ! valueClass.setType( cls ); /* *************** *** 1056,1060 **** LinkSetIndex ndx = (LinkSetIndex) linkSet.getIndex(valueClass); ! Vector oids = new Vector(); // of created objects. boolean done = false; int[] opsum = new int[Op.lastOp + 1]; // #of times we do each --- 1261,1265 ---- LinkSetIndex ndx = (LinkSetIndex) linkSet.getIndex(valueClass); ! final Vector<Long> oids = new Vector<Long>(); // of created objects. boolean done = false; int[] opsum = new int[Op.lastOp + 1]; // #of times we do each *************** *** 1312,1322 **** final Comparator internalKeyComparator = ndx.getBTree().getComparator(); ! /* ! * The comparator for the coerced form of the keys. This is ! * different iff duplicate keys are supported. ! */ ! final Comparator coercedKeyComparator = (duplicateKeys ? ((CompositeKeyComparator) internalKeyComparator) ! .getDelegate() ! : internalKeyComparator); /* --- 1517,1527 ---- final Comparator internalKeyComparator = ndx.getBTree().getComparator(); ! // /* ! // * The comparator for the coerced form of the keys. This is ! // * different iff duplicate keys are supported. ! // */ ! // final Comparator coercedKeyComparator = (duplicateKeys ? ((CompositeKeyComparator) internalKeyComparator) ! // .getDelegate() ! // : internalKeyComparator); /* *************** *** 1392,1396 **** if (duplicateKeys) { ! assertTrue(internalKey instanceof ICompositeKey); assertEquals("oid", g.getOID(), --- 1597,1602 ---- if (duplicateKeys) { ! // Note: may also be an unsigned byte[]. ! if(internalKey instanceof ICompositeKey) { assertEquals("oid", g.getOID(), *************** *** 1407,1410 **** --- 1613,1618 ---- ((ICompositeKey) internalKey) .getCoercedKey()); + + } } else { *************** *** 1494,1498 **** if( duplicateKeys ) { ! assertTrue( internalKey instanceof ICompositeKey ); assertEquals("oid", g.getOID(), --- 1702,1707 ---- if( duplicateKeys ) { ! // Note: may also be an unsigned byte[]. ! if( internalKey instanceof ICompositeKey ) { assertEquals("oid", g.getOID(), *************** *** 1510,1513 **** --- 1719,1723 ---- coercedVal.equals(((ICompositeKey) internalKey) .getCoercedKey())); + } } else { *************** *** 1528,1534 **** */ ! if( nscanned > 0 ) { assertTrue(internalKeyComparator.compare(lastInternalKey, internalKey) <= 0); } --- 1738,1746 ---- */ ! if( nscanned > 0 && internalKeyComparator!=null) { ! assertTrue(internalKeyComparator.compare(lastInternalKey, internalKey) <= 0); + } *************** *** 1559,1566 **** --- 1771,1806 ---- public Object coerce(Object externalKey) { + return externalKey; + } } + /** + * A short-lived stress test. + */ + public void test_dropAdd() { + + int ntrials = 10; /* 100 */; + + doDropAddTest( ntrials ); + + } + + /** + * A short-lived stress test. Longer lived stress tests can be run by + * increasing the first two arguments by an order of magnitude or more. + */ + public void test_stress() { + + doStressTest(// + 10000,// maxCreated + 100000,// maxOps + getOpGenerator(),// + true//logOps + ); + + } + } Index: TestCharacterTypeIndex.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/ndx/TestCharacterTypeIndex.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** TestCharacterTypeIndex.java 10 Jun 2006 18:15:53 -0000 1.2 --- TestCharacterTypeIndex.java 30 Nov 2007 21:53:57 -0000 1.3 *************** *** 60,74 **** Class getType() { return Character.class; } Object[] getValues() { ! return new Character[]{new Character('a'), ! new Character('m'), ! new Character('z')}; } ! Object successor(Object key) throws NoSuccessorException { return new Character(SuccessorUtil.successor(((Character) key).charValue())); } } --- 60,83 ---- Class getType() { + return Character.class; + } Object[] getValues() { ! ! return new Character[]{ ! new Character('a'), ! new Character('m'), ! new Character('z') ! }; ! } ! Object successor(Object key) throws NoSuccessorException { + return new Character(SuccessorUtil.successor(((Character) key).charValue())); + } + } Index: TestStringTypeIndex.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/ndx/TestStringTypeIndex.java,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** TestStringTypeIndex.java 15 Jun 2006 15:47:01 -0000 1.6 --- TestStringTypeIndex.java 30 Nov 2007 21:53:57 -0000 1.7 *************** *** 48,58 **** package org.CognitiveWeb.generic.core.ndx; - import java.util.Random; - - import org.CognitiveWeb.generic.core.Generic; - import org.CognitiveWeb.generic.core.LinkSet; import org.CognitiveWeb.generic.core.LinkSetIndex; - import org.CognitiveWeb.generic.core.PropertyClass; - import org.CognitiveWeb.generic.core.om.ObjectManager; /** --- 48,52 ---- *************** *** 66,293 **** Class getType() { return String.class; - } - - Object[] getValues() { - return new String[] { "a", "b", "c" }; - } - - Object successor(Object key) throws NoSuccessorException { - return SuccessorUtil.successor((String) key); - } - - /** - * A key generator appropriate for the type constraint (if any) on the - * index. - * - * @return The key generator. - * - * @todo Refactor into {@link AbstractIndexTest}. This will require - * breaking the tests of indices that do and do not allow duplicate - * keys into distinct test classes so that we can run the appropriate - * key generator in each case. It will also require appropriate key - * generators for each test class. Once that is done, refactor the - * {@link #test_stress()} and {@link #test_dropAdd()} test methods - * into the {@link AbstractIndexTest} class so that they are also - * run for each kind of typed and untyped index. - */ - public IKeyGenerator getKeyGenerator() { - - return new StringKeyGenerator(true); } ! /** ! * Key generator takes the type constraint from the index. ! * ! * @author <a href="mailto:tho...@us...">Bryan Thompson</a> ! * @version $Id$ ! */ ! ! public class StringKeyGenerator implements IKeyGenerator { ! ! /** ! * FIXME In order to generate duplicate keys there must be a reasonable ! * period to the keys. In order to guarentee distinct keys we must use a ! * one up identifier to make ties impossible. ! */ ! public StringKeyGenerator( boolean duplicateKeys ) { ! } ! ! public Object nextKey() {return getRandomString(10);} ! ! /** ! * Returns a random string of Unicode characters. The "-" character is ! * NOT included in the returned string and may be used to delimit the ! * random characters from a unique one up identifier to obtain a ! * guarenteed unique value. ! * ! * @param len ! * The maximum length of the string. Each generated literal ! * will have a mean length of <code>len/2</code> and the ! * lengths will be distributed using a normal distribution ! * (bell curve). ! */ ! ! public String getRandomString( int len ) ! { ! ! // final String data = "0123456789!@#$%^&*()`~-_=+[{]}\\|;:'\",<.>/?QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! final String data = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! ! int[] order = getRandomOrder( data.length() ); ! ! int n = getNormalInt( len ); ! StringBuffer sb = new StringBuffer( n ); ! ! int index = 0; - for( int i=0; i<n; i++ ) { - - sb.append( data.charAt( order[ index++ ] ) ); - - if( index == order.length ) { - - index = 0; - - } - - } - - return sb.toString(); - - } - } ! /** ! * Various tests of the ability to drop/add a link set index and the ability ! * of the link set index to continue to track the link set as the later is ! * cleared and repopulated. ! */ ! public void test_dropAdd() { ! ! Random r = new Random(); ! ! ObjectManager om = getNativeObjectManager(); ! ! PropertyClass ac = (PropertyClass) om.getPropertyClass( getUniquePropertyName("assoc")); ! ! PropertyClass pc = (PropertyClass) om.getPropertyClass( getUniquePropertyName("value")); ! ! pc.setType( getType() ); ! ! IKeyGenerator keyGen = getKeyGenerator(); ! ! Generic g = new Generic( om ); ! ! LinkSet linkSet = (LinkSet) g.getLinkSet( ac ); ! ! LinkSetIndex ndx = (LinkSetIndex) linkSet.getIndex( pc ); ! ! /* ! * Populate the link set. ! */ ! final int capacity = 3; /* 100 */ ! ! Generic ary[] = new Generic[capacity]; ! ! for( int i=0; i<capacity; i++ ) { ! ! Generic t = new Generic( om ); ! ! t.set(ac,g); ! ! t.set(pc, keyGen.nextKey() ); ! ! ary[ i ] = t; ! ! } ! ! /* ! * Verify the index against the link set. ! */ ! verify(linkSet, ndx); ! ! /* ! * Clear the link set and verify the index against the link set. This ! * breaks the links licensing membership in the link set but does not ! * cause the link set members to be removed from the database. ! */ ! linkSet.clear(); ! verify(linkSet, ndx); ! ! /* ! * Add all of the objects back into the link set and verify the index ! * against the link set. This verifies that the link set index is ! * transparently re-created when the link set becomes non-empty. ! */ ! for( int i=0; i<capacity; i++ ) { ! ary[ i ].set(ac, g); ! } ! verify(linkSet, ndx); ! ! /* ! * Rebuild the index. ! */ ! ndx.rebuildIndex(); ! ! /* ! * Verify the rebuilt index against the link set. ! */ ! verify(linkSet, ndx); ! /* ! * Verify that we can rebuild the index again (this operation should be ! * repeatable if and when desired). ! */ ! ndx.rebuildIndex(); ! /* ! * Verify the rebuilt index against the link set. ! */ ! verify(linkSet, ndx); ! ! /* ! * Modify a property value and verify that the index is tracking ! * updates. ! */ ! if( true ) { ! Generic t = ary[r.nextInt(ary.length)]; ! t.set(pc,keyGen.nextKey()); ! verify(linkSet, ndx); ! } ! ! /* ! * Unlink a link set member and verify that the index is tracking ! * updates. ! */ ! final Generic unlinked; ! if( true ) { ! Generic t = ary[r.nextInt(ary.length)]; ! t.set(ac,null); ! verify(linkSet, ndx); ! unlinked = t; ! } ! ! /* ! * Re-link a link set member and verify that the index is tracking ! * updates. ! */ ! if( true ) { ! unlinked.set(ac,g); ! verify(linkSet, ndx); ! } ! ! } ! ! /** ! * A short-lived stress test. Longer lived stress tests can be run by ! * increasing the first two arguments by an order of magnitude or more. ! */ ! public void test_stress() { ! doStressTest( 10000, 100000, getOpGenerator(), getKeyGenerator(), false ); ! } } --- 60,79 ---- Class getType() { + return String.class; } ! Object[] getValues() { ! return new String[] { "a", "b", "c" }; } ! Object successor(Object key) throws NoSuccessorException { ! return SuccessorUtil.successor((String) key); ! } } |
From: Bryan T. <tho...@us...> - 2007-11-30 21:54:02
|
Update of /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/om In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29214/src/java/org/CognitiveWeb/generic/core/om Modified Files: TestRollback.java ObjectManagerTestCase.java Log Message: Work on the bigdata-GOM integration. Index: ObjectManagerTestCase.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/om/ObjectManagerTestCase.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** ObjectManagerTestCase.java 10 Jun 2006 18:15:53 -0000 1.3 --- ObjectManagerTestCase.java 30 Nov 2007 21:53:57 -0000 1.4 *************** *** 460,464 **** /** * Test verifies that an object marked for lazy removal is removed before ! * the nested native transaction counter reaches zero if it is becomes only * weakly reachable. */ --- 460,464 ---- /** * Test verifies that an object marked for lazy removal is removed before ! * the nested native transaction counter reaches zero if it becomes only * weakly reachable. */ *************** *** 485,489 **** // create a bunch of objects in order to flush the MRU. ! final int limit = 10000; for( int i=0; i<limit; i++ ) { BaseObject obj = new BaseObject( om ); --- 485,489 ---- // create a bunch of objects in order to flush the MRU. ! final int limit = 20000; for( int i=0; i<limit; i++ ) { BaseObject obj = new BaseObject( om ); Index: TestRollback.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/om/TestRollback.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** TestRollback.java 10 Jun 2006 18:15:53 -0000 1.2 --- TestRollback.java 30 Nov 2007 21:53:57 -0000 1.3 *************** *** 156,160 **** --- 156,171 ---- om.rollbackNativeTransaction(); + /* + * FIXME This will fail unless you reload the references from the + * database since the object manager is not currently invaliding live + * objects that have been touched since the last commit. + */ + // + // g1 = (Generic) om.fetch(g1.getOID()); + // + // g2 = (Generic) om.fetch(g2.getOID()); + assertEquals("g1",g1.get(name)); + assertEquals("g2",g2.get(name)); |
From: Bryan T. <tho...@us...> - 2007-11-30 21:54:02
|
Update of /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29214/src/java/org/CognitiveWeb/generic/core Modified Files: LinkSetIndexSerializationTestCase.java Log Message: Work on the bigdata-GOM integration. Index: LinkSetIndexSerializationTestCase.java =================================================================== RCS file: /cvsroot/cweb/generic-native-test/src/java/org/CognitiveWeb/generic/core/LinkSetIndexSerializationTestCase.java,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** LinkSetIndexSerializationTestCase.java 15 Jun 2006 15:47:01 -0000 1.6 --- LinkSetIndexSerializationTestCase.java 30 Nov 2007 21:53:57 -0000 1.7 *************** *** 366,371 **** /* ! * If a strongly type index was used, then verify that the successor and ! * comparator are non-null. The coercer may still be null depending on * the implementation. If duplicate keys are allowed, then the * LinkSetIndex class itself handles the transparent coercion of keys to --- 366,371 ---- /* ! * If a strongly type index was used, then verify that the successor is ! * non-null. The comparator and coercer may still be null depending on * the implementation. If duplicate keys are allowed, then the * LinkSetIndex class itself handles the transparent coercion of keys to *************** *** 387,396 **** } ! if (type != null) { ! ! assertNotNull("comparator for " + type.getName(), ndx.getBTree() ! .getComparator()); ! ! } /* --- 387,396 ---- } ! // if (type != null) { ! // ! // assertNotNull("comparator for " + type.getName(), ndx.getBTree() ! // .getComparator()); ! // ! // } /* |
From: Bryan T. <tho...@us...> - 2007-11-30 21:53:45
|
Update of /cvsroot/cweb/junit-ext/src/java/junit/framework In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29190/src/java/junit/framework Modified Files: TestCase2.java Log Message: Work on the bigdata-GOM integration. Index: TestCase2.java =================================================================== RCS file: /cvsroot/cweb/junit-ext/src/java/junit/framework/TestCase2.java,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -d -r1.26 -r1.27 *** TestCase2.java 31 Oct 2007 09:51:03 -0000 1.26 --- TestCase2.java 30 Nov 2007 21:53:39 -0000 1.27 *************** *** 1112,1156 **** /** ! * Returns a random but unique string of Unicode characters with a ! * maximum length of len and a minimum length. ! * ! * @param len The maximum length of the string. Each generated ! * literal will have a mean length of <code>len/2</code> and the ! * lengths will be distributed using a normal distribution (bell ! * curve). ! * ! * @param id A unique index used to obtain a unique string. ! * Typically this is a one up identifier. */ ! public String getRandomString( int len, int id ) ! { ! // final String data = "0123456789!@#$%^&*()`~-_=+[{]}\\|;:'\",<.>/?QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! final String data = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! int[] order = getRandomOrder( data.length() ); ! ! int n = getNormalInt( len ); ! ! StringBuffer sb = new StringBuffer( n ); ! int index = 0; ! ! for( int i=0; i<n; i++ ) { ! sb.append( data.charAt( order[ index++ ] ) ); ! if( index == order.length ) { ! ! index = 0; ! ! } ! ! } ! ! sb.append( id ); ! return sb.toString(); } --- 1112,1158 ---- /** ! * Returns a random but unique string of Unicode characters with a maximum ! * length of len and a minimum length. Only alphanumeric characters are ! * present in the string so you can form a unique string by appending a ! * delimiter and an one-up counter. ! * ! * @param len ! * The maximum length of the string. Each generated literal will ! * have a mean length of <code>len/2</code> and the lengths ! * will be distributed using a normal distribution (bell curve). ! * ! * @param id ! * A unique index used to obtain a unique string. Typically this ! * is a one up identifier. */ + public String getRandomString(int len, int id) { ! // final String data = ! // "0123456789!@#$%^&*()`~-_=+[{]}\\|;:'\",<.>/?QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! final String data = "0123456789QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"; ! int[] order = getRandomOrder(data.length()); ! int n = getNormalInt(len); ! StringBuffer sb = new StringBuffer(n); ! int index = 0; ! for (int i = 0; i < n; i++) { ! sb.append(data.charAt(order[index++])); ! ! if (index == order.length) { ! ! index = 0; ! ! } ! ! } ! ! sb.append(id); ! ! return sb.toString(); } *************** *** 1169,1199 **** * An explicit NULL property value. */ ! ! final public static short NULL = 0; ! ! // /** ! // * A directed link to another generic object in the same store. ! // * ! // * @see LinkValue ! // */ ! // ! // final public static short LINK = 1; ! // ! // /** ! // * A BLOB (metadata that supports access to very large binary ! // * objects using a stream oriented API). ! // */ ! // ! // final public static short BLOB = 2; - /** - * The Java primitive type <em>boolean</em>. - * - * Note: Support for primitives recognizes the corresponding - * objects, e.g., {@link Boolean}, and special cases their - * serialization. This significantly reduces their the storage - * requirements. - */ - final public static short BOOLEAN = 20; final public static short BYTE = 21; --- 1171,1176 ---- * An explicit NULL property value. */ ! // final public static short NULL = 0; final public static short BOOLEAN = 20; final public static short BYTE = 21; *************** *** 1204,1207 **** --- 1181,1185 ---- final public static short FLOAT = 26; final public static short DOUBLE = 27; + final public static short STRING = 28; /** *************** *** 1209,1213 **** * Externalizable}). */ - final public static short OBJECT = 30; --- 1187,1190 ---- *************** *** 1215,1219 **** * Array of Java objects (but not Java primitives). */ - final public static short OBJECT_ARRAY = 31; --- 1192,1195 ---- *************** *** 1221,1225 **** * Array of Java primitives. */ - final public static short BOOLEAN_ARRAY = 40; final public static short BYTE_ARRAY = 41; --- 1197,1200 ---- *************** *** 1235,1238 **** --- 1210,1214 ---- // BLOB, BOOLEAN, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, + STRING, OBJECT, // OBJECT_ARRAY, *************** *** 1245,1252 **** // FLOAT_ARRAY, // DOUBLE_ARRAY, ! NULL // Note: null at end to make easy to exclude. }; /** * For random characters. */ --- 1221,1262 ---- // FLOAT_ARRAY, // DOUBLE_ARRAY, ! // NULL // Note: null at end to make easy to exclude. }; /** + * Return the type code for the specified class. + * + * @param cls + * A class. + * @return The type code. + * + * @throws UnsupportedOperationException + * if the class is not one of those that is supported by + * {@link RandomType}. + */ + public int getType(Class cls) { + + if(cls==null) { + + throw new IllegalArgumentException(); + + } + + if(cls.equals(Boolean.class)) return BOOLEAN; + if(cls.equals(Byte.class)) return BYTE; + if(cls.equals(Character.class)) return CHAR; + if(cls.equals(Short.class)) return SHORT; + if(cls.equals(Integer.class)) return INT; + if(cls.equals(Long.class)) return LONG; + if(cls.equals(Float.class)) return FLOAT; + if(cls.equals(Double.class)) return DOUBLE; + if(cls.equals(String.class)) return STRING; + if(cls.equals(Object.class)) return OBJECT; + + throw new UnsupportedOperationException("class="+cls); + + } + + /** * For random characters. */ *************** *** 1256,1267 **** * Returns an object with a random type and random value. * ! * @param rnd The random# generator to use. * ! * @param allowNull When true, a null object reference may be ! * returned. * * @return The random object. */ - public Object nextObject( Random rnd, boolean allowNull ) { --- 1266,1277 ---- * Returns an object with a random type and random value. * ! * @param rnd ! * The random# generator to use. * ! * @param allowNull ! * When true, a null object reference may be returned. * * @return The random object. */ public Object nextObject( Random rnd, boolean allowNull ) { *************** *** 1274,1285 **** int type = types[ rnd.nextInt( range ) ]; Object obj = null; switch( type ) { ! case NULL: { ! return null; ! } case BOOLEAN: { obj = ( rnd.nextBoolean() --- 1284,1347 ---- int type = types[ rnd.nextInt( range ) ]; + + return nextObject( rnd, type , allowNull ); + + } + + /** + * Return an instance of the specified type with a random value. + * + * @param rnd + * The random number generator. + * + * @param cls + * The class of the random instance to be returned -or- + * <code>null</code> to return an instance of any of the + * classes that can be generated by this method. + * + * @param allowNull + * When true, a null object reference may be returned. + * + * @return The random object. + */ + public Object nextObject(Random rnd, Class cls, boolean allowNull) { + if(cls==null) { + + // random object type. + return nextObject(rnd, allowNull); + + } else { + + // specific object type. + return nextObject(rnd, getType(cls), allowNull); + + } + + } + + /** + * Return an instance of the specified type with a random value. + * + * @param rnd + * The random number generator. + * + * @param type + * One of the values declared by this class. + * + * @param allowNull + * When true, a null object reference may be returned. + * + * @return The random object. + */ + public Object nextObject( Random rnd, int type, boolean allowNull ) { + Object obj = null; switch( type ) { ! // case NULL: { ! // return null; ! // } case BOOLEAN: { obj = ( rnd.nextBoolean() *************** *** 1317,1320 **** --- 1379,1386 ---- break; } + case STRING: { + obj = getRandomString( 40, rnd.nextInt() ); + break; + } case OBJECT: { obj = getRandomString( 40, rnd.nextInt() ); *************** *** 1342,1346 **** } ! private RandomType _randomType = new RandomType(); /** --- 1408,1412 ---- } ! protected RandomType _randomType = new RandomType(); /** *************** *** 1670,1674 **** className.replace('.','/') + ".properties" ; ! // Try to load properties from the resource into // the new layer. This uses a helper method that --- 1736,1743 ---- className.replace('.','/') + ".properties" ; ! ! // Note: requires Java 1.5. ! // String resourceName = this.getClass().getSimpleName(); ! // Try to load properties from the resource into // the new layer. This uses a helper method that *************** *** 1676,1680 **** // file system, so that it can find the resource // in a JAR if necessary. ! log.info ( "Will try to read properties from resource: "+ --- 1745,1749 ---- // file system, so that it can find the resource // in a JAR if necessary. ! log.info ( "Will try to read properties from resource: "+ |
From: Bryan T. <tho...@us...> - 2007-11-30 21:53:36
|
Update of /cvsroot/cweb/generic-native/src/test/org/CognitiveWeb/generic/core/ndx In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv29178/src/test/org/CognitiveWeb/generic/core/ndx Log Message: Directory /cvsroot/cweb/generic-native/src/test/org/CognitiveWeb/generic/core/ndx added to the repository |
From: Bryan T. <tho...@us...> - 2007-11-09 12:28:50
|
Update of /cvsroot/cweb/rdf-generic In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv15140 Modified Files: .cvsignore Log Message: .cvsignore Index: .cvsignore =================================================================== RCS file: /cvsroot/cweb/rdf-generic/.cvsignore,v retrieving revision 1.26 retrieving revision 1.27 diff -C2 -d -r1.26 -r1.27 *** .cvsignore 30 Jul 2006 13:41:52 -0000 1.26 --- .cvsignore 9 Nov 2007 12:28:47 -0000 1.27 *************** *** 59,60 **** --- 59,61 ---- documents.tgz .settings + *.xls |
From: Bryan T. <tho...@us...> - 2007-11-09 12:23:32
|
Update of /cvsroot/cweb/lgpl-utils In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv13208 Added Files: .cvsignore Log Message: .cvsignore --- NEW FILE: .cvsignore --- target |
From: Bryan T. <tho...@us...> - 2007-10-31 09:51:09
|
Update of /cvsroot/cweb/junit-ext/src/java/junit/framework In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv19053/src/java/junit/framework Modified Files: TestCase2.java Log Message: Use of generics commented out for 1.4 compatibility. Index: TestCase2.java =================================================================== RCS file: /cvsroot/cweb/junit-ext/src/java/junit/framework/TestCase2.java,v retrieving revision 1.25 retrieving revision 1.26 diff -C2 -d -r1.25 -r1.26 *** TestCase2.java 18 Oct 2007 16:53:59 -0000 1.25 --- TestCase2.java 31 Oct 2007 09:51:03 -0000 1.26 *************** *** 2254,2258 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will --- 2254,2258 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will *************** *** 2329,2333 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will --- 2329,2333 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will *************** *** 2606,2610 **** * if any parameter is null. */ ! static public Throwable getInnerCause(Throwable t, Class<? extends Throwable> cls) { if (t == null) --- 2606,2612 ---- * if any parameter is null. */ ! static public Throwable getInnerCause(Throwable t, Class cls) { ! // Note: Use of generics commented out for 1.4 compatibility. ! // static public Throwable getInnerCause(Throwable t, Class<? extends Throwable> cls) { if (t == null) *************** *** 2649,2653 **** * if any parameter is null. */ ! static public boolean isInnerCause(Throwable t, Class<? extends Throwable>cls) { return getInnerCause(t, cls) != null; --- 2651,2657 ---- * if any parameter is null. */ ! static public boolean isInnerCause(Throwable t, Class cls) { ! // Note: Use of generics commented out for 1.4 compatibility. ! // static public boolean isInnerCause(Throwable t, Class<? extends Throwable>cls) { return getInnerCause(t, cls) != null; |
From: Bryan T. <tho...@us...> - 2007-10-31 09:51:09
|
Update of /cvsroot/cweb/junit-ext In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv19053 Modified Files: .cvsignore Log Message: Use of generics commented out for 1.4 compatibility. Index: .cvsignore =================================================================== RCS file: /cvsroot/cweb/junit-ext/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** .cvsignore 23 May 2006 16:06:05 -0000 1.2 --- .cvsignore 31 Oct 2007 09:51:04 -0000 1.3 *************** *** 3,4 **** --- 3,5 ---- .project doc + .settings |
From: Bryan T. <tho...@us...> - 2007-10-18 16:54:11
|
Update of /cvsroot/cweb/junit-ext/src/test/junit/framework In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv5364/src/test/junit/framework Modified Files: TestCase2TestCase.java Log Message: Added getInnerCause and isInnerCause. Index: TestCase2TestCase.java =================================================================== RCS file: /cvsroot/cweb/junit-ext/src/test/junit/framework/TestCase2TestCase.java,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** TestCase2TestCase.java 23 May 2006 16:06:05 -0000 1.8 --- TestCase2TestCase.java 18 Oct 2007 16:53:59 -0000 1.9 *************** *** 364,370 **** } /** ! * Test helper generates the binary entity read by one of the ! * test cases above. * * @param args --- 364,494 ---- } + public void test_getInnerCause_correctRejection() { + + try { + getInnerCause(null, null); + fail("Expecting: "+IllegalArgumentException.class); + } catch(IllegalArgumentException ex) { + System.err.println("Ignoring expected exception: "+ex); + } + + try { + getInnerCause(null, RuntimeException.class); + fail("Expecting: "+IllegalArgumentException.class); + } catch(IllegalArgumentException ex) { + System.err.println("Ignoring expected exception: "+ex); + } + + try { + getInnerCause(new RuntimeException(), null); + fail("Expecting: "+IllegalArgumentException.class); + } catch(IllegalArgumentException ex) { + System.err.println("Ignoring expected exception: "+ex); + } + + } + /** ! * Finds cause when it is on top of the stack trace and the right type. ! */ ! public void test_getInnerCause01_find_exact() { ! ! Throwable t = new RuntimeException(); ! ! assertTrue(t == getInnerCause(t, RuntimeException.class)); ! ! } ! ! /** ! * Find cause when it is on top of the stack trace and a subclass of the ! * desired type. ! */ ! public void test_getInnerCause01_find_subclass() { ! ! Throwable t = new IOException(); ! ! assertTrue(t == getInnerCause(t, Exception.class)); ! ! } ! ! /** ! * Does not find cause that is a super class of the desired type. ! */ ! public void test_getInnerCause01_reject_superclass() { ! ! Throwable t = new Exception(); ! ! assertNull(getInnerCause(t, IOException.class)); ! ! } ! ! /** ! * Does not find cause when it is on top of the stack trace and not either ! * the desired type or a subclass of the desired type. ! */ ! public void test_getInnerCause01_reject_otherType() { ! ! Throwable t = new Throwable(); ! ! assertNull(getInnerCause(t, Exception.class)); ! ! } ! ! /** ! * Finds inner cause that is the exact type. ! */ ! public void test_getInnerCause02_find_exact() { ! ! Throwable cause = new Exception(); ! ! Throwable t = new Throwable(cause); ! ! assertTrue(cause == getInnerCause(t, Exception.class)); ! ! } ! ! /** ! * Finds inner cause that is a derived type (subclass). ! */ ! public void test_getInnerCause02_find_subclass() { ! ! Throwable cause = new IOException(); ! ! Throwable t = new Throwable(cause); ! ! assertTrue(cause == getInnerCause(t, Exception.class)); ! ! } ! ! /** ! * Does not find inner cause that is a super class of the desired type. ! */ ! public void test_getInnerCause02_reject_superclass() { ! ! Throwable cause = new Exception(); ! ! Throwable t = new RuntimeException(cause); ! ! assertNull( getInnerCause(t, IOException.class)); ! ! } ! ! /** ! * Does not find an inner cause that is neither the specified type nor a ! * subtype of the specified type. ! */ ! public void test_getInnerCause03_reject_otherType() { ! ! Throwable cause = new RuntimeException(); ! ! Throwable t = new Exception(cause); ! ! assertNull( getInnerCause(t, IOException.class) ); ! ! } ! ! /** ! * Test helper generates the binary entity read by one of the test cases ! * above. * * @param args |
From: Bryan T. <tho...@us...> - 2007-10-18 16:54:04
|
Update of /cvsroot/cweb/junit-ext/src/java/junit/framework In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv5364/src/java/junit/framework Modified Files: TestCase2.java Log Message: Added getInnerCause and isInnerCause. Index: TestCase2.java =================================================================== RCS file: /cvsroot/cweb/junit-ext/src/java/junit/framework/TestCase2.java,v retrieving revision 1.24 retrieving revision 1.25 diff -C2 -d -r1.24 -r1.25 *** TestCase2.java 10 Sep 2007 11:09:13 -0000 1.24 --- TestCase2.java 18 Oct 2007 16:53:59 -0000 1.25 *************** *** 2254,2258 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will --- 2254,2258 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will *************** *** 2329,2333 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will --- 2329,2333 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will *************** *** 2590,2592 **** --- 2590,2657 ---- } + /** + * Examines a stack trace for an instance of the specified cause nested to + * any level within that stack trace. + * + * @param t + * The stack trace. + * @param cls + * The class of exception that you are looking for in the stack + * trace. + * + * @return An exception that is an instance of that class iff one exists in + * the stack trace and <code>null</code> otherwise. + * + * @throws IllegalArgumentException + * if any parameter is null. + */ + static public Throwable getInnerCause(Throwable t, Class<? extends Throwable> cls) { + + if (t == null) + throw new IllegalArgumentException(); + + if (cls == null) + throw new IllegalArgumentException(); + + { + Class x = t.getClass(); + while(x != null){ + if( x == cls) + return t; + x = x.getSuperclass(); + } + + } + + t = t.getCause(); + + if (t == null) + return null; + + return getInnerCause(t, cls); + + } + + /** + * Examines a stack trace for an instance of the specified cause nested to + * any level within that stack trace. + * + * @param t + * The stack trace. + * @param cls + * The class of exception that you are looking for in the stack + * trace. + * + * @return <code>true</code> iff an exception that is an instance of that + * class iff one exists in the stack trace. + * + * @throws IllegalArgumentException + * if any parameter is null. + */ + static public boolean isInnerCause(Throwable t, Class<? extends Throwable>cls) { + + return getInnerCause(t, cls) != null; + + } + } |
From: Bryan T. <tho...@us...> - 2007-10-12 12:37:14
|
Update of /cvsroot/cweb/extser In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv27970 Modified Files: project.xml Log Message: POM documentation edit. Index: project.xml =================================================================== RCS file: /cvsroot/cweb/extser/project.xml,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** project.xml 27 May 2006 20:11:03 -0000 1.9 --- project.xml 12 Oct 2007 12:36:51 -0000 1.10 *************** *** 39,44 **** derived persistent classes. Transparent versioning of the serialization format is supported for all objects. Historical ! historical serialization versions are read transparently and ! written by default using the most current serialization version. </p> --- 39,44 ---- derived persistent classes. Transparent versioning of the serialization format is supported for all objects. Historical ! serialization versions are read transparently and written by ! default using the most current serialization version. </p> *************** *** 54,58 **** The DataInputStream and DataOutputStream classes need to know how to pack and unpack object identifiers (OIds) efficiently for ! the target platform. </p> --- 54,60 ---- The DataInputStream and DataOutputStream classes need to know how to pack and unpack object identifiers (OIds) efficiently for ! the target platform. You must also arrange for the persistence ! of the mapping from Class names to class identifiers and the ! ISerializer versions registered against those class identifiers. </p> *************** *** 61,65 **** Applications that make use of this framework need only provide ! implementation of the ISerializer interface and register those implementations with the IExtensibleSerializer provided by their persistence layer. --- 63,67 ---- Applications that make use of this framework need only provide ! implementations of the ISerializer interface and register those implementations with the IExtensibleSerializer provided by their persistence layer. |
From: Bryan T. <tho...@us...> - 2007-10-05 01:14:46
|
Update of /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv19546/src/java/org/CognitiveWeb/concurrent/locking Modified Files: TxDag.java Log Message: Fixed all known problems with the basic concurrency control for 2PL using exclusive locks. Index: TxDag.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/TxDag.java,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** TxDag.java 4 Oct 2007 19:55:30 -0000 1.13 --- TxDag.java 5 Oct 2007 01:14:36 -0000 1.14 *************** *** 1424,1453 **** /** ! * Remove all edges whose target is <i>tx</i>. This method MUST be used ! * when a running transaction completes (either aborts or commits). After ! * calling this method, the transaction is removed completely from the DAG. ! * Failure to use this method will result in the capacity of the DAG being ! * consumed as vertices will not be recycled. ! * ! * @param tx ! * A transaction. ! * ! * @param waiting ! * When false, caller asserts that this transaction it is NOT ! * waiting on any other transaction. This assertion is used to ! * optimize the update of the path count matrix by simply ! * removing the row and column associated with this transaction. ! * When [waiting == true], a less efficient procedure is used to ! * update the path count matrix. ! * <p> ! * Do NOT specify [waiting == false] unless you <em>know</em> ! * that the transaction is NOT waiting. In general, this ! * knowledge is available to the 2PL locking package. ! * ! * @todo Write test cases for this method. It duplicates much of the logic ! * of {@link #removeEdge(Object, Object)} and therefore must be ! * evaluated separately. ! */ ! synchronized public void removeEdges( Object tx, boolean waiting ) { --- 1424,1453 ---- /** ! * Remove all edges whose target is <i>tx</i>. This method SHOULD be used ! * when a running transaction completes (either aborts or commits). After ! * calling this method, the transaction is removed completely from the DAG. ! * Failure to use this method will result in the capacity of the DAG being ! * consumed as vertices will not be recycled unless you call ! * {@link #releaseVertex(Object)}. ! * ! * @param tx ! * A transaction. ! * ! * @param waiting ! * When false, caller asserts that this transaction it is NOT ! * waiting on any other transaction. This assertion is used to ! * optimize the update of the path count matrix by simply ! * removing the row and column associated with this transaction. ! * When [waiting == true], a less efficient procedure is used to ! * update the path count matrix. ! * <p> ! * Do NOT specify [waiting == false] unless you <em>know</em> ! * that the transaction is NOT waiting. In general, this ! * knowledge is available to the 2PL locking package. ! * ! * @todo Write test cases for this method. It duplicates much of the logic ! * of {@link #removeEdge(Object, Object)} and therefore must be ! * evaluated separately. ! */ synchronized public void removeEdges( Object tx, boolean waiting ) { |
From: Bryan T. <tho...@us...> - 2007-10-04 19:55:34
|
Update of /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv26833/src/java/org/CognitiveWeb/concurrent/locking Modified Files: TxDag.java Log Message: Mostly have the concurrency test suites running - there is one remaining problem that I have identified when the lock timeout is non-zero (e.g., 1000ms). This seems likely to be a mishandling of the lock timeout exception. Index: TxDag.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/TxDag.java,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** TxDag.java 3 Oct 2007 19:05:09 -0000 1.12 --- TxDag.java 4 Oct 2007 19:55:30 -0000 1.13 *************** *** 379,383 **** * would be exceeded if this transaction was added. */ - synchronized int lookup( Object tx, boolean insert ) { --- 379,382 ---- *************** *** 458,463 **** * * @return true iff the vertex was known. */ - synchronized public boolean releaseVertex( Object tx ) { --- 457,466 ---- * * @return true iff the vertex was known. + * + * FIXME Should it be an error if there is an edge remaining for that + * vertex? if we do not detect this condition then is is possible that + * uncleared edges will remainin in the WAITS_FOR graph and will interfere + * with reuse of the recycled index? */ synchronized public boolean releaseVertex( Object tx ) { *************** *** 549,553 **** * state of the DAG is unchanged if this exception is thrown. */ - synchronized public void addEdge( Object blocked, Object running ) throws DeadlockException --- 552,555 ---- *************** *** 555,564 **** // verify arguments some more. if( running == blocked ) { ! throw new IllegalArgumentException("transaction may not wait for self"); } final int dst = lookup( running, true ); final int src = lookup( blocked, true ); if( src == dst ) { ! throw new IllegalArgumentException("transaction may not wait for self."); } if( W[src][dst] ) { --- 557,566 ---- // verify arguments some more. if( running == blocked ) { ! throw new IllegalArgumentException("may not wait for self"); } final int dst = lookup( running, true ); final int src = lookup( blocked, true ); if( src == dst ) { ! throw new IllegalArgumentException("may not wait for self."); } if( W[src][dst] ) { |
From: Bryan T. <tho...@us...> - 2007-10-03 19:05:17
|
Update of /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv5631/src/java/org/CognitiveWeb/concurrent/locking Modified Files: TxDag.java LockContextManager.java Queue.java Log Message: Working on a refactor to support higher concurrency for unisolated writes, proper deadlock detection for transactions, and group commit. As things stand, unisolated writes are serialized (including the transaction commit) so deadlocks can not arise. However, we loose the opportunity to exploit parallelism on unisolated indices. Index: TxDag.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/TxDag.java,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** TxDag.java 2 Oct 2007 19:45:25 -0000 1.11 --- TxDag.java 3 Oct 2007 19:05:09 -0000 1.12 *************** *** 67,73 **** * matrix M to code the the number of different paths between two vertices. * Operations that insert one or more edges are atomic -- if a deadlock would ! * result, then the state of the DAG is NOT changed. The cost of the algorithm ! * is less than <code>O(n^^2)</code> and is suitable for systems with a ! * multi-programming level of 100s of concurrent transactions. * </p> * <p> --- 67,74 ---- * matrix M to code the the number of different paths between two vertices. * Operations that insert one or more edges are atomic -- if a deadlock would ! * result, then the state of the DAG is NOT changed (a deadlock is detected ! * when there is a non-zero path count in the diagonal of W). The cost of the ! * algorithm is less than <code>O(n^^2)</code> and is suitable for systems with ! * a multi-programming level of 100s of concurrent transactions. * </p> * <p> *************** *** 139,143 **** * </p> * <p> ! * A transaction in a granted group it is guarenteed to be running and hence not * waiting on any other transaction(s). When a transaction releases a lock, the * {@link Queue resource queue} automatically invokes --- 140,144 ---- * </p> * <p> ! * A transaction in a granted group is guarenteed to be running and hence not * waiting on any other transaction(s). When a transaction releases a lock, the * {@link Queue resource queue} automatically invokes *************** *** 459,463 **** */ ! synchronized boolean releaseVertex( Object tx ) { --- 460,464 ---- */ ! synchronized public boolean releaseVertex( Object tx ) { *************** *** 579,582 **** --- 580,584 ---- * Deadlock - rollback tentative change to M. */ + log.warn("Deadlock"); restore(order); if( debug ) { *************** *** 1113,1117 **** log.debug(toString()); } ! System.err.println(toString()); // FIXME uncomment this line. restore(order); throw new DeadlockException("deadlock"); --- 1115,1119 ---- log.debug(toString()); } ! // System.err.println(toString()); restore(order); throw new DeadlockException("deadlock"); Index: Queue.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/Queue.java,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** Queue.java 2 Oct 2007 19:45:26 -0000 1.9 --- Queue.java 3 Oct 2007 19:05:09 -0000 1.10 *************** *** 663,666 **** --- 663,671 ---- final long elapsed = System.currentTimeMillis() - begin; log.debug("resume: lock=" + lock + ", timeout=" + timeout + ", elapsed=" + elapsed); + if(elapsed>1000) { + // FIXME should only be required when timeout != 0L but I am seeing + // the code deadlock here and this at least gets us out of the deadlock. + throw new TimeoutException(); + } if (grantedGroup.contains(lock)) { // Lock was granted. *************** *** 732,736 **** * The lock was in the granted group and we just removed it. Now we * have to update the WAITS_FOR graph to remove all edges whose ! * source is a pending transaction for this resource that were * waiting on the lock that we just released. */ --- 737,741 ---- * The lock was in the granted group and we just removed it. Now we * have to update the WAITS_FOR graph to remove all edges whose ! * source is a pending transaction for this resource that was * waiting on the lock that we just released. */ Index: LockContextManager.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/LockContextManager.java,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** LockContextManager.java 2 Oct 2007 19:45:26 -0000 1.2 --- LockContextManager.java 3 Oct 2007 19:05:09 -0000 1.3 *************** *** 193,197 **** * locks. */ - protected void remove( LockContext lockContext ) { --- 193,196 ---- *************** *** 324,328 **** * does not cause any problems. */ - public static class LockContext { --- 323,326 ---- *************** *** 413,417 **** * was thrown at the time that the lock was requested. */ ! private final Set<Queue> locks = new HashSet<Queue>(); /** --- 411,415 ---- * was thrown at the time that the lock was requested. */ ! private final Set<Queue> lockRefs = new HashSet<Queue>(); /** *************** *** 458,462 **** * @todo add non-blocking variant of this method. */ - public void lock( final Object resource, final short mode ) { --- 456,459 ---- *************** *** 477,481 **** */ ! locks.add( queue ); try { --- 474,478 ---- */ ! lockRefs.add( queue ); try { *************** *** 484,496 **** } catch( DeadlockException t ) { ! locks.remove( queue ); throw t; } catch( TimeoutException t ) { // note: only possible when timeout is non-zero. ! locks.remove( queue ); throw t; } catch( Throwable t ) { ! locks.remove( queue ); throw new RuntimeException( t ); } --- 481,493 ---- } catch( DeadlockException t ) { ! lockRefs.remove( queue ); throw t; } catch( TimeoutException t ) { // note: only possible when timeout is non-zero. ! lockRefs.remove( queue ); throw t; } catch( Throwable t ) { ! lockRefs.remove( queue ); throw new RuntimeException( t ); } *************** *** 507,511 **** * {@link LockContext}. */ - public void unlock( Object resource ) { --- 504,507 ---- *************** *** 530,534 **** queue.unlock( this ); ! if( ! locks.remove( queue ) ) { throw new AssertionError(); --- 526,530 ---- queue.unlock( this ); ! if( ! lockRefs.remove( queue ) ) { throw new AssertionError(); *************** *** 550,554 **** * @see #abort() */ - public void releaseLocks() { --- 546,549 ---- *************** *** 557,600 **** /* ! * @todo In order to optimize lock release behavior both this method ! * and Queue should probably synchronize on waitsFor. This would ! * allow us to use a unlock() variant that did not update the ! * waitsFor graph to release each of the locks and then use the ! * optimized methods to clear the row and column for the lock ! * context from the waitsFor graph. ! * ! * The code below just steps through all of the locks that are still ! * held by this lock context releasing them one at a time and ! * updating the waitsFor graph each time a lock is released. ! */ ! ! Iterator itr = locks.iterator(); ! while( itr.hasNext() ) { ! ! Queue queue = (Queue) itr.next(); ! ! queue.unlock( this ); ! itr.remove(); ! ! } ! lockContextManager.remove( this ); ! ! releaseCurrentThread(); ! ! } ! /** ! * Force the abort of a blocked {@link LockContext}. All locks held by ! * the {@link LockContext} will be released and the {@link LockContext} ! * will be invalidated and removed from the {@link LockContextManager}. ! * ! * @see #releaseLocks() ! * ! * FIXME Implement the ability to abort a blocked lock context. ! */ public void abort() { --- 552,617 ---- /* ! * @todo In order to optimize lock release behavior both this method ! * and Queue should probably synchronize on waitsFor. This would ! * allow us to use a unlock() variant that did not update the ! * waitsFor graph to release each of the locks and then use the ! * optimized methods to clear the row and column for the lock ! * context from the waitsFor graph. ! * ! * The code below just steps through all of the locks that are still ! * held by this lock context releasing them one at a time and ! * updating the waitsFor graph each time a lock is released. Some ! * commented out code is present, but it does not update the ! * resource queues so it is not a complete solution. ! * ! * Also, we probably need to verify that nothing was waiting on the ! * tx since the optimization is otherwise illegal. ! */ ! // /* ! // * Since this transaction completed normally it was not waiting on ! // * anything and we can use the optimized method to clear the ! // * transaction from the WAITS_FOR graph. ! // */ ! // lockContextManager.waitsFor.removeEdges(this, false/*waiting*/); ! // ! // lockRefs.clear(); ! ! // @todo do we need to be synchronized here? ! synchronized (lockContextManager) { ! ! Iterator itr = lockRefs.iterator(); ! while (itr.hasNext()) { ! Queue queue = (Queue) itr.next(); ! try { ! queue.unlock(this); ! } catch (Throwable t) { ! log.warn("Could not unlock resource: " + queue, t); ! } ! ! } ! ! // clear hard references. ! lockRefs.clear(); ! ! // release vertex and lock context. ! lockContextManager.remove(this); + } + + releaseCurrentThread(); + + } + + /** + * Abnormal termination due to deadlock. All locks held by the + * {@link LockContext} will be released and the {@link LockContext} will + * be invalidated and removed from the {@link LockContextManager}. + * + * @see #releaseLocks() + */ public void abort() { |
From: Bryan T. <tho...@us...> - 2007-10-02 19:45:36
|
Update of /cvsroot/cweb/concurrent/src/test/org/CognitiveWeb/concurrent/schedule In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv6007/src/test/org/CognitiveWeb/concurrent/schedule Modified Files: Tx.java Condition.java Action.java Schedule.java Log Message: Working on some edge cases in which deadlocks arise among threads that are blocked and waiting on a resource to be released but in which the WAITS_FOR graph does NOT have any cycles. Also fixed a bug in which vertices of the WAITS_FOR graph were not being released by LockContextManager. Index: Action.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/test/org/CognitiveWeb/concurrent/schedule/Action.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Action.java 17 Mar 2006 14:25:29 -0000 1.3 --- Action.java 2 Oct 2007 19:45:26 -0000 1.4 *************** *** 70,76 **** final private String name; ! final private List preConditions = new LinkedList(); ! final private List postConditions = new LinkedList(); /** --- 70,76 ---- final private String name; ! final private List<Condition> preConditions = new LinkedList<Condition>(); ! final private List<Condition> postConditions = new LinkedList<Condition>(); /** Index: Tx.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/test/org/CognitiveWeb/concurrent/schedule/Tx.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Tx.java 17 Mar 2006 14:25:29 -0000 1.3 --- Tx.java 2 Oct 2007 19:45:26 -0000 1.4 *************** *** 49,228 **** import org.CognitiveWeb.concurrent.locking.TestQueueConcurrentTx; - /** ! * Test helper conflates a transactions with a thread. The {@link Runnable} ! * target executions the operations of the transaction as defined by a ! * {@link Schedule}. * ! * @author thompsonbry * ! * @see Schedule */ - - public class Tx extends Thread - { ! /** ! * Initially false and set to [true] when the transaction completes. ! * This field is checked by the {@link Schedule}. ! */ ! ! volatile boolean done = false; ! ! /** ! * Initially <code>null</code>. If a pre-condition, post-condition or ! * action fails, then this is set to the thrown exception. This field is ! * checked by the {@link Schedule}. ! */ ! volatile Throwable exception = null; ! ! /** ! * The next/current action to be run by the transaction. This field is ! * set by the {@link Schedule}and cleared by the {@link Tx}as each ! * action is successfully executed. The field is NOT cleared if an ! * action is blocked or if an exception is thrown. ! */ ! ! volatile Action action = null; ! ! /** ! * The schedule responsible for assigning actions to this transaction. ! */ ! final Schedule schedule; ! /** ! * Counter of the #of actions executed. ! */ ! private int nactions = 0; ! ! /** ! * Create a new transaction. ! * ! * @param schedule ! * The schedule which will run this transaction. ! * ! * @param name ! * The name of the transaction. ! */ ! ! Tx( Schedule schedule, String name ) { ! super( name ); ! if( schedule == null ) { ! throw new IllegalArgumentException(); } ! this.schedule = schedule; ! setDaemon(true); // can exit while this is running. ! start(); // start transaction -- it will wait on the Schedule. ! } ! ! public String toString() { ! return getName(); ! } ! ! /** ! * Run the transaction. Actions are executed as they set set on ! * the transaction by the schedule. ! * ! * @see Schedule#run() ! */ ! synchronized public void run() { ! while (true) { ! waitOnSchedule(); ! if (action != null) { ! runAction(); ! } ! } // while(true) ! } // run() ! /** ! * If {@link #action}!= null, then executes the pre-conditions, the ! * action, and the post-conditions defined for that action and clears ! * the {@link #action}so that another action may be tasked to this ! * transaction. ! * ! * @exception IllegalStateException ! * If the transaction is complete [done == true]. ! * ! * @exception IllegalStateException ! * If the transaction has thrown an exception [exception != ! * null]. ! */ ! ! synchronized private void runAction() ! { ! final long begin = System.currentTimeMillis(); ! try { ! // Make sure that the transaction is still valid. ! if (done || exception != null) { ! // Transaction may not execute more actions. ! throw new IllegalStateException("done/error: tx=" + this ! + ", done=" + done + ", ex=" + exception); ! } ! // pre-conditions. ! TestQueueConcurrentTx.log.debug("preConditions: tx=" + this + ", action=" + action); ! action.runPreConditions(); ! // action. ! TestQueueConcurrentTx.log.info("action: tx=" + this + ", action=" + action); ! action.run(); ! // post-condition. ! TestQueueConcurrentTx.log.debug("postConditions: tx=" + this + ", action=" + action); ! action.runPostConditions(); ! // success: Clear [action]. ! TestQueueConcurrentTx.log.debug("success: tx=" + this + ", action=" + action); ! } catch (Throwable t) { ! exception = t; ! TestQueueConcurrentTx.log.error("tx=" + this, t); ! } ! finally { ! action = null; ! nactions++; ! final long elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.info( "action: elapsed="+elapsed ); } } ! /** ! * Hand off execution to the schedule. ! */ ! synchronized private void waitOnSchedule() ! { ! if( action != null ) { ! /* ! * Do NOT wait if an action is assigned. This can happen on the ! * first action if {@link Schedule#run()}begins executing ! * actions before {@link Tx#run()}starts to execute. In this ! * case the Schedule will hold the monitor on the Tx and set the ! * action before the Tx enters this method for the first time. ! * After that this SHOULD NOT happen if things are synchronizing ! * properly. ! */ ! if( nactions > 0 ) { ! TestQueueConcurrentTx.log.warn( "Action already assigned: tx="+this+", action="+action); ! } ! return; } ! // Wait. ! TestQueueConcurrentTx.log.info("waiting: tx=" ! + this ! + (done ? ", done" : "") ! + (exception == null ? "" : ", ex=" ! + exception.getMessage())); ! final long begin = System.currentTimeMillis(); ! try { ! notifyAll(); // notify - will notify schedule waiting on tx. ! // schedule.thread.interrupt(); ! wait(); // hand off execution to the schedule. ! long elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.info("resume: tx=" + this + ", elapsed=" + elapsed); ! } catch (InterruptedException ex) { ! long elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.info( "interrupted: tx=" + this + ", elapsed=" ! + elapsed); ! } } ! ! } \ No newline at end of file --- 49,226 ---- import org.CognitiveWeb.concurrent.locking.TestQueueConcurrentTx; /** ! * Test helper conflates a transactions with a thread. The {@link Runnable} ! * target executions the operations of the transaction as defined by a ! * {@link Schedule}. ! * ! * @author thompsonbry ! * ! * @see Schedule ! */ ! public class Tx extends Thread { ! ! /** ! * Initially false and set to [true] when the transaction completes. ! * This field is checked by the {@link Schedule}. ! */ ! ! volatile boolean done = false; ! ! /** ! * Initially <code>null</code>. If a pre-condition, post-condition or ! * action fails, then this is set to the thrown exception. This field is ! * checked by the {@link Schedule}. ! */ ! ! volatile Throwable exception = null; ! ! /** ! * The next/current action to be run by the transaction. This field is ! * set by the {@link Schedule}and cleared by the {@link Tx}as each ! * action is successfully executed. The field is NOT cleared if an ! * action is blocked or if an exception is thrown. ! */ ! ! volatile Action action = null; ! ! /** ! * The schedule responsible for assigning actions to this transaction. ! */ ! ! final Schedule schedule; ! ! /** ! * Counter of the #of actions executed. ! */ ! private int nactions = 0; ! ! /** ! * Create a new transaction. * ! * @param schedule ! * The schedule which will run this transaction. * ! * @param name ! * The name of the transaction. */ ! Tx(Schedule schedule, String name) { ! super(name); ! if (schedule == null) { ! throw new IllegalArgumentException(); ! } ! this.schedule = schedule; ! setDaemon(true); // can exit while this is running. ! start(); // start transaction -- it will wait on the Schedule. ! } ! public String toString() { ! return getName(); ! } ! /** ! * Run the transaction. Actions are executed as they set set on ! * the transaction by the schedule. ! * ! * @see Schedule#run() ! */ ! synchronized public void run() { ! while (true) { ! waitOnSchedule(); ! if (action != null) { ! runAction(); } ! } // while(true) ! } // run() ! /** ! * If {@link #action}!= null, then executes the pre-conditions, the ! * action, and the post-conditions defined for that action and clears ! * the {@link #action}so that another action may be tasked to this ! * transaction. ! * ! * @exception IllegalStateException ! * If the transaction is complete [done == true]. ! * ! * @exception IllegalStateException ! * If the transaction has thrown an exception [exception != ! * null]. ! */ ! synchronized private void runAction() { ! final long begin = System.currentTimeMillis(); ! try { ! // Make sure that the transaction is still valid. ! if (done || exception != null) { ! // Transaction may not execute more actions. ! throw new IllegalStateException("done/error: tx=" + this ! + ", done=" + done + ", ex=" + exception); } + // pre-conditions. + TestQueueConcurrentTx.log.debug("preConditions: tx=" + this + + ", action=" + action); + action.runPreConditions(); + // action. + TestQueueConcurrentTx.log.info("action: tx=" + this + ", action=" + + action); + action.run(); + // post-condition. + TestQueueConcurrentTx.log.debug("postConditions: tx=" + this + + ", action=" + action); + action.runPostConditions(); + // success: Clear [action]. + TestQueueConcurrentTx.log.debug("success: tx=" + this + ", action=" + + action); + } catch (Throwable t) { + exception = t; + TestQueueConcurrentTx.log.error("tx=" + this, t); + } finally { + action = null; + nactions++; + final long elapsed = System.currentTimeMillis() - begin; + TestQueueConcurrentTx.log.info("action: elapsed=" + elapsed); } + } ! /** ! * Hand off execution to the schedule. ! */ ! synchronized private void waitOnSchedule() { ! if (action != null) { ! /* ! * Do NOT wait if an action is assigned. This can happen on the ! * first action if {@link Schedule#run()} begins executing ! * actions before {@link Tx#run()} starts to execute. In this ! * case the Schedule will hold the monitor on the Tx and set the ! * action before the Tx enters this method for the first time. ! * After that this SHOULD NOT happen if things are synchronizing ! * properly. ! */ ! if (nactions > 0) { ! TestQueueConcurrentTx.log.warn("Action already assigned: tx=" ! + this + ", action=" + action); } ! return; } ! // Wait. ! TestQueueConcurrentTx.log.info("waiting: tx=" + this ! + (done ? ", done" : "") ! + (exception == null ? "" : ", ex=" + exception.getMessage())); ! final long begin = System.currentTimeMillis(); ! try { ! notifyAll(); // notify - will notify schedule waiting on tx. ! // schedule.thread.interrupt(); ! wait(); // hand off execution to the schedule. ! long elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.info("resume: tx=" + this + ", elapsed=" ! + elapsed); ! } catch (InterruptedException ex) { ! long elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.info("interrupted: tx=" + this ! + ", elapsed=" + elapsed); ! } ! } ! ! } \ No newline at end of file Index: Schedule.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/test/org/CognitiveWeb/concurrent/schedule/Schedule.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Schedule.java 17 Mar 2006 14:25:29 -0000 1.3 --- Schedule.java 2 Oct 2007 19:45:26 -0000 1.4 *************** *** 56,453 **** import org.CognitiveWeb.concurrent.locking.action.LockAction; ! /** ! * A schedule of operations by concurrent transactions. The schedule is a ! * discrete timeline. Each point on the timeline is defined by an action. ! * Each action is paired with the transaction which will execute that ! * action. Actions execute in the thread associated with their transaction, ! * so actions never block the main thread. Actions may be associated with ! * pre- and/or post-conditions. Actions are executed atomically unless the ! * action blocks. An action MUST declare whether or not it will ! * {@link Action#block}. If the action causes an exception to be thrown, ! * then the schedule will halt and the exception to be thrown out of the ! * {@link #run()} method. ! * <p> ! * Once the action has been successfully executed by the transaction, the ! * thread for that transaction will wait until the schedule sets the next ! * action for that transaction and notifies the transaction. If an action ! * blocks, then the next action in the schedule is executed and the duration ! * of the blocked action will extend until the transaction is unblock. ! * Normally blocking occurs due to a specific combination of {@link LockAction}s ! * and unblocking results when appropriate {@link LockAction}s are released. If a ! * transaction is blocked when its next action is reached in the schedule, ! * then an error is reported (since it is impossible for the transaction to ! * execute any further actions while it is blocked). Once all actions have ! * been executed, the transactions are scanned to verify that none are ! * blocked and that all transactions are complete. An error message is ! * logged if these conditions are violated. ! * <p> ! * Aborts must be executed in the main thread so that blocked transactions ! * may be aborted. ! * <p> ! * An event log is recorded using the {@link #log}. ! * <p> * ! * @author thompsonbry * ! * @see Tx */ - - public class Schedule implements Runnable - { - - /** - * The set of declared transactions. - */ - Set transactions = new HashSet(); - - /** - * The sequence of actions. - */ - List actions = new LinkedList(); ! /** ! * The thread in which the schedule is running. This is initially ! * <code>null</code> and is set when the schedule is {@link #run()}. ! */ ! Thread thread = null; ! ! /** ! * Create a new schedule. ! */ ! public Schedule() ! { ! } ! /** ! * Create a transaction for use with this {@link Schedule}. ! * ! * @param name The name of the transaction. ! * ! * @return The transaction. ! */ ! ! public Tx createTx( String name ) { ! Tx tx = new Tx( this, name ); ! transactions.add( tx ); ! return tx; ! } ! /** ! * Add an action to the schedule. ! * ! * @param action ! * The action. ! */ ! ! public void add( Action action ) { ! if( action == null ) { ! throw new IllegalArgumentException(); ! } ! Tx tx = action.getTx(); ! if (!transactions.contains(tx)) { ! throw new IllegalArgumentException( ! "action belongs to a transaction created by a different schedule."); ! } ! actions.add( action ); } ! ! /** ! * Return iterator over the transactions known to the schedule. ! */ ! public Iterator getTransactions() { ! return transactions.iterator(); } ! /** ! * Return the #of transactions known to the schedule. ! */ ! public int getTransactionCount() { ! return transactions.size(); ! } ! /** ! * Return the #of actions scheduled for the specified transaction. ! * ! * @param tx ! * The transaction. ! * @return The #of actions scheduled for that transaction. ! */ ! public int getActionCount( Tx tx ) { ! if( tx == null ) { ! throw new IllegalArgumentException(); ! } ! int count = 0; ! Iterator itr = actions.iterator(); ! while( itr.hasNext() ) { ! Action action = (Action) itr.next(); ! if( action.getTx() == tx ) { ! count++; ! } } - return count; } ! ! /** ! * Run all actions. ! * ! * @exception RuntimeException ! * If an error has occurred either in the scheduler state ! * machine, in the execution of an action, or in the pre- ! * or post-conditions for an action. ! */ ! ! public void run() ! { ! thread = Thread.currentThread(); ! ! TestQueueConcurrentTx.log.info("Will run: " + actions.size() + " actions defined for " ! + transactions.size() + " transactions"); ! ! Iterator itr = actions.iterator(); ! ! int i = 0; ! ! while( itr.hasNext() ) { ! ! Action action = (Action) itr.next(); ! ! TestQueueConcurrentTx.log.info( "Action#="+i+": "+action ); ! ! Tx tx = action.getTx(); ! /* ! * Set the action to be executed and setup a timeout. If the ! * timeout is exceeded, then the action blocked. This should ! * only happen for actions which declare that they will block. ! * Blocking in any other case causes an exception to be thrown. ! * Failure to block when a the action was expected to block also ! * causes an exception to be thrown. ! * ! * The schedule runs in the main thread. Synchronization is on ! * the individual transactions. Normally one transaction runs at ! * a time and only when the schedule is halted. The exception ! * occurs when a transaction which was blocked becomes ! * unblocked, e.g., by sending it an interrupt or notifying the ! * Tx object. ! * ! * @todo schedule#run() Is there a way to detect a block without ! * relying on a long timeout? (Short timeouts are sometimes too ! * short and give a false positive.) ! */ ! synchronized( tx ) { ! checkTx( tx ); ! TestQueueConcurrentTx.log.info("Setting action on tx: tx="+tx+", action="+action); ! tx.action = action; // set action to be executed. ! final long timeout = 1000L; // ms. ! long elapsed; ! // this.notifyAll(); // notify all transactions. ! // synchronized (this) { ! final long begin = System.currentTimeMillis(); ! try { ! TestQueueConcurrentTx.log.debug("notify: tx="+tx); ! // tx.interrupt(); // wake up transaction. ! tx.notifyAll(); // notify tx. ! tx.wait(timeout); // transaction will attempt to run. ! elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.debug("timeout: tx="+tx+", elapsed=" + elapsed); ! } catch (InterruptedException ex) { ! elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.debug("interrupted: elapsed=" + elapsed); ! // throw new RuntimeException("???", ex); ! } ! // } ! if (tx.exception != null) { /* ! * The action caused an exception to be thrown. This ! * halts the execution of the schedule and the exception ! * is reported back to the caller. */ ! throw new RuntimeException("failure: tx=" + tx, ! tx.exception); } ! if (action.blocks) { ! if (elapsed < timeout) { ! /* ! * The transaction failed to blocked when it was ! * supposed to block. ! */ ! throw new RuntimeException( ! "action failed to block: tx=" + tx ! + ", action=" + action ! + ", elapsed=" + elapsed); ! } ! } else { ! if (elapsed >= timeout) { ! /* ! * The transaction blocked when it was not supposed ! * to block. ! */ ! throw new RuntimeException( ! "action blocked: tx=" + tx ! + ", action=" + action ! + ", elapsed=" + elapsed); ! } } - } - - i++; - - } - TestQueueConcurrentTx.log.info( "Schedule done."); - - /* - * Scan transactions and report any which are in an error condition - * [exception != null], blocked [action != null ], or failed to - * complete [done != true]. - */ - - itr = transactions.iterator(); - - while( itr.hasNext() ) { - - Tx tx = (Tx) itr.next(); - - if( tx.exception != null ) { - - TestQueueConcurrentTx.log.error( "error: tx="+tx, tx.exception ); - - } else if( tx.action != null ) { - - TestQueueConcurrentTx.log.error( "blocked: tx="+tx+" on action="+tx.action ); - - } else if( ! tx.done ) { - - TestQueueConcurrentTx.log.warn( "active: tx="+tx ); - - } - } ! ! // /* ! // * Transactions may still be executing at this point. Therefore we ! // * scan through the transaction set repeatedly, removing any ! // * transactions which have completed execution. ! // * ! // * If any transaction has set its [exception] field, then it has ! // * failed and we will throw an exception out of the test case. ! // * Otherwise if the [action] field is cleared then the transaction ! // * has finished executing (since we are not scheduling more ! // * actions). If the [done] flag was NOT set, then we log a warning ! // * since the test harness did not "commit" that transaction. ! // */ ! // ! // while( true ) { ! // ! // if( transactions.size() == 0 ) { ! // ! // // All transactions have finished. ! // ! // break; ! // ! // } ! // ! // // Scan remaining transactions. ! // ! // itr = transactions.iterator(); ! // ! // while( itr.hasNext() ) { ! // ! // Tx tx = (Tx) itr.next(); ! // ! // if( tx.exception != null ) { ! // ! // /* ! // * This transaction failed, so thrown the exception out ! // * to the test harness. ! // */ ! // ! // throw new RuntimeException("failure: tx=" + tx, ! // tx.exception); ! // ! // } ! // ! // if( tx.action == null ) { ! // ! // /* ! // * The transaction is not executing anything. ! // */ ! // ! // if( ! tx.done ) { ! // ! // /* ! // * Log a warning since the test harness did not ! // * explicitly commit the transaction. (This is not ! // * an error since we are not really required to ! // * commit transactions during tests of the ! // * concurrency control mechanism.) ! // */ ! // ! // log.warn( "transaction was not committed: tx="+tx ); ! // ! // } ! // ! // // Remove from the set of remaining transactions. ! // ! // itr.remove(); ! // ! // } ! // ! // } ! // ! // } ! } ! ! /** ! * Check some pre-conditions before tasking a transaction to execute an ! * action. ! * ! * @exception IllegalStateException ! * If the transaction is complete [{@link Tx#done}== ! * true]. ! * ! * @exception IllegalStateException ! * If the transaction has thrown an exception [ ! * {@link Tx#exception}!= null] ! * ! * @exception IllegalStateException ! * If the transaction is blocked [{@link Tx#action}!= ! * null]. */ ! ! private void checkTx( Tx tx ) ! throws IllegalStateException ! { ! if (tx.done) { ! throw new IllegalStateException("transaction is done: tx=" + tx); } ! if (tx.action != null) { ! /* ! * This case arises when a lock was not granted for a ! * transaction and the schedule reaches the next action for that ! * transaction. This is either a problem with the test case or a ! * failure in the locking system. ! */ ! if (tx.exception != null) { ! // Special case when a block transaction throws an ! // exception. ! IllegalStateException ex = new IllegalStateException( ! "transaction is blocked: tx=" + tx + " by action=" ! + tx.action); ! ex.initCause(tx.exception); ! throw ex; ! } else { ! throw new IllegalStateException( ! "transaction is blocked: tx=" + tx + " by action=" ! + tx.action); ! } ! } } ! ! } \ No newline at end of file --- 56,456 ---- import org.CognitiveWeb.concurrent.locking.action.LockAction; + /** + * A schedule of operations by concurrent transactions. The schedule is a + * discrete timeline. Each point on the timeline is defined by an {@link Action}. + * Each action is paired with the {@link Tx transaction} which will execute that + * action. Actions execute in the thread associated with their transaction, so + * actions never block the main thread. Actions may be associated with pre- + * and/or post-{@link Condition}s. Actions are executed atomically unless the + * action blocks. An action MUST declare whether or not it will + * {@link Action#block}. If the action causes an exception to be thrown, then + * the schedule will halt and the exception to be thrown out of the + * {@link #run()} method. + * <p> + * Once the action has been successfully executed by the transaction, the thread + * for that transaction will wait until the schedule sets the next action for + * that transaction and notifies the transaction. If an action blocks, then the + * next action in the schedule is executed and the duration of the blocked + * action will extend until the transaction is unblocked. Normally blocking + * occurs due to a specific combination of {@link LockAction}s and unblocking + * results when appropriate {@link LockAction}s are released. If a transaction + * is blocked when its next action is reached in the schedule, then an error is + * reported (since it is impossible for the transaction to execute any further + * actions while it is blocked). Once all actions have been executed, the + * transactions are scanned to verify that none are blocked and that all + * transactions are complete. An error message is logged if these conditions are + * violated. + * <p> + * Aborts must be executed in the main thread so that blocked transactions may + * be aborted. + * <p> + * An event log is recorded using {@link #log}. + * <p> + * + * @author thompsonbry + * + * @see Tx + * @see Action + */ + public class Schedule implements Runnable { + + /** + * The set of declared transactions. + */ + Set<Tx> transactions = new HashSet<Tx>(); ! /** ! * The sequence of actions. ! */ ! List<Action> actions = new LinkedList<Action>(); ! ! /** ! * The thread in which the schedule is running. This is initially ! * <code>null</code> and is set when the schedule is {@link #run()}. ! */ ! Thread thread = null; ! ! /** ! * Create a new schedule. ! */ ! public Schedule() { ! } ! ! /** ! * Create a transaction for use with this {@link Schedule}. * ! * @param name The name of the transaction. * ! * @return The transaction. */ ! public Tx createTx(String name) { ! Tx tx = new Tx(this, name); ! transactions.add(tx); ! return tx; ! } ! /** ! * Add an action to the schedule. ! * ! * @param action ! * The action. ! */ ! public void add(Action action) { ! if (action == null) { ! throw new IllegalArgumentException(); } ! Tx tx = action.getTx(); ! if (!transactions.contains(tx)) { ! throw new IllegalArgumentException( ! "action belongs to a transaction created by a different schedule."); } + actions.add(action); + } ! /** ! * Return iterator over the transactions known to the schedule. ! */ ! public Iterator getTransactions() { ! return transactions.iterator(); ! } ! /** ! * Return the #of transactions known to the schedule. ! */ ! public int getTransactionCount() { ! return transactions.size(); ! } ! ! /** ! * Return the #of actions scheduled for the specified transaction. ! * ! * @param tx ! * The transaction. ! * @return The #of actions scheduled for that transaction. ! */ ! public int getActionCount(Tx tx) { ! if (tx == null) { ! throw new IllegalArgumentException(); ! } ! int count = 0; ! Iterator itr = actions.iterator(); ! while (itr.hasNext()) { ! Action action = (Action) itr.next(); ! if (action.getTx() == tx) { ! count++; } } ! return count; ! } ! /** ! * Run all actions. ! * ! * @exception RuntimeException ! * If an error has occurred either in the scheduler state ! * machine, in the execution of an action, or in the pre- ! * or post-conditions for an action. ! */ ! public void run() { ! thread = Thread.currentThread(); ! ! TestQueueConcurrentTx.log.info("Will run: " + actions.size() ! + " actions defined for " + transactions.size() ! + " transactions"); ! ! Iterator itr = actions.iterator(); ! ! int i = 0; ! ! while (itr.hasNext()) { ! ! Action action = (Action) itr.next(); ! ! TestQueueConcurrentTx.log.info("Action#=" + i + ": " + action); ! ! Tx tx = action.getTx(); ! ! /* ! * Set the action to be executed and setup a timeout. If the ! * timeout is exceeded, then the action blocked. This should ! * only happen for actions which declare that they will block. ! * Blocking in any other case causes an exception to be thrown. ! * Failure to block when a the action was expected to block also ! * causes an exception to be thrown. ! * ! * The schedule runs in the main thread. Synchronization is on ! * the individual transactions. Normally one transaction runs at ! * a time and only when the schedule is halted. The exception ! * occurs when a transaction which was blocked becomes ! * unblocked, e.g., by sending it an interrupt or notifying the ! * Tx object. ! * ! * @todo schedule#run() Is there a way to detect a block without ! * relying on a long timeout? (Short timeouts are sometimes too ! * short and give a false positive.) ! */ ! ! synchronized (tx) { ! checkTx(tx); ! TestQueueConcurrentTx.log.info("Setting action on tx: tx=" + tx ! + ", action=" + action); ! tx.action = action; // set action to be executed. ! final long timeout = 1000L; // ms. ! long elapsed; ! // this.notifyAll(); // notify all transactions. ! // synchronized (this) { ! final long begin = System.currentTimeMillis(); ! try { ! TestQueueConcurrentTx.log.debug("notify: tx=" + tx); ! // tx.interrupt(); // wake up transaction. ! tx.notifyAll(); // notify tx. ! /* ! * Note: the timeout is "more or less" so we add 10% ! * in an attempt to convince wait(long) to wait for ! * at least timeout ms. ! */ ! final long requestedTimeout = (long) (timeout + timeout * .10); ! tx.wait(requestedTimeout); // transaction will attempt to run. ! elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.debug("timeout: tx=" + tx ! + ", elapsed=" + elapsed); ! } catch (InterruptedException ex) { ! elapsed = System.currentTimeMillis() - begin; ! TestQueueConcurrentTx.log.debug("interrupted: elapsed=" ! + elapsed); ! // throw new RuntimeException("???", ex); ! } ! // } ! if (tx.exception != null) { ! /* ! * The action caused an exception to be thrown. This ! * halts the execution of the schedule and the exception ! * is reported back to the caller. ! */ ! throw new RuntimeException("failure: tx=" + tx, ! tx.exception); ! } ! if (action.blocks) { ! if (elapsed < timeout) { /* ! * The transaction failed to blocked when it was ! * supposed to block. */ ! throw new RuntimeException( ! "action failed to block: tx=" + tx ! + ", action=" + action + ", elapsed=" ! + elapsed); } ! } else { ! if (elapsed >= timeout) { ! /* ! * The transaction blocked when it was not supposed ! * to block. ! */ ! throw new RuntimeException("action blocked: tx=" + tx ! + ", action=" + action + ", elapsed=" + elapsed); } } } ! ! i++; ! } ! ! TestQueueConcurrentTx.log.info("Schedule done."); ! ! /* ! * Scan transactions and report any which are in an error condition ! * [exception != null], blocked [action != null ], or failed to ! * complete [done != true]. */ ! ! itr = transactions.iterator(); ! ! while (itr.hasNext()) { ! ! Tx tx = (Tx) itr.next(); ! ! if (tx.exception != null) { ! ! TestQueueConcurrentTx.log ! .error("error: tx=" + tx, tx.exception); ! ! } else if (tx.action != null) { ! ! TestQueueConcurrentTx.log.error("blocked: tx=" + tx ! + " on action=" + tx.action); ! ! } else if (!tx.done) { ! ! TestQueueConcurrentTx.log.warn("active: tx=" + tx); ! } ! } ! ! // /* ! // * Transactions may still be executing at this point. Therefore we ! // * scan through the transaction set repeatedly, removing any ! // * transactions which have completed execution. ! // * ! // * If any transaction has set its [exception] field, then it has ! // * failed and we will throw an exception out of the test case. ! // * Otherwise if the [action] field is cleared then the transaction ! // * has finished executing (since we are not scheduling more ! // * actions). If the [done] flag was NOT set, then we log a warning ! // * since the test harness did not "commit" that transaction. ! // */ ! // ! // while( true ) { ! // ! // if( transactions.size() == 0 ) { ! // ! // // All transactions have finished. ! // ! // break; ! // ! // } ! // ! // // Scan remaining transactions. ! // ! // itr = transactions.iterator(); ! // ! // while( itr.hasNext() ) { ! // ! // Tx tx = (Tx) itr.next(); ! // ! // if( tx.exception != null ) { ! // ! // /* ! // * This transaction failed, so thrown the exception out ! // * to the test harness. ! // */ ! // ! // throw new RuntimeException("failure: tx=" + tx, ! // tx.exception); ! // ! // } ! // ! // if( tx.action == null ) { ! // ! // /* ! // * The transaction is not executing anything. ! // */ ! // ! // if( ! tx.done ) { ! // ! // /* ! // * Log a warning since the test harness did not ! // * explicitly commit the transaction. (This is not ! // * an error since we are not really required to ! // * commit transactions during tests of the ! // * concurrency control mechanism.) ! // */ ! // ! // log.warn( "transaction was not committed: tx="+tx ); ! // ! // } ! // ! // // Remove from the set of remaining transactions. ! // ! // itr.remove(); ! // ! // } ! // ! // } ! // ! // } ! ! } ! ! /** ! * Check some pre-conditions before tasking a transaction to execute an ! * action. ! * ! * @exception IllegalStateException ! * If the transaction is complete [{@link Tx#done}== ! * true]. ! * ! * @exception IllegalStateException ! * If the transaction has thrown an exception [ ! * {@link Tx#exception}!= null] ! * ! * @exception IllegalStateException ! * If the transaction is blocked [{@link Tx#action}!= ! * null]. ! */ ! ! private void checkTx(Tx tx) throws IllegalStateException { ! if (tx.done) { ! throw new IllegalStateException("transaction is done: tx=" + tx); ! } ! if (tx.action != null) { ! /* ! * This case arises when a lock was not granted for a ! * transaction and the schedule reaches the next action for that ! * transaction. This is either a problem with the test case or a ! * failure in the locking system. ! */ ! if (tx.exception != null) { ! // Special case when a block transaction throws an ! // exception. ! IllegalStateException ex = new IllegalStateException( ! "transaction is blocked: tx=" + tx + " by action=" ! + tx.action); ! ex.initCause(tx.exception); ! throw ex; ! } else { ! throw new IllegalStateException("transaction is blocked: tx=" ! + tx + " by action=" + tx.action); ! } ! } ! } ! ! } Index: Condition.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/test/org/CognitiveWeb/concurrent/schedule/Condition.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Condition.java 17 Mar 2006 14:25:29 -0000 1.3 --- Condition.java 2 Oct 2007 19:45:26 -0000 1.4 *************** *** 47,51 **** package org.CognitiveWeb.concurrent.schedule; - /** * Abstract base class for pre-condition or post-condition checks run before --- 47,50 ---- *************** *** 54,63 **** * @author thompsonbry */ ! abstract public class Condition ! { - public Condition() {} - /** * Test the state of the transaction. --- 53,61 ---- * @author thompsonbry */ + abstract public class Condition { ! public Condition() { ! } /** * Test the state of the transaction. *************** *** 69,74 **** * If the condition was violated. */ ! ! abstract public void check( Tx tx ); ! } \ No newline at end of file --- 67,72 ---- * If the condition was violated. */ ! ! abstract public void check(Tx tx); ! } \ No newline at end of file |
From: Bryan T. <tho...@us...> - 2007-10-02 19:45:35
|
Update of /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv6007/src/java/org/CognitiveWeb/concurrent/locking Modified Files: TxDag.java Lock.java LockContextManager.java IGrantedGroup.java GrantedGroup.java IRequestQueue.java Queue.java Added Files: ConcurrentRequestQueue.java Removed Files: RequestQueue.java Log Message: Working on some edge cases in which deadlocks arise among threads that are blocked and waiting on a resource to be released but in which the WAITS_FOR graph does NOT have any cycles. Also fixed a bug in which vertices of the WAITS_FOR graph were not being released by LockContextManager. Index: IGrantedGroup.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/IGrantedGroup.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** IGrantedGroup.java 17 Mar 2006 14:25:28 -0000 1.4 --- IGrantedGroup.java 2 Oct 2007 19:45:26 -0000 1.5 *************** *** 64,67 **** --- 64,72 ---- /** + * True iff the granted group is empty. + */ + public boolean isEmpty(); + + /** * Return the #of transactions in the granted group. */ *************** *** 69,79 **** /** ! * Return <code>true</code> iff the <i>lock </i> is in the granted ! * group. * ! * @param lock The lock. * ! * @return <code>true</code> iff the <i>lock </i> is in the granted ! * group. */ public boolean contains(Lock lock); --- 74,83 ---- /** ! * Return <code>true</code> iff the <i>lock </i> is in the granted group. * ! * @param lock ! * The lock. * ! * @return <code>true</code> iff the <i>lock </i> is in the granted group. */ public boolean contains(Lock lock); *************** *** 89,92 **** --- 93,100 ---- * * @exception IllegalStateException + * If the <i>lock</i> not not compatible with the mode of + * the granted group. + * + * @exception IllegalStateException * If the <i>lock</i> is already in the granted group. */ *************** *** 115,127 **** public Lock getTxLock(Object tx); ! /** ! * Recompute the group mode. This method is used when a granted lock is ! * released or when the mode of a granted lock is updated. In these ! * cases we must rescan the granted group and re-compute the granted ! * mode. ! * ! * @return The new granted mode. ! */ ! public short computeGroupMode(); /** --- 123,135 ---- public Lock getTxLock(Object tx); ! // /** ! // * Recompute the group mode. This method is used when a granted lock is ! // * released or when the mode of a granted lock is updated. In these ! // * cases we must rescan the granted group and re-compute the granted ! // * mode. ! // * ! // * @return The new granted mode. ! // */ ! // public short computeGroupMode(); /** Index: GrantedGroup.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/GrantedGroup.java,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** GrantedGroup.java 17 Mar 2006 14:25:28 -0000 1.3 --- GrantedGroup.java 2 Oct 2007 19:45:26 -0000 1.4 *************** *** 47,53 **** package org.CognitiveWeb.concurrent.locking; - import java.util.HashSet; import java.util.Iterator; ! import java.util.Set; --- 47,54 ---- package org.CognitiveWeb.concurrent.locking; import java.util.Iterator; ! import java.util.NoSuchElementException; ! import java.util.concurrent.ConcurrentHashMap; ! import java.util.concurrent.atomic.AtomicInteger; *************** *** 62,76 **** { ! /* ! * Since the multi-programming level is bounded in 10s-100s, the use of ! * an ArrayList provides relatively fast linear search (could be binary ! * search iff transactions define a Comparable ordering) for a specific ! * lock combined with simple semantics and the ability to traverse the ! * list w/o creating an Iterator. In contrast, the use of a Java 1.5 ! * concurrent HashSet might provide higher concurrency and faster ! * testing of whether or not a lock is a member of the granted group. ! */ // private final ArrayList data = new ArrayList(); ! private final Set grantedGroup = new HashSet(); /** --- 63,77 ---- { ! // /* ! // * Since the multi-programming level is bounded in 10s-100s, the use of ! // * an ArrayList provides relatively fast linear search (could be binary ! // * search iff transactions define a Comparable ordering) for a specific ! // * lock combined with simple semantics and the ability to traverse the ! // * list w/o creating an Iterator. In contrast, the use of a Java 1.5 ! // * concurrent HashSet might provide higher concurrency and faster ! // * testing of whether or not a lock is a member of the granted group. ! // */ // private final ArrayList data = new ArrayList(); ! private final ConcurrentHashMap<Lock,Lock> grantedGroup = new ConcurrentHashMap<Lock,Lock>(); /** *************** *** 78,86 **** * lock is released and whenever a lock request is granted. */ ! private short groupMode = LockMode.NL; ! synchronized public short getMode() { ! return groupMode; } --- 79,87 ---- * lock is released and whenever a lock request is granted. */ ! private AtomicInteger groupMode = new AtomicInteger(LockMode.NL); ! public short getMode() { ! return (short) groupMode.get(); } *************** *** 90,94 **** } ! synchronized public int size() { return grantedGroup.size(); --- 91,101 ---- } ! public boolean isEmpty() { ! ! return grantedGroup.isEmpty(); ! ! } ! ! public int size() { return grantedGroup.size(); *************** *** 96,100 **** } ! synchronized public boolean contains(Lock lock) { if (lock == null) { --- 103,107 ---- } ! public boolean contains(Lock lock) { if (lock == null) { *************** *** 104,108 **** } ! return grantedGroup.contains(lock); } --- 111,115 ---- } ! return grantedGroup.containsKey(lock); } *************** *** 122,128 **** } ! if (!grantedGroup.add(lock)) { ! throw new IllegalStateException("lock already in granted group"); } --- 129,141 ---- } ! if(!isCompatibleRequest(lock.getMode())) { ! ! throw new IllegalStateException("Lock not compatible with granted group mode"); ! ! } ! ! if (grantedGroup.putIfAbsent(lock, lock) != null) { ! throw new IllegalStateException("Lock already in granted group"); } *************** *** 142,149 **** } ! if (grantedGroup.remove(lock)) { // Re-compute the group mode. ! computeGroupMode(); return true; --- 155,162 ---- } ! if (grantedGroup.remove(lock)!=null) { // Re-compute the group mode. ! groupMode.set(computeGroupMode()); return true; *************** *** 155,159 **** } ! synchronized public Lock getTxLock(Object tx) { if (tx == null) { --- 168,172 ---- } ! public Lock getTxLock(Object tx) { if (tx == null) { *************** *** 164,175 **** /* ! * @todo optimize this if we change the grantedGroup Collection ! * class. */ ! Iterator itr = grantedGroup.iterator(); while (itr.hasNext()) { ! Lock grantedLock = (Lock) itr.next(); if (grantedLock.getTransaction() == tx) { --- 177,198 ---- /* ! * @todo optimize this? hash set/map iterators are slow. */ ! Iterator<Lock> itr = grantedGroup.keySet().iterator(); while (itr.hasNext()) { ! Lock grantedLock; ! ! try { ! ! grantedLock = (Lock) itr.next(); ! ! } catch (NoSuchElementException ex) { ! ! // concurrent removal. ! break; ! ! } if (grantedLock.getTransaction() == tx) { *************** *** 191,211 **** * @param mode * The mode of a lock being admitted to the granted group. - * - * @see #computeGroupMode() */ - private void updateGroupMode(short mode) { LockMode.assertLockedMode(mode); ! groupMode = LockMode.getSuperMode(groupMode, mode); } ! synchronized public short computeGroupMode() { ! groupMode = LockMode.NL; ! if (grantedGroup.size() == 0) { return groupMode; --- 214,238 ---- * @param mode * The mode of a lock being admitted to the granted group. */ private void updateGroupMode(short mode) { LockMode.assertLockedMode(mode); ! groupMode.set(LockMode.getSuperMode(getMode(), mode)); } ! /** ! * Recompute the group mode. This method is used when a granted lock is ! * released or when the mode of a granted lock is updated. In these cases we ! * must rescan the granted group and re-compute the granted mode. ! * ! * @return The new granted mode. ! */ ! private short computeGroupMode() { ! short groupMode = LockMode.NL; ! if (grantedGroup.isEmpty()) { return groupMode; *************** *** 213,217 **** } ! Iterator itr = grantedGroup.iterator(); while (itr.hasNext()) { --- 240,244 ---- } ! Iterator<Lock> itr = grantedGroup.keySet().iterator(); while (itr.hasNext()) { *************** *** 227,241 **** } ! synchronized public boolean isCompatibleRequest(short mode) { LockMode.assertLockedMode(mode); ! return LockMode.isCompatible(mode, groupMode); } ! synchronized public Lock[] getGrantedLocks() { ! return (Lock[]) grantedGroup.toArray(new Lock[] {}); } --- 254,268 ---- } ! public boolean isCompatibleRequest(short mode) { LockMode.assertLockedMode(mode); ! return LockMode.isCompatible(mode, getMode()); } ! public Lock[] getGrantedLocks() { ! return (Lock[]) grantedGroup.keySet().toArray(new Lock[] {}); } --- NEW FILE: ConcurrentRequestQueue.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Mar 3, 2006 */ package org.CognitiveWeb.concurrent.locking; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.LinkedBlockingQueue; /** * Implemention based on {@link LinkedBlockingQueue}. */ class ConcurrentRequestQueue implements IRequestQueue { private final LinkedBlockingQueue<Lock> requestQueue; ConcurrentRequestQueue() { this.requestQueue = new LinkedBlockingQueue<Lock>(); } ConcurrentRequestQueue(int capacity) { this.requestQueue = new LinkedBlockingQueue<Lock>(capacity); } public boolean isEmpty() { return requestQueue.isEmpty(); } public int size() { return requestQueue.size(); } public boolean contains( Lock lock ) { if( lock == null ) { throw new IllegalArgumentException(); } return requestQueue.contains( lock ); } public void add( Lock lock ) { if( lock == null ) { throw new IllegalArgumentException(); } requestQueue.add( lock ); } public boolean remove( Lock lock ) { if( lock == null ) { throw new IllegalArgumentException(); } return requestQueue.remove( lock ); } public Lock getTxLock( Object tx ) { if (tx == null) { throw new IllegalArgumentException(); } Iterator<Lock> itr = requestQueue.iterator(); while (itr.hasNext()) { final Lock pendingLock; try { pendingLock = itr.next(); } catch(NoSuchElementException ex) { // concurrent removal - queue is now empty. break; } if (pendingLock.getTransaction() == tx) { return pendingLock; } } return null; } public Lock[] getRequestedLocks() { return (Lock[]) requestQueue.toArray(new Lock[]{}); } } Index: IRequestQueue.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/IRequestQueue.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** IRequestQueue.java 17 Mar 2006 14:25:28 -0000 1.4 --- IRequestQueue.java 2 Oct 2007 19:45:26 -0000 1.5 *************** *** 65,68 **** --- 65,73 ---- /** + * True iff the request queue is empty. + */ + public boolean isEmpty(); + + /** * The #of lock requests in the queue. */ *************** *** 115,117 **** --- 120,123 ---- */ public Lock[] getRequestedLocks(); + } Index: TxDag.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/TxDag.java,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** TxDag.java 7 Apr 2006 16:50:04 -0000 1.10 --- TxDag.java 2 Oct 2007 19:45:25 -0000 1.11 *************** *** 277,281 **** /** ! * A list containing {@link Integer}indices available to be assigned to a * new transaction. When this list is empty, then the maximum #of * transactions are running concurrently. Entries are removed from the --- 277,281 ---- /** ! * A list containing {@link Integer} indices available to be assigned to a * new transaction. When this list is empty, then the maximum #of * transactions are running concurrently. Entries are removed from the *************** *** 283,287 **** * the list when a transaction is complete (abort or commit). */ ! private final List indices = new LinkedList(); /** --- 283,287 ---- * the list when a transaction is complete (abort or commit). */ ! private final List<Integer> indices = new LinkedList<Integer>(); /** *************** *** 291,295 **** * @see #indices */ ! private final Map mapping = new HashMap(); /** --- 291,295 ---- * @see #indices */ ! private final Map<Object,Integer> mapping = new HashMap<Object, Integer>(); /** *************** *** 407,419 **** } ! // Assign the transaction a free index. ! ! index = (Integer) indices.remove(0); ! ! if (index == null) { ! throw new AssertionError("no free index to assign?"); ! } mapping.put(tx, index); // add transaction to mapping. --- 407,423 ---- } ! /* ! * Assign the transaction a free index. Throws ! * IndexOutOfBoundsException if there is no free index ! * available. ! */ ! index = (Integer) indices.remove(0); ! // if (index == null) { ! // ! // throw new AssertionError("no free index to assign?"); ! // ! // } mapping.put(tx, index); // add transaction to mapping. *************** *** 451,457 **** * * @param tx */ ! synchronized void releaseVertex( Object tx ) { --- 455,463 ---- * * @param tx + * + * @return true iff the vertex was known. */ ! synchronized boolean releaseVertex( Object tx ) { *************** *** 460,464 **** if( index == null ) { ! throw new IllegalArgumentException("tx="+tx); } --- 466,473 ---- if( index == null ) { ! // throw new IllegalArgumentException("tx="+tx); ! log.info("Not a vertex"); ! ! return false; } *************** *** 478,481 **** --- 487,492 ---- // resetOrder(); // invalidate the order[] cache. + return true; + } *************** *** 1098,1104 **** --- 1109,1117 ---- for (int i = 0; i < dst.length; i++) { if( ! updateClosure( src, dst[i], true ) ) { + log.warn("deadlock"); if( debug ) { log.debug(toString()); } + System.err.println(toString()); // FIXME uncomment this line. restore(order); throw new DeadlockException("deadlock"); *************** *** 1217,1221 **** // Object[] transactions = getTransactions(); // populate array of explict edges w/ optional closure. ! Vector v = new Vector(); for(int i=0; i<n; i++ ) { for( int j=0; j<n; j++ ) { --- 1230,1234 ---- // Object[] transactions = getTransactions(); // populate array of explict edges w/ optional closure. ! Vector<Edge> v = new Vector<Edge>(); for(int i=0; i<n; i++ ) { for( int j=0; j<n; j++ ) { *************** *** 1497,1501 **** * have been removed. */ ! releaseVertex( tx ); if( debug ) { log.debug(toString()); --- 1510,1516 ---- * have been removed. */ ! if(!releaseVertex( tx )) { ! throw new AssertionError("Unknown vertex="+tx); ! } if( debug ) { log.debug(toString()); Index: Lock.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/Lock.java,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** Lock.java 27 Mar 2006 21:27:20 -0000 1.4 --- Lock.java 2 Oct 2007 19:45:26 -0000 1.5 *************** *** 47,50 **** --- 47,53 ---- package org.CognitiveWeb.concurrent.locking; + import java.util.concurrent.locks.Condition; + import java.util.concurrent.locks.ReentrantLock; + /** * A lock obtained from a {@link Queue} governing access a database resource. *************** *** 54,58 **** * @author thompsonbry */ - public class Lock { --- 57,60 ---- *************** *** 229,232 **** --- 231,244 ---- return queue.isReleased( this ); } + + public String toString() { + + return super.toString() + "{resource=" + queue.getResource() + + ", mode=" + LockMode.getName(mode) + ", tx=" + tx + "}"; + + } + + // java.util.concurrent.locks.Lock lock = new ReentrantLock(); + // Condition granted = lock.newCondition(); } Index: Queue.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/Queue.java,v retrieving revision 1.8 retrieving revision 1.9 diff -C2 -d -r1.8 -r1.9 *** Queue.java 7 Apr 2006 16:50:04 -0000 1.8 --- Queue.java 2 Oct 2007 19:45:26 -0000 1.9 *************** *** 163,167 **** * The pending lock requests. */ ! private final IRequestQueue requestQueue = new RequestQueue(); /** --- 163,167 ---- * The pending lock requests. */ ! private final IRequestQueue requestQueue = new ConcurrentRequestQueue(); /** *************** *** 326,393 **** /** ! * <p> ! * Protected variant allows the caller to specify an explicit transaction ! * object rather than equating the transaction object with the thread of the ! * caller. In order to use this method the caller MUST observe the ! * constraint that at most one thread at a time may do work on a ! * transaction. Failure to observe this constraint can circumvent the ! * synchronization semantics and result in work continuing on a transaction ! * when it should be WAITing for a lock. ! * </p> ! * ! * @param tx ! * The transaction object. ! * ! * @param mode ! * The requested lock mode. ! * ! * @param timeout ! * the maximum time to wait in milliseconds. ! * ! * @param nanos ! * additional time, in nanoseconds range 0-999999. ! * ! * @return The granted {@link Lock}. ! * ! * @exception DeadlockException ! * if the lock request would result in a deadlock. ! * ! * @exception TimeoutException ! * if the lock could not be obtained within the specified ! * timeout period. ! * ! * @exception IllegalStateException ! * if the thread already has a granted lock on the resource ! * associated with this queue. ! * ! * @exception IllegalStateException ! * FIXME if the thread already has a pending lock request for ! * the resource associated with this queue (this exception ! * can only occur if more than one thread is doing work on ! * the same transaction at the same time - which is ! * explicitly forbidden). ! * ! * @issue [CONCURRENT-2] In order to support multiple locking granularities, ! * this method MUST examine the resource DAG as well in order to ! * determine if there is a higher level lock in progress. Further ! * locks must be granted and released in accord with the structure of ! * that resource DAG. This is coordinated by the use of the ! * "intention" modes to lock all ancestors in the resource DAG. For ! * example, when the resource DAG is a tree, the protocol to lock a ! * resource R in mode S or X is to first lock all ancestors of R in ! * that mode and then lock R. This method must handle all of that ! * transparently. ! * ! * @todo Examine the semantics when a lock is requested and has already been ! * granted. First, it should be impossible to request a lock that is ! * currently pending (iff transaction == thread). It then remains to ! * decide whether a lock mode may be modified by a lock request, ! * whether it is an error to request a lock when one has already been ! * granted, or whether it is allowed iff the same lock mode was ! * requested. ! * ! * @todo Add tryLock( short mode, long timeout, int nanos ) ! */ ! protected Lock lock( Object tx, short mode, long timeout, int nanos) throws DeadlockException, TimeoutException --- 326,397 ---- /** ! * <p> ! * Protected variant allows the caller to specify an explicit transaction ! * object rather than equating the transaction object with the thread of the ! * caller. In order to use this method the caller MUST observe the ! * constraint that at most one thread at a time may do work on a ! * transaction. Failure to observe this constraint can circumvent the ! * synchronization semantics and result in work continuing on a transaction ! * when it should be WAITing for a lock. ! * </p> ! * ! * @param tx ! * The transaction object. ! * ! * @param mode ! * The requested lock mode. ! * ! * @param timeout ! * the maximum time to wait in milliseconds. ! * ! * @param nanos ! * additional time, in nanoseconds range 0-999999. ! * ! * @return The granted {@link Lock}. ! * ! * @exception DeadlockException ! * if the lock request would result in a deadlock. ! * ! * @exception TimeoutException ! * if the lock could not be obtained within the specified ! * timeout period. ! * ! * @exception IllegalStateException ! * if the thread already has a granted lock on the resource ! * associated with this queue. ! * ! * @exception IllegalStateException ! * FIXME if the thread already has a pending lock request for ! * the resource associated with this queue (this exception ! * can only occur if more than one thread is doing work on ! * the same transaction at the same time - which is ! * explicitly forbidden). ! * ! * @issue [CONCURRENT-2] In order to support multiple locking granularities, ! * this method MUST examine the resource DAG as well in order to ! * determine if there is a higher level lock in progress. Further ! * locks must be granted and released in accord with the structure of ! * that resource DAG. This is coordinated by the use of the ! * "intention" modes to lock all ancestors in the resource DAG. For ! * example, when the resource DAG is a tree, the protocol to lock a ! * resource R in mode S or X is to first lock all ancestors of R in ! * that mode and then lock R. This method must handle all of that ! * transparently. ! * ! * @todo Examine the semantics when a lock is requested and has already been ! * granted. First, it should be impossible to request a lock that is ! * currently pending (iff transaction == thread). It then remains to ! * decide whether a lock mode may be modified by a lock request, ! * whether it is an error to request a lock when one has already been ! * granted, or whether it is allowed iff the same lock mode was ! * requested. ! * ! * @todo Add tryLock( short mode, long timeout, int nanos ) ! * ! * @todo What should the behavior be when interrupted while awaiting a lock? ! * What do the tests suites expect? Normally if something is ! * interrupted it should abort, so we could return a lock that is not ! * granted or interrupt the current thread. ! */ protected Lock lock( Object tx, short mode, long timeout, int nanos) throws DeadlockException, TimeoutException *************** *** 408,411 **** --- 412,418 ---- } + // @todo support timeouts + if(timeout!=0L) throw new UnsupportedOperationException(); + boolean changedState = false; *************** *** 423,427 **** if (lock != null) { ! synchronized (grantedGroup) { if (grantedGroup.contains(lock)) { --- 430,434 ---- if (lock != null) { ! // synchronized (grantedGroup) { if (grantedGroup.contains(lock)) { *************** *** 458,462 **** // } } // if( grantedGroup.contains( lock ) ) ! } // synchronized( grantedGroup ) } // if( lock != null ) --- 465,469 ---- // } } // if( grantedGroup.contains( lock ) ) ! // } // synchronized( grantedGroup ) } // if( lock != null ) *************** *** 465,487 **** synchronized (grantedGroup) { - synchronized (requestQueue) { ! /* ! * If there are no pending requests and the request is ! * compatible with the granted group, then grant it ! * immediately. ! */ ! if (requestQueue.size() == 0 ! && grantedGroup.isCompatibleRequest(mode)) { ! grantedGroup.add(lock, timestampFactory); ! changedState = true; ! return lock; ! } /* * Update the WAITS_FOR graph. --- 472,495 ---- synchronized (grantedGroup) { ! /* ! * If there are no pending requests and the request is ! * compatible with the granted group, then grant it ! * immediately. ! */ ! if (requestQueue.isEmpty() ! && grantedGroup.isCompatibleRequest(mode)) { ! grantedGroup.add(lock, timestampFactory); ! changedState = true; ! return lock; ! } + // synchronized (requestQueue) { + /* * Update the WAITS_FOR graph. *************** *** 498,502 **** changedState = true; ! } } --- 506,528 ---- changedState = true; ! // } ! ! // while(!lock.isGranted()) { ! // ! // log.info("Acquiring condition lock: "+lock); ! // lock.lock.lock(); ! // try { ! // log.info("Awaiting grant: "+lock); ! // lock.granted.await(); ! // } catch(InterruptedException ex) { ! // if(!lock.isGranted()) { ! // return lock; ! // } ! // } finally { ! // lock.lock.unlock(); ! // } ! // ! // } ! } *************** *** 594,598 **** * be granted. If the lock is not granted after the specified timeout, then * an exception is thrown. ! * * If this thread is interrupted, then we check to see if the lock was * granted. If not, and there is time remaining, then we reset the timeout --- 620,624 ---- * be granted. If the lock is not granted after the specified timeout, then * an exception is thrown. ! * <p> * If this thread is interrupted, then we check to see if the lock was * granted. If not, and there is time remaining, then we reset the timeout *************** *** 606,695 **** * * @todo Note: nanos are ignored. */ - private void block( Object tx, Lock lock, long begin, long timeout, int nanos ) { while (true) { ! try { synchronized (tx) { ! /* ! * Block the tx thread. ! */ ! long remaining = timeout ! - (System.currentTimeMillis() - begin); ! if( timeout == 0L ) { ! log.debug("blocking: resource=" + getResource() ! + ", tx=" + lock.getTransaction() ! + ", lock=" + lock); ! tx.wait(); // wait on TX. ! log.debug("resume: resource=" + getResource() ! + ", tx=" + lock.getTransaction() ! + ", lock=" + lock); ! } else if( remaining > 0L) { ! log.debug("blocking: resource=" + getResource() ! + ", tx=" + lock.getTransaction() ! + ", lock=" + lock + ", timeout=" + timeout ! + ", remaining=" + remaining); ! tx.wait(remaining); // wait on TX. ! long elapsed = System.currentTimeMillis() - begin; ! log.debug("resume: resource=" + getResource() ! + ", tx=" + lock.getTransaction() ! + ", lock=" + lock + ", timeout=" + timeout ! + ", elapsed=" + elapsed); } if (grantedGroup.contains(lock)) { // Lock was granted. if (info) { ! log.info(toString()); } return; - } else { - /* - * This condition will arise when a lock is not granted, - * either due to a timeout or because the transaction - * was aborted as a result of a deadlock. - */ - throw new RuntimeException("Lock not granted"); } ! } ! } catch (InterruptedException ex) { ! log.debug("interrupted: resource=" + getResource() ! + ", tx=" + lock.getTransaction() + ", lock=" ! + lock); ! if (grantedGroup.contains(lock)) { ! // Lock was granted. ! if (info) { ! log.info(toString()); } ! return; ! } ! } ! } // while( true ) } /** ! * Release a lock. ! * ! * @param lock ! * The lock. ! * ! * @exception IllegalArgumentException ! * If the <i>lock </i> is not associated with this ! * {@link Queue}. ! * ! * @return <code>true</code> iff a granted lock was released. (Other ! * possible outcomes include releasing a pending lock request and ! * invocation on a lock which had already been released and hence ! * was neither granted nor pending). ! * ! * @todo When integrating with an MVCC strategy for ww synchronization, the ! * timestamp of the lock MUST be updated from the timestamp assigned ! * to the transaction at its "locked point". ! * ! * @todo review synchronization assumptions in this method. ! * ! * @todo Should this method be exposed more in order to support release of ! * locks associated with aborted transactions? ! */ boolean releaseLock( Lock lock ) --- 632,719 ---- * * @todo Note: nanos are ignored. + * @todo should we abort on interrupt rather than continue? */ private void block( Object tx, Lock lock, long begin, long timeout, int nanos ) { + /* + * max time to wait w/o rechecking the grantedGroup. This keeps everyone + * from waiting forever if the lock was granted before this method was + * entered (a distinct possibility per lock(...) above). + */ + final long maxWait = 250; while (true) { ! final long remaining = timeout - (System.currentTimeMillis() - begin); ! while (timeout == 0L || remaining > 0L) { ! final long wait = timeout == 0L || remaining > maxWait ? maxWait ! : remaining; ! log.debug("blocking: resource=" + getResource() + ", tx=" ! + lock.getTransaction() + ", lock=" + lock ! + ", timeout=" + timeout); synchronized (tx) { ! try { // wait on TX. ! tx.wait(wait /* remaining */); ! } catch (InterruptedException ex) { ! log.debug("interrupted: lock=" + lock); ! if (grantedGroup.contains(lock)) { ! // Lock was granted. ! if (info) log.info(toString()); ! return; ! } } + final long elapsed = System.currentTimeMillis() - begin; + log.debug("resume: lock=" + lock + ", timeout=" + timeout + ", elapsed=" + elapsed); if (grantedGroup.contains(lock)) { // Lock was granted. if (info) { ! log.info("lock granted"); // toString()); } return; } ! if (requestQueue.isEmpty() && grantedGroup.isEmpty()) { ! // Error if both the request queue and granted ever ! // become empty. ! throw new AssertionError( ! "Blocked waiting but request queue and granted group are empty: " ! + lock); } ! // if (grantedGroup.isEmpty()) { ! // // Try granting requests. ! // grantRequests(); ! // } ! } // synchronized(tx) ! } // while(timeout...) ! /* ! * This condition will arise when a lock is not granted, either ! * due to a timeout or because the transaction was aborted as a ! * result of a deadlock. ! */ ! throw new RuntimeException("Lock not granted"); ! } // while( true ) } /** ! * Release a lock. ! * ! * @param lock ! * The lock. ! * ! * @exception IllegalArgumentException ! * If the <i>lock </i> is not associated with this ! * {@link Queue}. ! * ! * @return <code>true</code> iff a granted lock was released. (Other ! * possible outcomes include releasing a pending lock request and ! * invocation on a lock which had already been released and hence ! * was neither granted nor pending). ! * ! * @todo When integrating with an MVCC strategy for ww synchronization, the ! * timestamp of the lock MUST be updated from the timestamp assigned ! * to the transaction at its "locked point". ! * ! * @todo review synchronization assumptions in this method. ! * ! * @todo Should this method be exposed more in order to support release of ! * locks associated with aborted transactions? ! */ boolean releaseLock( Lock lock ) *************** *** 701,704 **** --- 725,730 ---- */ + final Object tx = lock.getTransaction(); + if( grantedGroup.remove( lock ) ) { *************** *** 712,717 **** Lock[] pendingLocks = requestQueue.getRequestedLocks(); for( int i=0; i<pendingLocks.length; i++ ) { ! waitsFor.removeEdge(pendingLocks[i].getTransaction(), lock ! .getTransaction()); } --- 738,742 ---- Lock[] pendingLocks = requestQueue.getRequestedLocks(); for( int i=0; i<pendingLocks.length; i++ ) { ! waitsFor.removeEdge(pendingLocks[i].getTransaction(), tx); } *************** *** 748,752 **** final boolean waiting = true; ! waitsFor.removeEdges(lock.getTransaction(), waiting ); if (info) { --- 773,777 ---- final boolean waiting = true; ! waitsFor.removeEdges(tx, waiting ); if (info) { *************** *** 835,839 **** Lock lock; ! synchronized( grantedGroup ) { if( ( lock = grantedGroup.getTxLock( tx ) ) != null ) { --- 860,864 ---- Lock lock; ! // synchronized( grantedGroup ) { if( ( lock = grantedGroup.getTxLock( tx ) ) != null ) { *************** *** 843,847 **** } ! synchronized (requestQueue) { if( ( lock = requestQueue.getTxLock( tx ) ) != null ) { --- 868,872 ---- } ! // synchronized (requestQueue) { if( ( lock = requestQueue.getTxLock( tx ) ) != null ) { *************** *** 851,857 **** } ! } ! ! } return null; --- 876,882 ---- } ! // } ! // ! // } return null; *************** *** 873,879 **** * @return <code>true</code> iff any requests were granted. */ - private boolean grantRequests() { // true iff one or more lock requests are granted. boolean changedState = false; --- 898,908 ---- * @return <code>true</code> iff any requests were granted. */ private boolean grantRequests() { + // There are no pending requests. + if (requestQueue.isEmpty()) { + return false; + } + // true iff one or more lock requests are granted. boolean changedState = false; *************** *** 881,890 **** try { ! synchronized (requestQueue) { ! ! // There are no pending requests. ! if (requestQueue.size() == 0) { ! return false; ! } /* --- 910,914 ---- try { ! // synchronized (requestQueue) { /* *************** *** 920,929 **** } - changedState = true; - if (!requestQueue.remove(requestedLock)) { ! throw new AssertionError(); } /* * Remove edges from the members of the granted group to --- 944,955 ---- } if (!requestQueue.remove(requestedLock)) { ! // Already granted or timeout out. ! log.info("Request gone"); ! return changedState; } + changedState = true; + /* * Remove edges from the members of the granted group to *************** *** 964,968 **** } ! } // next requestedLock --- 990,1003 ---- } ! ! // log.info("Acquiring condition lock: "+requestedLock); ! // requestedLock.lock.lock(); ! // try { ! // log.info("Signaling grant of lock: "+requestedLock); ! // requestedLock.granted.signalAll(); ! // } finally { ! // requestedLock.lock.unlock(); ! // } ! } // next requestedLock *************** *** 971,975 **** } // synchronized( grantedGroup ) ! } // synchronized( requestQueue ) } finally { --- 1006,1010 ---- } // synchronized( grantedGroup ) ! // } // synchronized( requestQueue ) } finally { *************** *** 1065,1069 **** --- 1100,1106 ---- */ public int getGroupSize() { + return grantedGroup.size(); + } *************** *** 1072,1098 **** */ public int getQueueSize() { return requestQueue.size(); } /** * A human readable representation of the state of the queue. */ ! public String toString() { /* ! * Make a synchronous snapshot of the state of the queue. */ final Lock[] grantedLocks; final Lock[] requestedLocks; final short groupMode; ! synchronized( grantedGroup ) { ! synchronized( requestQueue ) { ! groupMode = grantedGroup.getMode(); ! grantedLocks = grantedGroup.getGrantedLocks(); ! requestedLocks = requestQueue.getRequestedLocks(); } } --- 1109,1169 ---- */ public int getQueueSize() { + return requestQueue.size(); + } /** * A human readable representation of the state of the queue. + * <p> + * Note: The queue will be labelled as "inconsistent" because this method + * does not make a synchronous snapshot of its state in order to avoid + * deadlocks that might arise from synchronization. */ + public String toString() { + + return toString(false); + + } ! /** ! * A human readable representation of the state of the queue. ! * <p> ! * Caution: <strong>deadlocks may arise</strong> when ! * <code>synchronous := true</code>. ! * ! * @param synchronous ! * When true, a synchronous snapshot will be made. Otherwise the ! * queue will be labelled as "inconsistent" because this method ! * did not make a synchronous snapshot of its state in order to ! * avoid deadlocks that might arise from synchronization. ! * ! * @return ! */ ! public String toString(boolean synchronous) { /* ! * Make a snapshot of the state of the queue. */ final Lock[] grantedLocks; + final Lock[] requestedLocks; final short groupMode; ! if (synchronous) { ! // Note: This can cause synchronization deadlocks!!! ! synchronized (grantedGroup) { ! synchronized (requestQueue) { ! groupMode = grantedGroup.getMode(); ! grantedLocks = grantedGroup.getGrantedLocks(); ! requestedLocks = requestQueue.getRequestedLocks(); ! } } + } else { + + groupMode = grantedGroup.getMode(); + grantedLocks = grantedGroup.getGrantedLocks(); + requestedLocks = requestQueue.getRequestedLocks(); } *************** *** 1104,1108 **** StringBuffer sb = new StringBuffer(); ! sb.append("Queue(" + resource + ") "); if( grantedLocks.length > 0 ) { --- 1175,1179 ---- StringBuffer sb = new StringBuffer(); ! sb.append("Queue["+(synchronous?"":"in")+"consistent](" + resource + ") "); if( grantedLocks.length > 0 ) { --- RequestQueue.java DELETED --- Index: LockContextManager.java =================================================================== RCS file: /cvsroot/cweb/concurrent/src/java/org/CognitiveWeb/concurrent/locking/LockContextManager.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** LockContextManager.java 7 Apr 2006 16:50:04 -0000 1.1 --- LockContextManager.java 2 Oct 2007 19:45:26 -0000 1.2 *************** *** 92,96 **** * class. */ ! protected final Set lockContexts; /** --- 92,96 ---- * class. */ ! protected final Set<LockContext> lockContexts; /** *************** *** 134,155 **** waitsFor = new TxDag( capacity ); ! lockContexts = new HashSet( capacity ); } /** ! * Create a new {@link LockContext}. By default the {@link LockContext} ! * will be bound to the thread in which this request was made. ! * ! * @exception IllegalStateException ! * If the thread is already bound to another ! * {@link LockContext}. ! * ! * @exception IllegalStateException ! * If the maximum multi-programming level would be exceeded. ! * ! * @return The new {@link LockContext}. ! */ ! public LockContext createLockContext() { --- 134,154 ---- waitsFor = new TxDag( capacity ); ! lockContexts = new HashSet<LockContext>( capacity ); } /** ! * Create a new {@link LockContext}. By default the {@link LockContext} ! * initially will be bound to the thread in which this request was made. ! * ! * @exception IllegalStateException ! * If the current thread is already bound to another ! * {@link LockContext}. ! * ! * @exception IllegalStateException ! * If the maximum multi-programming level would be exceeded. ! * ! * @return The new {@link LockContext}. ! */ public LockContext createLockContext() { *************** *** 205,209 **** } ! } --- 204,218 ---- } ! ! /* ! * Release the vertex (if any) in the WAITS_FOR graph. ! * ! * Note: A vertex is created iff a dependency chain is established. ! * Therefore it is possible for a transaction to obtain a lock ! * without a vertex begin created for that tranasaction. Hence it is ! * Ok if this method returns [false]. ! */ ! waitsFor.releaseVertex(lockContext); ! } *************** *** 324,329 **** * current thread is not bound to any {@link LockContext}. */ ! final private static ThreadLocal lockContext = new ThreadLocal() { ! protected synchronized Object initialValue() { return null; } --- 333,338 ---- * current thread is not bound to any {@link LockContext}. */ ! final private static ThreadLocal<LockContext> lockContext = new ThreadLocal<LockContext>() { ! protected synchronized LockContext initialValue() { return null; } *************** *** 336,342 **** */ final static synchronized public LockContext getCurrentThread() { ! return (LockContext) lockContext.get(); } /** * Release the {@link LockContext} for the current thread. --- 345,368 ---- */ final static synchronized public LockContext getCurrentThread() { ! return lockContext.get(); } + /** + * <p> + * Forces the release of the {@link LockContext} object owned by the + * current thread (if any). + * </p> + * <p> + * Note: This is currently used by the test cases to "clean" the main + * thread in which the unit tests are executing between tests. If we + * don't clear the thread then subsequent unit tests can fail since the + * initial conditions for those tests assume that the main thread does + * not own a {@link LockContext}. + * </p> + */ + final static synchronized void clearCurrentThread() { + lockContext.set(null); + } + /** * Release the {@link LockContext} for the current thread. *************** *** 376,396 **** /** - * <p> - * Forces the release of the {@link LockContext} object owned by the - * current thread (if any). - * </p> - * <p> - * Note: This is currently used by the test cases to "clean" the main - * thread in which the unit tests are executing between tests. If we - * don't clear the thread then subsequent unit tests can fail since the - * initial conditions for those tests assume that the main thread does - * not own a {@link LockContext}. - * </p> - */ - final static synchronized void clearCurrentThread() { - lockContext.set(null); - } - - /** * The {@link LockContextManager}. */ --- 402,405 ---- *************** *** 404,415 **** * was thrown at the time that the lock was requested. */ ! private final Set locks = new HashSet(); /** * The {@link LockContext} manager. */ - public LockContextManager getLockContextManager() { ! return lockContextManager; } --- 413,425 ---- * was thrown at the time that the lock was requested. */ ! private final Set<Queue> locks = new HashSet<Queue>(); /** * The {@link LockContext} manager. */ public LockContextManager getLockContextManager() { ! ! return lockContextManager; ! } *************** *** 509,513 **** assertCurrentThread(); ! Queue queue = lockContextManager.getQueue( resource, true ); if( queue == null ) { --- 519,523 ---- assertCurrentThread(); ! Queue queue = lockContextManager.getQueue( resource, false ); if( queue == null ) { |
From: Bryan T. <tho...@us...> - 2007-09-11 12:04:19
|
Update of /cvsroot/cweb/generic-test In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv23799 Modified Files: project.xml Log Message: updated required version of junit-ext to 1.1-b3 which includes the refactored ULPs methods for floating point comparisons. Index: project.xml =================================================================== RCS file: /cvsroot/cweb/generic-test/project.xml,v retrieving revision 1.12 retrieving revision 1.13 diff -C2 -d -r1.12 -r1.13 *** project.xml 27 May 2006 21:58:54 -0000 1.12 --- project.xml 11 Sep 2007 12:04:15 -0000 1.13 *************** *** 159,163 **** <groupId>org.CognitiveWeb</groupId> <artifactId>cweb-junit-ext</artifactId> ! <version>1.1-b2-dev</version> <url>http://www.cognitiveweb.org/</url> </dependency> --- 159,163 ---- <groupId>org.CognitiveWeb</groupId> <artifactId>cweb-junit-ext</artifactId> ! <version>1.1-b3-dev</version> <url>http://www.cognitiveweb.org/</url> </dependency> |
From: Bryan T. <tho...@us...> - 2007-09-10 11:09:19
|
Update of /cvsroot/cweb/junit-ext/src/java/junit/framework In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv20004/src/java/junit/framework Modified Files: TestCase2.java Log Message: Remove some non-ASCII characters. Index: TestCase2.java =================================================================== RCS file: /cvsroot/cweb/junit-ext/src/java/junit/framework/TestCase2.java,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -d -r1.23 -r1.24 *** TestCase2.java 16 Aug 2007 09:48:51 -0000 1.23 --- TestCase2.java 10 Sep 2007 11:09:13 -0000 1.24 *************** *** 2127,2131 **** * specifies how big an error we are willing to accept in terms * of the value of the least significant digit of the floating ! * point numbers representation. <i>maxUlps</i> can also be * interpreted in terms of how many representable floats we are * willing to accept between A and B. This function will allow --- 2127,2131 ---- * specifies how big an error we are willing to accept in terms * of the value of the least significant digit of the floating ! * point number's representation. <i>maxUlps</i> can also be * interpreted in terms of how many representable floats we are * willing to accept between A and B. This function will allow *************** *** 2175,2179 **** * specifies how big an error we are willing to accept in terms * of the value of the least significant digit of the floating ! * point numbers representation. <i>maxUlps</i> can also be * interpreted in terms of how many representable doubles we are * willing to accept between A and B. This function will allow --- 2175,2179 ---- * specifies how big an error we are willing to accept in terms * of the value of the least significant digit of the floating ! * point number's representation. <i>maxUlps</i> can also be * interpreted in terms of how many representable doubles we are * willing to accept between A and B. This function will allow *************** *** 2254,2258 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will --- 2254,2258 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will *************** *** 2329,2333 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will --- 2329,2333 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will |
From: Bryan T. <tho...@us...> - 2007-09-10 11:02:19
|
Update of /cvsroot/cweb/generic-test/src/java/org/CognitiveWeb/generic/gql In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv16866/src/java/org/CognitiveWeb/generic/gql Modified Files: GValueTestCase.java Log Message: Remove some non-ASCII characters. Index: GValueTestCase.java =================================================================== RCS file: /cvsroot/cweb/generic-test/src/java/org/CognitiveWeb/generic/gql/GValueTestCase.java,v retrieving revision 1.11 retrieving revision 1.12 diff -C2 -d -r1.11 -r1.12 *** GValueTestCase.java 16 Aug 2007 09:49:45 -0000 1.11 --- GValueTestCase.java 10 Sep 2007 11:02:10 -0000 1.12 *************** *** 95,99 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will --- 95,99 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable floats // * we are willing to accept between A and B. This function will *************** *** 170,174 **** // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will --- 170,174 ---- // * Place. This specifies how big an error we are willing to accept // * in terms of the value of the least significant digit of the ! // * floating point number's representation. <i>maxUlps</i> can // * also be interpreted in terms of how many representable doubles // * we are willing to accept between A and B. This function will |
From: Bryan T. <tho...@us...> - 2007-08-28 16:14:09
|
Update of /cvsroot/cweb/rdf-generic/src/test/org/CognitiveWeb/sesame/sailimpl/generic In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv17805/src/test/org/CognitiveWeb/sesame/sailimpl/generic Modified Files: TestUnicodeClean.java Log Message: added test of delete. Index: TestUnicodeClean.java =================================================================== RCS file: /cvsroot/cweb/rdf-generic/src/test/org/CognitiveWeb/sesame/sailimpl/generic/TestUnicodeClean.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** TestUnicodeClean.java 27 Aug 2007 19:39:31 -0000 1.1 --- TestUnicodeClean.java 28 Aug 2007 14:59:09 -0000 1.2 *************** *** 135,180 **** new LiteralImpl(unicode1))); /* ! * Verify literals can be returned from the graph. */ ! StatementIterator itr = r.getStatements(null, null, null); ! try { ! ! int stmt1 = 0, stmt2 = 0, stmt3 = 0; ! while (itr.hasNext()) { ! Statement stmt = itr.next(); ! Literal lit = (Literal) stmt.getObject(); ! if(lit.getLabel().equals("Gozo")) stmt1++; ! if(lit.getLabel().equals("gozo")) stmt2++; ! if(lit.getLabel().equals(unicode1)) stmt3++; ! } ! ! // verify ASCII literal is returned. ! assertEquals("stmt1",1,stmt1); ! ! if(stmt2==0) { ! /* ! * The index does not differentiate between "Gozo" and "gozo" ! * (it is not case sensitive). ! */ ! log.warn("Index does not differentiate case of strings."); } ! ! // verify can return Unicode literal. ! assertEquals("stmt3",1,stmt3); ! ! } finally { ! ! itr.close(); ! } --- 135,252 ---- new LiteralImpl(unicode1))); + { + + /* + * Verify literals can be returned from the graph. + */ + StatementIterator itr = r.getStatements(null, null, null); + + try { + + int stmt1 = 0, stmt2 = 0, stmt3 = 0; + + while (itr.hasNext()) { + + Statement stmt = itr.next(); + + Literal lit = (Literal) stmt.getObject(); + + if (lit.getLabel().equals("Gozo")) + stmt1++; + if (lit.getLabel().equals("gozo")) + stmt2++; + if (lit.getLabel().equals(unicode1)) + stmt3++; + + } + + // verify ASCII literal is returned. + assertEquals("stmt1", 1, stmt1); + + if (stmt2 == 0) { + + /* + * The index does not differentiate between "Gozo" and + * "gozo" (it is not case sensitive). + */ + + log.warn("Index does not differentiate case of strings."); + + } + + // verify can return Unicode literal. + assertEquals("stmt3", 1, stmt3); + + } finally { + + itr.close(); + + } + + } + /* ! * Attempt to remove the unicode label. */ ! { ! ! r.startTransaction(); ! ! assertEquals("#removed", 1, r.removeStatements(null, ! URIImpl.RDFS_LABEL, new LiteralImpl(unicode1))); ! ! r.commitTransaction(); ! ! } ! /* ! * Verify that the unicode label is gone. ! */ ! { ! /* ! * Verify literals can be returned from the graph. ! */ ! StatementIterator itr = r.getStatements(null, null, null); ! ! try { ! int stmt1 = 0, stmt2 = 0, stmt3 = 0; ! ! while (itr.hasNext()) { ! Statement stmt = itr.next(); ! ! Literal lit = (Literal) stmt.getObject(); ! ! if(lit.getLabel().equals("Gozo")) stmt1++; ! if(lit.getLabel().equals("gozo")) stmt2++; ! if(lit.getLabel().equals(unicode1)) stmt3++; ! ! } ! // verify ASCII literal is returned. ! assertEquals("stmt1",1,stmt1); ! if(stmt2==0) { ! ! /* ! * The index does not differentiate between "Gozo" and "gozo" ! * (it is not case sensitive). ! */ ! ! log.warn("Index does not differentiate case of strings."); ! ! } ! // verify will no longer return Unicode literal. ! assertEquals("stmt3",0,stmt3); ! } finally { ! ! itr.close(); } ! } |
From: Bryan T. <tho...@us...> - 2007-08-27 19:39:36
|
Update of /cvsroot/cweb/rdf-generic/src/test/org/CognitiveWeb/sesame/sailimpl/generic In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv7880/src/test/org/CognitiveWeb/sesame/sailimpl/generic Added Files: TestUnicodeClean.java Log Message: Added a test for Unicode clean literals. (The CTC store is not Unicode clean in its indices - the "YAC"s but it does store and return Unicode strings without trouble.) --- NEW FILE: TestUnicodeClean.java --- /** The Notice below must appear in each file of the Source Code of any copy you distribute of the Licensed Product. Contributors to any Modifications may add their own copyright notices to identify their own contributions. License: The contents of this file are subject to the CognitiveWeb Open Source License Version 1.1 (the License). You may not copy or use this file, in either source code or executable form, except in compliance with the License. You may obtain a copy of the License from http://www.CognitiveWeb.org/legal/license/ Software distributed under the License is distributed on an AS IS basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Copyrights: Portions created by or assigned to CognitiveWeb are Copyright (c) 2003-2003 CognitiveWeb. All Rights Reserved. Contact information for CognitiveWeb is available at http://www.CognitiveWeb.org Portions Copyright (c) 2002-2003 Bryan Thompson. Acknowledgements: Special thanks to the developers of the Jabber Open Source License 1.0 (JOSL), from which this License was derived. This License contains terms that differ from JOSL. Special thanks to the CognitiveWeb Open Source Contributors for their suggestions and support of the Cognitive Web. Modifications: */ /* * Created on Aug 27, 2007 */ package org.CognitiveWeb.sesame.sailimpl.generic; import java.util.Properties; import java.util.UUID; import org.CognitiveWeb.sesame.sailimpl.generic.ctc.CTCGRdfRepository; import org.openrdf.model.Literal; import org.openrdf.model.Statement; import org.openrdf.model.impl.LiteralImpl; import org.openrdf.model.impl.URIImpl; import org.openrdf.sesame.sail.RdfRepository; import org.openrdf.sesame.sail.SailUpdateException; import org.openrdf.sesame.sail.StatementIterator; /** * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestUnicodeClean extends AbstractRepositoryTestCase { /** * */ public TestUnicodeClean() { super(); } /** * @param name */ public TestUnicodeClean(String name) { super(name); } /** * The URI used in the tests. It is random so that it will not collide with * existing URIs if you are running the integration test. */ final URIImpl uri1 = new URIImpl("http://www.systap.com/test/uri1/"+UUID.randomUUID()); /** * A label that is used to test for Unicode clean. The UTF-16 code points * are: * * <pre> * 0047 0127 0061 0077 0064 0065 0078 * </pre> */ final String unicode1 = "G\u0127awdex"; public Properties getProperties() { Properties properties = super.getProperties(); properties.setProperty ( "repositoryClass", CTCGRdfRepository.class.getName() // CTCGRdfSchemaRepository.class.getName() ); return properties; } public void test_unicodeClean() throws SailUpdateException { RdfRepository r = super.m_repo; r.startTransaction(); r.addStatement(uri1, URIImpl.RDFS_LABEL, new LiteralImpl("Gozo")); r.addStatement(uri1, URIImpl.RDFS_LABEL, new LiteralImpl(unicode1)); r.commitTransaction(); // verify with ASCII label. assertTrue(r.hasStatement(uri1, URIImpl.RDFS_LABEL, new LiteralImpl("Gozo"))); // verify with lower case version of label (not found). assertFalse(r.hasStatement(uri1, URIImpl.RDFS_LABEL, new LiteralImpl("gozo"))); // verify with Unicode label. assertTrue(r.hasStatement(uri1, URIImpl.RDFS_LABEL, new LiteralImpl(unicode1))); /* * Verify literals can be returned from the graph. */ StatementIterator itr = r.getStatements(null, null, null); try { int stmt1 = 0, stmt2 = 0, stmt3 = 0; while (itr.hasNext()) { Statement stmt = itr.next(); Literal lit = (Literal) stmt.getObject(); if(lit.getLabel().equals("Gozo")) stmt1++; if(lit.getLabel().equals("gozo")) stmt2++; if(lit.getLabel().equals(unicode1)) stmt3++; } // verify ASCII literal is returned. assertEquals("stmt1",1,stmt1); if(stmt2==0) { /* * The index does not differentiate between "Gozo" and "gozo" * (it is not case sensitive). */ log.warn("Index does not differentiate case of strings."); } // verify can return Unicode literal. assertEquals("stmt3",1,stmt3); } finally { itr.close(); } } } |
From: Bryan T. <tho...@us...> - 2007-08-16 10:49:20
|
Update of /cvsroot/cweb/generic-test/src/java/org/CognitiveWeb/generic/gql In directory sc8-pr-cvs4.sourceforge.net:/tmp/cvs-serv27969/src/java/org/CognitiveWeb/generic/gql Modified Files: GValueTestCase.java Log Message: Moved ulps support into the junit-test module (TestCase2 class). Index: GValueTestCase.java =================================================================== RCS file: /cvsroot/cweb/generic-test/src/java/org/CognitiveWeb/generic/gql/GValueTestCase.java,v retrieving revision 1.10 retrieving revision 1.11 diff -C2 -d -r1.10 -r1.11 *** GValueTestCase.java 10 Jun 2006 18:16:05 -0000 1.10 --- GValueTestCase.java 16 Aug 2007 09:49:45 -0000 1.11 *************** *** 81,487 **** } ! //************************************************************ ! //************************************************************ ! //************************************************************ ! ! /** ! * Derived from <a ! * href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"> ! * Comparing floating point numbers </a> by Bruce Dawson. ! * ! * @param A A floating point value. ! * @param B Another floating point value ! * @param maxUlps The maximum error in terms of Units in the Last ! * Place. This specifies how big an error we are willing to accept ! * in terms of the value of the least significant digit of the ! * floating point numbers representation. <i>maxUlps</i> can ! * also be interpreted in terms of how many representable floats ! * we are willing to accept between A and B. This function will ! * allow <code>maxUlps-1</code> floats between <i>A</i> and ! * <i>B</i>. ! */ ! ! static protected int getUlps ! // static public boolean AlmostEqual2sComplement ! ( float A, ! float B ! // , ! // int maxUlps ! ) ! { ! ! // // Make sure maxUlps is non-negative and small enough that the ! // // default NAN won't compare as equal to anything. ! ! // if( ! (maxUlps > 0 && maxUlps < 4 * 1024 * 1024) ) { ! ! // throw new IllegalArgumentException ! // ( "maxUlps is out of range: "+maxUlps ! // ); ! ! // } ! ! int aInt = Float.floatToIntBits( A ); // *(int*)&A; ! ! // Make aInt lexicographically ordered as a twos-complement ! // int. ! ! if (aInt < 0) { ! ! aInt = 0x80000000 - aInt; ! ! } ! ! // Make bInt lexicographically ordered as a twos-complement ! // int. ! ! int bInt = Float.floatToIntBits( B ); // *(int*)&B; ! ! if (bInt < 0) { ! ! bInt = 0x80000000 - bInt; ! ! } ! ! int intDiff = Math.abs ! ( aInt - bInt ! ); ! ! return intDiff; ! ! // if (intDiff <= maxUlps) { ! ! // return true; ! ! // } ! ! // return false; ! ! } ! ! /** ! * Derived from <a ! * href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"> ! * Comparing floating point numbers </a> by Bruce Dawson. ! * ! * @param A A double precision floating point value. ! * @param B Another double precision floating point value ! * @param maxUlps The maximum error in terms of Units in the Last ! * Place. This specifies how big an error we are willing to accept ! * in terms of the value of the least significant digit of the ! * floating point numbers representation. <i>maxUlps</i> can ! * also be interpreted in terms of how many representable doubles ! * we are willing to accept between A and B. This function will ! * allow <code>maxUlps-1</code> doubles between <i>A</i> and ! * <i>B</i>. ! */ ! ! static protected long getUlps ! // static public boolean AlmostEqual2sComplement ! ( double A, ! double B ! // , ! // long maxUlps ! ) ! { ! ! // Make sure maxUlps is non-negative and small enough that the ! // default NAN won't compare as equal to anything. ! // ! // @todo The range check here is for float. The max possible ! // legal range is larger for double. ! ! // if( ! (maxUlps > 0 && maxUlps < 4 * 1024 * 1024) ) { ! ! // throw new IllegalArgumentException ! // ( "maxUlps is out of range: "+maxUlps ! // ); ! ! // } ! ! long aLong = Double.doubleToLongBits( A ); // *(int*)&A; ! ! // Make aInt lexicographically ordered as a twos-complement ! // long. ! ! if (aLong < 0) { ! ! aLong = 0x8000000000000000L - aLong; ! ! } ! ! // Make bInt lexicographically ordered as a twos-complement ! // int. ! ! long bLong = Double.doubleToLongBits( B ); // *(int*)&B; ! ! if (bLong < 0) { ! ! bLong = 0x8000000000000000L - bLong; ! ! } ! ! long longDiff = Math.abs ! ( aLong - bLong ! ); ! ! ! return longDiff; ! ! // if (longDiff <= maxUlps) { ! ! // return true; ! ! // } ! ! // return false; ! ! } ! ! /** ! * Provides a proper basis for comparing floating point numbers. ! */ ! ! public static void assertEquals ! ( float expected, ! float actual ! ) ! { ! assertEquals ! ( "", ! expected, ! actual ! ); ! } ! ! /** ! * Provides a proper basis for comparing floating point numbers. ! */ ! ! public static void assertEquals ! ( String message, ! float expected, ! float actual ! ) ! { ! ! if( expected == actual ) return; ! ! final int maxUlps = 10; ! ! int ulps = getUlps( expected, actual ); ! ! if( ulps <= maxUlps ) { ! ! return; ! ! } ! ! fail( "Expecting "+expected+", not "+actual+ ! ": abs(difference)="+Math.abs( expected - actual )+ ! ": ulps="+ulps ! ); ! ! } ! ! public static void assertEquals ! ( double expected, ! double actual ! ) ! { ! assertEquals ! ( "", ! expected, ! actual ! ); ! } ! ! public static void assertEquals ! ( String message, ! double expected, ! double actual ! ) ! { ! ! if( expected == actual ) return; ! ! ! final long maxUlps = 10L; ! ! long ulps = getUlps( expected, actual ); ! ! if( ulps <= maxUlps ) { ! ! return; ! ! } ! ! fail( "Expecting "+expected+", not "+actual+ ! ": abs(difference)="+Math.abs( expected - actual )+ ! ", ulps="+ulps ! ); ! ! } ! ! public static void assertSameBigInteger ! ( BigInteger expected, ! BigInteger actual ! ) ! { ! ! assertSameBigInteger ! ( "", ! expected, ! actual ! ); ! ! } ! ! public static void assertSameBigInteger ! ( String message, ! BigInteger expected, ! BigInteger actual ! ) ! { ! ! assertTrue ! ( message+": expected "+expected+", not "+actual, ! expected.equals( actual ) ! ); ! ! } ! ! /** ! * This uses {@link BigDecimal#compareTo( Object other )}, which ! * considers that two {@link BigDecimal}s that are equal in ! * <i>value</i> but have a different <i>scale</i> are the same. ! * (This is NOT true of {@link BigDecimal#equals( Object other )}, ! * which also requires the values to ave the same <i>scale</i>.) ! */ ! ! public static void assertSameBigDecimal ! ( BigDecimal expected, ! BigDecimal actual ! ) ! { ! ! assertEquals ! ( "", ! expected, ! actual ! ); ! ! } ! ! /** ! * This uses {@link BigDecimal#compareTo( Object other )}, which ! * considers that two {@link BigDecimal}s that are equal in ! * <i>value</i> but have a different <i>scale</i> are the same. ! * (This is NOT true of {@link BigDecimal#equals( Object other )}, ! * which also requires the values to ave the same <i>scale</i>.) ! */ ! ! public static void assertSameBigDecimal ! ( String message, ! BigDecimal expected, ! BigDecimal actual ! ) ! { ! ! assertTrue ! ( message+": expected "+expected+", not "+actual, ! expected.compareTo( actual ) == 0 ! ); ! ! } ! ! /** ! * Helper method verifies that the arrays are consistent in length ! * and that their elements are consistent under {@link ! * Object#equals( Object other )}. ! */ ! ! public static void assertSameArray ! ( Object[] expected, ! Object[] actual ! ) ! { ! assertSameArray ! ( "", ! expected, ! actual ! ); ! } ! ! /** ! * Helper method verifies that the arrays are consistent in length ! * and that their elements are consistent under {@link ! * Object#equals( Object other )}. ! */ ! ! public static void assertSameArray ! ( String message, ! Object[] expected, ! Object[] actual ! ) ! { ! ! if( expected == null && actual == null ) { ! ! return; ! ! } ! ! if( expected != null && actual == null ) { ! ! fail( message+" : expecting actual to be non-null." ! ); ! ! } ! ! if( expected == null && actual != null ) { ! ! fail( message+" : expecting actual to be null." ! ); ! ! } ! ! assertEquals ! ( message+" : length is wrong.", ! expected.length, ! actual.length ! ); ! ! for( int i=0; i<expected.length; i++ ) { ! ! if( expected[i] == null && actual[i] == null ) { ! ! continue; ! ! } ! ! if( expected[i] != null && actual[i] == null ) { ! ! fail( message+" : expecting actual["+i+"] to be non-null" ! ); ! ! } ! ! if( expected[i] == null && actual[i] != null ) { ! ! fail( message+" : expecting actual["+i+"] to be null." ! ); ! ! } ! ! assertTrue ! ( message+" : expected["+i+"]="+expected[i]+ ! ", but actual["+i+"]="+actual[i], ! expected[i].equals( actual[i] ) ! ); ! ! } ! ! } //************************************************************ --- 81,487 ---- } ! // //************************************************************ ! // //************************************************************ ! // //************************************************************ ! // ! // /** ! // * Derived from <a ! // * href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"> ! // * Comparing floating point numbers </a> by Bruce Dawson. ! // * ! // * @param A A floating point value. ! // * @param B Another floating point value ! // * @param maxUlps The maximum error in terms of Units in the Last ! // * Place. This specifies how big an error we are willing to accept ! // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can ! // * also be interpreted in terms of how many representable floats ! // * we are willing to accept between A and B. This function will ! // * allow <code>maxUlps-1</code> floats between <i>A</i> and ! // * <i>B</i>. ! // */ ! // ! // static protected int getUlps ! //// static public boolean AlmostEqual2sComplement ! // ( float A, ! // float B ! //// , ! //// int maxUlps ! // ) ! // { ! // ! //// // Make sure maxUlps is non-negative and small enough that the ! //// // default NAN won't compare as equal to anything. ! // ! //// if( ! (maxUlps > 0 && maxUlps < 4 * 1024 * 1024) ) { ! // ! //// throw new IllegalArgumentException ! //// ( "maxUlps is out of range: "+maxUlps ! //// ); ! // ! //// } ! // ! // int aInt = Float.floatToIntBits( A ); // *(int*)&A; ! // ! // // Make aInt lexicographically ordered as a twos-complement ! // // int. ! // ! // if (aInt < 0) { ! // ! // aInt = 0x80000000 - aInt; ! // ! // } ! // ! // // Make bInt lexicographically ordered as a twos-complement ! // // int. ! // ! // int bInt = Float.floatToIntBits( B ); // *(int*)&B; ! // ! // if (bInt < 0) { ! // ! // bInt = 0x80000000 - bInt; ! // ! // } ! // ! // int intDiff = Math.abs ! // ( aInt - bInt ! // ); ! // ! // return intDiff; ! // ! //// if (intDiff <= maxUlps) { ! // ! //// return true; ! // ! //// } ! // ! //// return false; ! // ! // } ! // ! // /** ! // * Derived from <a ! // * href="http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm"> ! // * Comparing floating point numbers </a> by Bruce Dawson. ! // * ! // * @param A A double precision floating point value. ! // * @param B Another double precision floating point value ! // * @param maxUlps The maximum error in terms of Units in the Last ! // * Place. This specifies how big an error we are willing to accept ! // * in terms of the value of the least significant digit of the ! // * floating point numbers representation. <i>maxUlps</i> can ! // * also be interpreted in terms of how many representable doubles ! // * we are willing to accept between A and B. This function will ! // * allow <code>maxUlps-1</code> doubles between <i>A</i> and ! // * <i>B</i>. ! // */ ! // ! // static protected long getUlps ! //// static public boolean AlmostEqual2sComplement ! // ( double A, ! // double B ! //// , ! //// long maxUlps ! // ) ! // { ! // ! // // Make sure maxUlps is non-negative and small enough that the ! // // default NAN won't compare as equal to anything. ! // // ! // // @todo The range check here is for float. The max possible ! // // legal range is larger for double. ! // ! //// if( ! (maxUlps > 0 && maxUlps < 4 * 1024 * 1024) ) { ! // ! //// throw new IllegalArgumentException ! //// ( "maxUlps is out of range: "+maxUlps ! //// ); ! // ! //// } ! // ! // long aLong = Double.doubleToLongBits( A ); // *(int*)&A; ! // ! // // Make aInt lexicographically ordered as a twos-complement ! // // long. ! // ! // if (aLong < 0) { ! // ! // aLong = 0x8000000000000000L - aLong; ! // ! // } ! // ! // // Make bInt lexicographically ordered as a twos-complement ! // // int. ! // ! // long bLong = Double.doubleToLongBits( B ); // *(int*)&B; ! // ! // if (bLong < 0) { ! // ! // bLong = 0x8000000000000000L - bLong; ! // ! // } ! // ! // long longDiff = Math.abs ! // ( aLong - bLong ! // ); ! // ! // ! // return longDiff; ! // ! //// if (longDiff <= maxUlps) { ! // ! //// return true; ! // ! //// } ! // ! //// return false; ! // ! // } ! // ! // /** ! // * Provides a proper basis for comparing floating point numbers. ! // */ ! // ! // public static void assertEquals ! // ( float expected, ! // float actual ! // ) ! // { ! // assertEquals ! // ( "", ! // expected, ! // actual ! // ); ! // } ! // ! // /** ! // * Provides a proper basis for comparing floating point numbers. ! // */ ! // ! // public static void assertEquals ! // ( String message, ! // float expected, ! // float actual ! // ) ! // { ! // ! // if( expected == actual ) return; ! // ! // final int maxUlps = 10; ! // ! // int ulps = getUlps( expected, actual ); ! // ! // if( ulps <= maxUlps ) { ! // ! // return; ! // ! // } ! // ! // fail( "Expecting "+expected+", not "+actual+ ! // ": abs(difference)="+Math.abs( expected - actual )+ ! // ": ulps="+ulps ! // ); ! // ! // } ! // ! // public static void assertEquals ! // ( double expected, ! // double actual ! // ) ! // { ! // assertEquals ! // ( "", ! // expected, ! // actual ! // ); ! // } ! // ! // public static void assertEquals ! // ( String message, ! // double expected, ! // double actual ! // ) ! // { ! // ! // if( expected == actual ) return; ! // ! // ! // final long maxUlps = 10L; ! // ! // long ulps = getUlps( expected, actual ); ! // ! // if( ulps <= maxUlps ) { ! // ! // return; ! // ! // } ! // ! // fail( "Expecting "+expected+", not "+actual+ ! // ": abs(difference)="+Math.abs( expected - actual )+ ! // ", ulps="+ulps ! // ); ! // ! // } ! // ! // public static void assertSameBigInteger ! // ( BigInteger expected, ! // BigInteger actual ! // ) ! // { ! // ! // assertSameBigInteger ! // ( "", ! // expected, ! // actual ! // ); ! // ! // } ! // ! // public static void assertSameBigInteger ! // ( String message, ! // BigInteger expected, ! // BigInteger actual ! // ) ! // { ! // ! // assertTrue ! // ( message+": expected "+expected+", not "+actual, ! // expected.equals( actual ) ! // ); ! // ! // } ! // ! // /** ! // * This uses {@link BigDecimal#compareTo( Object other )}, which ! // * considers that two {@link BigDecimal}s that are equal in ! // * <i>value</i> but have a different <i>scale</i> are the same. ! // * (This is NOT true of {@link BigDecimal#equals( Object other )}, ! // * which also requires the values to ave the same <i>scale</i>.) ! // */ ! // ! // public static void assertSameBigDecimal ! // ( BigDecimal expected, ! // BigDecimal actual ! // ) ! // { ! // ! // assertEquals ! // ( "", ! // expected, ! // actual ! // ); ! // ! // } ! // ! // /** ! // * This uses {@link BigDecimal#compareTo( Object other )}, which ! // * considers that two {@link BigDecimal}s that are equal in ! // * <i>value</i> but have a different <i>scale</i> are the same. ! // * (This is NOT true of {@link BigDecimal#equals( Object other )}, ! // * which also requires the values to ave the same <i>scale</i>.) ! // */ ! // ! // public static void assertSameBigDecimal ! // ( String message, ! // BigDecimal expected, ! // BigDecimal actual ! // ) ! // { ! // ! // assertTrue ! // ( message+": expected "+expected+", not "+actual, ! // expected.compareTo( actual ) == 0 ! // ); ! // ! // } ! // ! // /** ! // * Helper method verifies that the arrays are consistent in length ! // * and that their elements are consistent under {@link ! // * Object#equals( Object other )}. ! // */ ! // ! // public static void assertSameArray ! // ( Object[] expected, ! // Object[] actual ! // ) ! // { ! // assertSameArray ! // ( "", ! // expected, ! // actual ! // ); ! // } ! // ! // /** ! // * Helper method verifies that the arrays are consistent in length ! // * and that their elements are consistent under {@link ! // * Object#equals( Object other )}. ! // */ ! // ! // public static void assertSameArray ! // ( String message, ! // Object[] expected, ! // Object[] actual ! // ) ! // { ! // ! // if( expected == null && actual == null ) { ! // ! // return; ! // ! // } ! // ! // if( expected != null && actual == null ) { ! // ! // fail( message+" : expecting actual to be non-null." ! // ); ! // ! // } ! // ! // if( expected == null && actual != null ) { ! // ! // fail( message+" : expecting actual to be null." ! // ); ! // ! // } ! // ! // assertEquals ! // ( message+" : length is wrong.", ! // expected.length, ! // actual.length ! // ); ! // ! // for( int i=0; i<expected.length; i++ ) { ! // ! // if( expected[i] == null && actual[i] == null ) { ! // ! // continue; ! // ! // } ! // ! // if( expected[i] != null && actual[i] == null ) { ! // ! // fail( message+" : expecting actual["+i+"] to be non-null" ! // ); ! // ! // } ! // ! // if( expected[i] == null && actual[i] != null ) { ! // ! // fail( message+" : expecting actual["+i+"] to be null." ! // ); ! // ! // } ! // ! // assertTrue ! // ( message+" : expected["+i+"]="+expected[i]+ ! // ", but actual["+i+"]="+actual[i], ! // expected[i].equals( actual[i] ) ! // ); ! // ! // } ! // ! // } //************************************************************ |