0001: /**
0002:
0003: * JDBM LICENSE v1.00
0004:
0005: *
0006:
0007: * Redistribution and use of this software and associated documentation
0008:
0009: * ("Software"), with or without modification, are permitted provided
0010:
0011: * that the following conditions are met:
0012:
0013: *
0014:
0015: * 1. Redistributions of source code must retain copyright
0016:
0017: * statements and notices. Redistributions must also contain a
0018:
0019: * copy of this document.
0020:
0021: *
0022:
0023: * 2. Redistributions in binary form must reproduce the
0024:
0025: * above copyright notice, this list of conditions and the
0026:
0027: * following disclaimer in the documentation and/or other
0028:
0029: * materials provided with the distribution.
0030:
0031: *
0032:
0033: * 3. The name "JDBM" must not be used to endorse or promote
0034:
0035: * products derived from this Software without prior written
0036:
0037: * permission of Cees de Groot. For written permission,
0038:
0039: * please contact cg@cdegroot.com.
0040:
0041: *
0042:
0043: * 4. Products derived from this Software may not be called "JDBM"
0044:
0045: * nor may "JDBM" appear in their names without prior written
0046:
0047: * permission of Cees de Groot.
0048:
0049: *
0050:
0051: * 5. Due credit should be given to the JDBM Project
0052:
0053: * (http://jdbm.sourceforge.net/).
0054:
0055: *
0056:
0057: * THIS SOFTWARE IS PROVIDED BY THE JDBM PROJECT AND CONTRIBUTORS
0058:
0059: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
0060:
0061: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
0062:
0063: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
0064:
0065: * CEES DE GROOT OR ANY CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
0066:
0067: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0068:
0069: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
0070:
0071: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
0072:
0073: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
0074:
0075: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0076:
0077: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
0078:
0079: * OF THE POSSIBILITY OF SUCH DAMAGE.
0080:
0081: *
0082:
0083: * Copyright 2000 (C) Cees de Groot. All Rights Reserved.
0084:
0085: * Contributions are Copyright (C) 2000 by their associated contributors.
0086:
0087: *
0088:
0089: */package jdbm.btree;
0090:
0091: import jdbm.RecordManager;
0092:
0093: import jdbm.RecordManagerFactory;
0094:
0095: import jdbm.recman.TestRecordFile;
0096:
0097: import jdbm.helper.ByteArrayComparator;
0098:
0099: import jdbm.helper.StringComparator;
0100:
0101: import jdbm.helper.TupleBrowser;
0102:
0103: import jdbm.helper.Tuple;
0104:
0105: import junit.framework.*;
0106:
0107: import java.io.IOException;
0108:
0109: import java.io.Serializable;
0110:
0111: import java.util.Map;
0112:
0113: import java.util.TreeMap;
0114:
0115: import java.util.Iterator;
0116:
0117: /**
0118:
0119: * This class contains all Unit tests for {@link BTree}.
0120:
0121: *
0122:
0123: * @author <a href="mailto:boisvert@exoffice.com">Alex Boisvert</a>
0124:
0125: * @version $Id: TestBTree.java,v 1.8 2003/09/21 15:49:02 boisvert Exp $
0126:
0127: */
0128:
0129: public class TestBTree
0130:
0131: extends TestCase
0132:
0133: {
0134:
0135: static final boolean DEBUG = false;
0136:
0137: // the number of threads to be started in the synchronization test
0138:
0139: static final int THREAD_NUMBER = 5;
0140:
0141: // the size of the content of the maps for the synchronization
0142:
0143: // test. Beware that THREAD_NUMBER * THREAD_CONTENT_COUNT < Integer.MAX_VALUE.
0144:
0145: static final int THREAD_CONTENT_SIZE = 150;
0146:
0147: // for how long should the threads run.
0148:
0149: static final int THREAD_RUNTIME = 10 * 1000;
0150:
0151: protected TestResult result_;
0152:
0153: public TestBTree(String name)
0154:
0155: {
0156:
0157: super (name);
0158:
0159: }
0160:
0161: public void setUp()
0162:
0163: {
0164:
0165: TestRecordFile.deleteTestFile();
0166:
0167: }
0168:
0169: public void tearDown()
0170:
0171: {
0172:
0173: TestRecordFile.deleteTestFile();
0174:
0175: }
0176:
0177: /**
0178:
0179: * Overrides TestCase.run(TestResult), so the errors from threads
0180:
0181: * started from this thread can be added to the testresult. This is
0182:
0183: * shown in
0184:
0185: * http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit.html
0186:
0187: *
0188:
0189: * @param result the testresult
0190:
0191: */
0192:
0193: public void run(TestResult result)
0194:
0195: {
0196:
0197: result_ = result;
0198:
0199: super .run(result);
0200:
0201: result_ = null;
0202:
0203: }
0204:
0205: //----------------------------------------------------------------------
0206:
0207: /**
0208:
0209: * Handles the exceptions from other threads, so they are not ignored
0210:
0211: * in the junit test result. This method must be called from every
0212:
0213: * thread's run() method, if any throwables were throws.
0214:
0215: *
0216:
0217: * @param t the throwable (either from an assertEquals, assertTrue,
0218:
0219: * fail, ... method, or an uncaught exception to be added to the test
0220:
0221: * result of the junit test.
0222:
0223: */
0224:
0225: protected void handleThreadException(final Throwable t)
0226:
0227: {
0228:
0229: synchronized (result_)
0230:
0231: {
0232:
0233: if (t instanceof AssertionFailedError)
0234:
0235: result_.addFailure(this , (AssertionFailedError) t);
0236:
0237: else
0238:
0239: result_.addError(this , t);
0240:
0241: }
0242:
0243: }
0244:
0245: /**
0246:
0247: * Basic tests
0248:
0249: */
0250:
0251: public void testBasics() throws IOException {
0252:
0253: RecordManager recman;
0254:
0255: BTree tree;
0256:
0257: byte[] test, test0, test1, test2, test3;
0258:
0259: byte[] value1, value2;
0260:
0261: test = "test".getBytes();
0262:
0263: test0 = "test0".getBytes();
0264:
0265: test1 = "test1".getBytes();
0266:
0267: test2 = "test2".getBytes();
0268:
0269: test3 = "test3".getBytes();
0270:
0271: value1 = "value1".getBytes();
0272:
0273: value2 = "value2".getBytes();
0274:
0275: if (DEBUG) {
0276:
0277: System.out.println("TestBTree.testBasics");
0278:
0279: }
0280:
0281: recman = RecordManagerFactory.createRecordManager("test");
0282:
0283: tree = BTree.createInstance(recman, new ByteArrayComparator());
0284:
0285: tree.insert(test1, value1, false);
0286:
0287: tree.insert(test2, value2, false);
0288:
0289: byte[] result;
0290:
0291: result = (byte[]) tree.find(test0);
0292:
0293: if (result != null) {
0294:
0295: throw new Error("Test0 shouldn't be found");
0296:
0297: }
0298:
0299: result = (byte[]) tree.find(test1);
0300:
0301: if (result == null
0302: || ByteArrayComparator.compareByteArray(result, value1) != 0) {
0303:
0304: throw new Error("Invalid value for test1: " + result);
0305:
0306: }
0307:
0308: result = (byte[]) tree.find(test2);
0309:
0310: if (result == null
0311: || ByteArrayComparator.compareByteArray(result, value2) != 0) {
0312:
0313: throw new Error("Invalid value for test2: " + result);
0314:
0315: }
0316:
0317: result = (byte[]) tree.find(test3);
0318:
0319: if (result != null) {
0320:
0321: throw new Error("Test3 shouldn't be found");
0322:
0323: }
0324:
0325: recman.close();
0326:
0327: }
0328:
0329: /**
0330:
0331: * Basic tests, just use the simple test possibilities of junit (cdaller)
0332:
0333: */
0334:
0335: public void testBasics2() throws IOException {
0336:
0337: RecordManager recman;
0338:
0339: BTree tree;
0340:
0341: byte[] test, test0, test1, test2, test3;
0342:
0343: byte[] value1, value2;
0344:
0345: test = "test".getBytes();
0346:
0347: test0 = "test0".getBytes();
0348:
0349: test1 = "test1".getBytes();
0350:
0351: test2 = "test2".getBytes();
0352:
0353: test3 = "test3".getBytes();
0354:
0355: value1 = "value1".getBytes();
0356:
0357: value2 = "value2".getBytes();
0358:
0359: if (DEBUG)
0360:
0361: System.out.println("TestBTree.testBasics2");
0362:
0363: recman = RecordManagerFactory.createRecordManager("test");
0364:
0365: tree = BTree.createInstance(recman, new ByteArrayComparator());
0366:
0367: tree.insert(test1, value1, false);
0368:
0369: tree.insert(test2, value2, false);
0370:
0371: assertEquals(null, tree.find(test0));
0372:
0373: assertEquals(0, ByteArrayComparator.compareByteArray(value1,
0374: (byte[]) tree.find(test1)));
0375:
0376: assertEquals(0, ByteArrayComparator.compareByteArray(value2,
0377: (byte[]) tree.find(test2)));
0378:
0379: assertEquals(null, (byte[]) tree.find(test3));
0380:
0381: recman.close();
0382:
0383: }
0384:
0385: /**
0386:
0387: * Test what happens after the recmanager has been closed but the
0388:
0389: * btree is accessed. WHAT SHOULD HAPPEN???????????
0390:
0391: * (cdaller)
0392:
0393: */
0394:
0395: public void testClose()
0396:
0397: throws IOException
0398:
0399: {
0400:
0401: RecordManager recman;
0402:
0403: BTree tree;
0404:
0405: byte[] test, test0, test1, test2, test3;
0406:
0407: byte[] value1, value2;
0408:
0409: test = "test".getBytes();
0410:
0411: test0 = "test0".getBytes();
0412:
0413: test1 = "test1".getBytes();
0414:
0415: test2 = "test2".getBytes();
0416:
0417: test3 = "test3".getBytes();
0418:
0419: value1 = "value1".getBytes();
0420:
0421: value2 = "value2".getBytes();
0422:
0423: if (DEBUG)
0424:
0425: System.out.println("TestBTree.testClose");
0426:
0427: recman = RecordManagerFactory.createRecordManager("test");
0428:
0429: tree = BTree.createInstance(recman, new ByteArrayComparator());
0430:
0431: tree.insert(test1, value1, false);
0432:
0433: tree.insert(test2, value2, false);
0434:
0435: assertEquals(null, tree.find(test0));
0436:
0437: assertEquals(0, ByteArrayComparator.compareByteArray(value1,
0438: (byte[]) tree.find(test1)));
0439:
0440: assertEquals(0, ByteArrayComparator.compareByteArray(value2,
0441: (byte[]) tree.find(test2)));
0442:
0443: assertEquals(null, (byte[]) tree.find(test3));
0444:
0445: recman.close();
0446:
0447: try {
0448:
0449: tree.browse();
0450:
0451: fail("Should throw an IllegalStateException on access on not opened btree");
0452:
0453: } catch (IllegalStateException except) {
0454:
0455: // ignore
0456:
0457: }
0458:
0459: try {
0460:
0461: tree.find(test0);
0462:
0463: fail("Should throw an IllegalStateException on access on not opened btree");
0464:
0465: } catch (IllegalStateException except) {
0466:
0467: // ignore
0468:
0469: }
0470:
0471: try {
0472:
0473: tree.findGreaterOrEqual(test0);
0474:
0475: fail("Should throw an IllegalStateException on access on not opened btree");
0476:
0477: } catch (IllegalStateException except) {
0478:
0479: // ignore
0480:
0481: }
0482:
0483: try {
0484:
0485: tree.insert(test2, value2, false);
0486:
0487: fail("Should throw an IllegalStateException on access on not opened btree");
0488:
0489: } catch (IllegalStateException except) {
0490:
0491: // ignore
0492:
0493: }
0494:
0495: try {
0496:
0497: tree.remove(test0);
0498:
0499: fail("Should throw an IllegalStateException on access on not opened btree");
0500:
0501: } catch (IllegalStateException except) {
0502:
0503: // ignore
0504:
0505: }
0506:
0507: /*
0508:
0509: try {
0510:
0511: tree.size();
0512:
0513: fail( "Should throw an IllegalStateException on access on not opened btree" );
0514:
0515: } catch( IllegalStateException except ) {
0516:
0517: // ignore
0518:
0519: }
0520:
0521: */
0522:
0523: }
0524:
0525: /**
0526:
0527: * Test to insert different objects into one btree. (cdaller)
0528:
0529: */
0530:
0531: public void testInsert()
0532:
0533: throws IOException
0534:
0535: {
0536:
0537: RecordManager recman;
0538:
0539: BTree tree;
0540:
0541: if (DEBUG)
0542:
0543: System.out.println("TestBTree.testInsert");
0544:
0545: recman = RecordManagerFactory.createRecordManager("test");
0546:
0547: tree = BTree.createInstance(recman, new StringComparator());
0548:
0549: // insert differnt objects and retrieve them
0550:
0551: tree.insert("test1", "value1", false);
0552:
0553: tree.insert("test2", "value2", false);
0554:
0555: tree.insert("one", new Integer(1), false);
0556:
0557: tree.insert("two", new Long(2), false);
0558:
0559: tree.insert("myownobject", new TestObject(new Integer(234)),
0560: false);
0561:
0562: assertEquals("value2", (String) tree.find("test2"));
0563:
0564: assertEquals("value1", (String) tree.find("test1"));
0565:
0566: assertEquals(new Integer(1), (Integer) tree.find("one"));
0567:
0568: assertEquals(new Long(2), (Long) tree.find("two"));
0569:
0570: // what happens here? must not be replaced, does it return anything?
0571:
0572: // probably yes!
0573:
0574: assertEquals("value1", tree.insert("test1", "value11", false));
0575:
0576: assertEquals("value1", tree.find("test1")); // still the old value?
0577:
0578: assertEquals("value1", tree.insert("test1", "value11", true));
0579:
0580: assertEquals("value11", tree.find("test1")); // now the new value!
0581:
0582: TestObject expected_obj = new TestObject(new Integer(234));
0583:
0584: TestObject btree_obj = (TestObject) tree.find("myownobject");
0585:
0586: assertEquals(expected_obj, btree_obj);
0587:
0588: recman.close();
0589:
0590: }
0591:
0592: /**
0593:
0594: * Test to remove objects from the btree. (cdaller)
0595:
0596: */
0597:
0598: public void testRemove()
0599:
0600: throws IOException
0601:
0602: {
0603:
0604: RecordManager recman;
0605:
0606: BTree tree;
0607:
0608: if (DEBUG) {
0609:
0610: System.out.println("TestBTree.testRemove");
0611:
0612: }
0613:
0614: recman = RecordManagerFactory.createRecordManager("test");
0615:
0616: tree = BTree.createInstance(recman, new StringComparator());
0617:
0618: tree.insert("test1", "value1", false);
0619:
0620: tree.insert("test2", "value2", false);
0621:
0622: assertEquals("value1", (String) tree.find("test1"));
0623:
0624: assertEquals("value2", (String) tree.find("test2"));
0625:
0626: tree.remove("test1");
0627:
0628: assertEquals(null, (String) tree.find("test1"));
0629:
0630: assertEquals("value2", (String) tree.find("test2"));
0631:
0632: tree.remove("test2");
0633:
0634: assertEquals(null, (String) tree.find("test2"));
0635:
0636: int iterations = 1000;
0637:
0638: for (int count = 0; count < iterations; count++) {
0639:
0640: tree.insert("num" + count, new Integer(count), false);
0641:
0642: }
0643:
0644: assertEquals(iterations, tree.size());
0645:
0646: for (int count = 0; count < iterations; count++) {
0647:
0648: assertEquals(new Integer(count), tree.find("num" + count));
0649:
0650: }
0651:
0652: for (int count = 0; count < iterations; count++) {
0653:
0654: tree.remove("num" + count);
0655:
0656: }
0657:
0658: assertEquals(0, tree.size());
0659:
0660: recman.close();
0661:
0662: }
0663:
0664: /**
0665:
0666: * Test to find differents objects in the btree. (cdaller)
0667:
0668: */
0669:
0670: public void testFind()
0671:
0672: throws IOException
0673:
0674: {
0675:
0676: RecordManager recman;
0677:
0678: BTree tree;
0679:
0680: if (DEBUG)
0681:
0682: System.out.println("TestBTree.testFind");
0683:
0684: recman = RecordManagerFactory.createRecordManager("test");
0685:
0686: tree = BTree.createInstance(recman, new StringComparator());
0687:
0688: tree.insert("test1", "value1", false);
0689:
0690: tree.insert("test2", "value2", false);
0691:
0692: Object value = tree.find("test1");
0693:
0694: assertTrue(value instanceof String);
0695:
0696: assertEquals("value1", value);
0697:
0698: tree.insert("", "Empty String as key", false);
0699:
0700: assertEquals("Empty String as key", (String) tree.find(""));
0701:
0702: assertEquals(null, (String) tree.find("someoneelse"));
0703:
0704: recman.close();
0705:
0706: }
0707:
0708: /**
0709:
0710: * Test to insert, retrieve and remove a large amount of data. (cdaller)
0711:
0712: */
0713:
0714: public void testLargeDataAmount()
0715:
0716: throws IOException
0717:
0718: {
0719:
0720: RecordManager recman;
0721:
0722: BTree tree;
0723:
0724: if (DEBUG)
0725:
0726: System.out.println("TestBTree.testLargeDataAmount");
0727:
0728: recman = RecordManagerFactory.createRecordManager("test");
0729:
0730: // recman = new jdbm.recman.BaseRecordManager( "test" );
0731:
0732: tree = BTree.createInstance(recman, new StringComparator());
0733:
0734: // tree.setSplitPoint( 4 );
0735:
0736: int iterations = 10000;
0737:
0738: // insert data
0739:
0740: for (int count = 0; count < iterations; count++) {
0741:
0742: try {
0743:
0744: assertEquals(null, tree.insert("num" + count,
0745: new Integer(count), false));
0746:
0747: } catch (IOException except) {
0748:
0749: except.printStackTrace();
0750:
0751: throw except;
0752:
0753: }
0754:
0755: }
0756:
0757: // find data
0758:
0759: for (int count = 0; count < iterations; count++)
0760:
0761: {
0762:
0763: assertEquals(new Integer(count), tree.find("num" + count));
0764:
0765: }
0766:
0767: // delete data
0768:
0769: for (int count = 0; count < iterations; count++)
0770:
0771: {
0772:
0773: assertEquals(new Integer(count), tree.remove("num" + count));
0774:
0775: }
0776:
0777: assertEquals(0, tree.size());
0778:
0779: recman.close();
0780:
0781: }
0782:
0783: /**
0784:
0785: * Test access from multiple threads. Assertions only work, when the
0786:
0787: * run() method is overridden and the exceptions of the threads are
0788:
0789: * added to the resultset of the TestCase. see run() and
0790:
0791: * handleException().
0792:
0793: */
0794:
0795: public void testMultithreadAccess()
0796:
0797: throws IOException
0798:
0799: {
0800:
0801: RecordManager recman;
0802:
0803: BTree tree;
0804:
0805: if (DEBUG)
0806:
0807: System.out.println("TestBTree.testMultithreadAccess");
0808:
0809: recman = RecordManagerFactory.createRecordManager("test");
0810:
0811: tree = BTree.createInstance(recman, new StringComparator());
0812:
0813: TestThread[] thread_pool = new TestThread[THREAD_NUMBER];
0814:
0815: String name;
0816:
0817: Map content;
0818:
0819: // create content for the tree, different content for different threads!
0820:
0821: for (int thread_count = 0; thread_count < THREAD_NUMBER; thread_count++) {
0822:
0823: name = "thread" + thread_count;
0824:
0825: content = new TreeMap();
0826:
0827: for (int content_count = 0; content_count < THREAD_CONTENT_SIZE; content_count++) {
0828:
0829: // guarantee, that keys and values do not overleap,
0830:
0831: // otherwise one thread removes some keys/values of
0832:
0833: // other threads!
0834:
0835: content.put(name + "_" + content_count,
0836:
0837: new Integer(thread_count * THREAD_CONTENT_SIZE
0838: + content_count));
0839:
0840: }
0841:
0842: thread_pool[thread_count] = new TestThread(name, tree,
0843: content);
0844:
0845: thread_pool[thread_count].start();
0846:
0847: }
0848:
0849: try {
0850:
0851: Thread.sleep(THREAD_RUNTIME);
0852:
0853: } catch (InterruptedException ignore) {
0854:
0855: ignore.printStackTrace();
0856:
0857: }
0858:
0859: // stop threads:
0860:
0861: for (int thread_count = 0; thread_count < THREAD_NUMBER; thread_count++) {
0862:
0863: if (DEBUG)
0864: System.out.println("Stop threads");
0865:
0866: thread_pool[thread_count].setStop();
0867:
0868: }
0869:
0870: // wait until the threads really stop:
0871:
0872: try {
0873:
0874: for (int thread_count = 0; thread_count < THREAD_NUMBER; thread_count++) {
0875:
0876: if (DEBUG)
0877: System.out.println("Join thread " + thread_count);
0878:
0879: thread_pool[thread_count].join();
0880:
0881: if (DEBUG)
0882: System.out.println("Joined thread " + thread_count);
0883:
0884: }
0885:
0886: } catch (InterruptedException ignore) {
0887:
0888: ignore.printStackTrace();
0889:
0890: }
0891:
0892: recman.close();
0893:
0894: }
0895:
0896: /**
0897:
0898: * Helper method to 'simulate' the methods of an entry set of the btree.
0899:
0900: */
0901:
0902: protected static boolean containsKey(Object key, BTree btree)
0903:
0904: throws IOException
0905:
0906: {
0907:
0908: return (btree.find(key) != null);
0909:
0910: }
0911:
0912: /**
0913:
0914: * Helper method to 'simulate' the methods of an entry set of the btree.
0915:
0916: */
0917:
0918: protected static boolean containsValue(Object value, BTree btree)
0919:
0920: throws IOException
0921:
0922: {
0923:
0924: // we must synchronize on the BTree while browsing
0925:
0926: synchronized (btree) {
0927:
0928: TupleBrowser browser = btree.browse();
0929:
0930: Tuple tuple = new Tuple();
0931:
0932: while (browser.getNext(tuple)) {
0933:
0934: if (tuple.getValue().equals(value))
0935:
0936: return (true);
0937:
0938: }
0939:
0940: }
0941:
0942: // System.out.println("Comparation of '"+value+"' with '"+ tuple.getValue()+"' FAILED");
0943:
0944: return (false);
0945:
0946: }
0947:
0948: /**
0949:
0950: * Helper method to 'simulate' the methods of an entry set of the btree.
0951:
0952: */
0953:
0954: protected static boolean contains(Map.Entry entry, BTree btree)
0955:
0956: throws IOException
0957:
0958: {
0959:
0960: Object tree_obj = btree.find(entry.getKey());
0961:
0962: if (tree_obj == null) {
0963:
0964: // can't distuingish, if value is null or not found!!!!!!
0965:
0966: return (entry.getValue() == null);
0967:
0968: }
0969:
0970: return (tree_obj.equals(entry.getValue()));
0971:
0972: }
0973:
0974: /**
0975:
0976: * Runs all tests in this class
0977:
0978: */
0979:
0980: public static void main(String[] args) {
0981:
0982: junit.textui.TestRunner.run(new TestSuite(TestBTree.class));
0983:
0984: }
0985:
0986: /**
0987:
0988: * Inner class for testing puroposes only (multithreaded access)
0989:
0990: */
0991:
0992: class TestThread
0993:
0994: extends Thread
0995:
0996: {
0997:
0998: Map _content;
0999:
1000: BTree _btree;
1001:
1002: volatile boolean _continue = true;
1003:
1004: int THREAD_SLEEP_TIME = 50; // in ms
1005:
1006: String _name;
1007:
1008: TestThread(String name, BTree btree, Map content)
1009:
1010: {
1011:
1012: _content = content;
1013:
1014: _btree = btree;
1015:
1016: _name = name;
1017:
1018: }
1019:
1020: public void setStop()
1021:
1022: {
1023:
1024: _continue = false;
1025:
1026: }
1027:
1028: private void action()
1029:
1030: throws IOException
1031:
1032: {
1033:
1034: Iterator iterator = _content.entrySet().iterator();
1035:
1036: Map.Entry entry;
1037:
1038: if (DEBUG) {
1039:
1040: System.out.println("Thread " + _name + ": fill btree.");
1041:
1042: }
1043:
1044: while (iterator.hasNext()) {
1045:
1046: entry = (Map.Entry) iterator.next();
1047:
1048: assertEquals(null, _btree.insert(entry.getKey(), entry
1049: .getValue(), false));
1050:
1051: }
1052:
1053: // as other threads are filling the btree as well, the size
1054:
1055: // of the btree is unknown (but must be at least the size of
1056:
1057: // the content map)
1058:
1059: assertTrue(_content.size() <= _btree.size());
1060:
1061: iterator = _content.entrySet().iterator();
1062:
1063: if (DEBUG) {
1064:
1065: System.out.println("Thread " + _name
1066: + ": iterates btree.");
1067:
1068: }
1069:
1070: while (iterator.hasNext()) {
1071:
1072: entry = (Map.Entry) iterator.next();
1073:
1074: assertEquals(entry.getValue(), _btree.find(entry
1075: .getKey()));
1076:
1077: assertTrue(contains(entry, _btree));
1078:
1079: assertTrue(containsKey(entry.getKey(), _btree));
1080:
1081: assertTrue(containsValue(entry.getValue(), _btree));
1082:
1083: }
1084:
1085: iterator = _content.entrySet().iterator();
1086:
1087: Object key;
1088:
1089: if (DEBUG) {
1090:
1091: System.out.println("Thread " + _name
1092: + ": removes his elements from the btree.");
1093:
1094: }
1095:
1096: while (iterator.hasNext()) {
1097:
1098: key = ((Map.Entry) iterator.next()).getKey();
1099:
1100: _btree.remove(key);
1101:
1102: assertTrue(!containsKey(key, _btree));
1103:
1104: }
1105:
1106: }
1107:
1108: public void run()
1109:
1110: {
1111:
1112: if (DEBUG)
1113:
1114: System.out.println("Thread " + _name + ": started.");
1115:
1116: try {
1117:
1118: while (_continue) {
1119:
1120: action();
1121:
1122: try {
1123:
1124: Thread.sleep(THREAD_SLEEP_TIME);
1125:
1126: } catch (InterruptedException except) {
1127:
1128: except.printStackTrace();
1129:
1130: }
1131:
1132: }
1133:
1134: } catch (Throwable t) {
1135:
1136: if (DEBUG) {
1137:
1138: System.err.println("Thread " + _name
1139: + " threw an exception:");
1140:
1141: t.printStackTrace();
1142:
1143: }
1144:
1145: handleThreadException(t);
1146:
1147: }
1148:
1149: if (DEBUG)
1150:
1151: System.out.println("Thread " + _name + ": stopped.");
1152:
1153: }
1154:
1155: } // end of class TestThread
1156:
1157: }
1158:
1159: /**
1160:
1161: * class for testing puroposes only (store as value in btree) not
1162:
1163: * implemented as inner class, as this prevents Serialization if
1164:
1165: * outer class is not Serializable.
1166:
1167: */
1168:
1169: class TestObject
1170:
1171: implements Serializable
1172:
1173: {
1174:
1175: Object _content;
1176:
1177: private TestObject()
1178:
1179: {
1180:
1181: // empty
1182:
1183: }
1184:
1185: public TestObject(Object content)
1186:
1187: {
1188:
1189: _content = content;
1190:
1191: }
1192:
1193: Object getContent()
1194:
1195: {
1196:
1197: return _content;
1198:
1199: }
1200:
1201: public boolean equals(Object obj)
1202:
1203: {
1204:
1205: if (!(obj instanceof TestObject)) {
1206:
1207: return false;
1208:
1209: }
1210:
1211: return _content.equals(((TestObject) obj).getContent());
1212:
1213: }
1214:
1215: public String toString()
1216:
1217: {
1218:
1219: return ("TestObject {content='" + _content + "'}");
1220:
1221: }
1222:
1223: } // TestObject
|