/*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* 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.
*
* The Original Code is the Kowari Metadata Store.
*
* The Initial Developer of the Original Code is Plugged In Software Pty
* Ltd (http://www.pisoftware.com, mailto:info@pisoftware.com). Portions
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
* Contributor(s): N/A.
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
* should use the text of this Exhibit A rather than the text found in the
* Original Code Source Code for Your Modifications.]
*
*/
package org.mulgara.store.stringpool;
// Java 2 standard packages
import java.io.*;
import java.util.*;
import java.util.zip.*;
// third party packages
import junit.framework.*;
import org.mulgara.store.nodepool.NodePool;
import org.mulgara.store.stringpool.SPObject;
import org.mulgara.store.xa.XAStringPool;
/**
* Test case for {@link StringPool} implementations.
*
* @created 2001-10-05
*
* @author <a href="http://staff.pisoftware.com/mike">Michael Judd</a>
*
* @version $Revision: 1.1 $
*
* @modified $Date: 2005/02/20 10:26:19 $ by $Author: newmana $
*
* @maintenanceAuthor $Author: newmana $
*
* @copyright ©2001-2003
* <a href="http://www.pisoftware.com/">Plugged In Software Pty Ltd</a>
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
public class StringPoolLoadTest extends TestCase {
/** Get line separator. */
private static final String eol = System.getProperty("line.separator");
/** List of stored node/string pairs */
protected static List<StringPoolTestEntry> testEntries;
/** Subclasses must initialize this string pool field. */
protected XAStringPool stringPool;
/** Subclasses must initialize this factory for creating string pool objects. */
protected SPObjectFactory spoFactory;
/** Reads in test data from file */
protected BufferedReader reader;
/** maximum number of entries */
protected int maxSize = 3000000;
/** the number of queries to be made */
protected int noQueries = 3000;
/** the file containing test data */
protected String dataFile = "data/testwords.txt.gz";
/** This flag indicates data should be written to the string pool when it is read */
protected boolean loadData = true;
// these are using for thread testing (testThirdQuery)
/** Query counter */
private int numberOfQueries = 0;
/** Random number generator */
private Random random;
/**
* Constructor for the test object.
* @param name Name of this test.
*/
public StringPoolLoadTest(String name) {
super(name);
}
/**
* Hook for test runner to obtain an empty test suite from, because this test
* can't be run (it's abstract). This must be overridden in subclasses.
* @return The test suite
*/
public static Test suite() {
TestSuite suite = new TestSuite();
return suite;
}
/**
* Default text runner.
* @param args The command line arguments
*/
public static void main(SPString[] args) {
junit.textui.TestRunner.run(suite());
}
/**
* Reads in all (or a subset determined by maxSize) of the dataset. The total
* data has approximately 3 million literals.
*/
public void testLoadStringPool() throws Exception {
// adjust noQueries if the maxSize is less than it
noQueries = (maxSize < noQueries) ? maxSize : noQueries;
// create the array of test entries
testEntries = new ArrayList<StringPoolTestEntry>();
String line = reader.readLine();
int count = 1;
int gapSize = maxSize / noQueries;
long start = System.currentTimeMillis();
while ((line != null) && (count < maxSize)) {
SPObject spObject = spoFactory.newSPString(line);
if (loadData) stringPool.put(count, spObject);
if ((count % gapSize) == 0) testEntries.add(new StringPoolTestEntry(count, spObject));
line = reader.readLine();
count++;
}
System.out.println(String.format("Loaded %d statements in %fsec", count, (System.currentTimeMillis() - start) / 1000.0));
}
/**
* Go through the test entries and find graph node by passing in the SPObject
* and assert the returned integer equals the original
*/
public void testFirstQuery() throws Exception {
for (int i = 0; i < testEntries.size(); i++) {
StringPoolTestEntry entry = (StringPoolTestEntry) testEntries.get(i);
long gNode = stringPool.findGNode(entry.spObject);
assertTrue("StringPool.findGNode returned NONE for gNode/spObject: " + entry.gNode + "/" + entry.spObject,
gNode != NodePool.NONE);
assertTrue("The graph node found for the SPObject " + entry.spObject + " was incorrect. Expected " + entry.gNode + " but found " + gNode,
gNode == entry.gNode);
}
}
/**
* Go through the test entries and find string by passing in the node and
* assert the returned string equals the original
*/
public void testSecondQuery() throws Exception {
for (int i = 0; i < testEntries.size(); i++) {
StringPoolTestEntry entry = (StringPoolTestEntry)testEntries.get(i);
SPObject spObject = stringPool.findSPObject(entry.gNode);
assertTrue("StringPool.findSPObject returned null for gNode/spObject: " + entry.gNode + "/" + entry.spObject,
spObject != null);
assertTrue("The SPObject found for the graph node " + entry.gNode + " was incorrect. Expected " + entry.spObject + " but found " + spObject,
spObject.equals(entry.spObject));
}
}
/**
* This query will test threading capabilities of the string pool.
*/
public void testThirdQuery() throws Exception {
int numberOfThreads = 10;
numberOfQueries = 0;
ThreadGroup testGroup = new ThreadGroup("testThirdQuery");
System.out.print(eol + "Starting StringPoolLoadTest query threads...>");
for (int threadCount = 0; threadCount < numberOfThreads; threadCount++) {
TestThirdThread thread = new TestThirdThread(testGroup, threadCount, this, testEntries);
thread.start();
}
// Wait for the all the threads to stop.
Thread.sleep(70 * 1000);
System.out.println(eol + "Total number of queries performed in 60 " +
"seconds with " + numberOfThreads + " threads is :" + numberOfQueries);
}
/**
* Adds a feature to the NumberOfQueries attribute of the StringPoolLoadTest object
* @param numberOfQueries The feature to be added to the NumberOfQueries attribute
*/
public void addNumberOfQueries(int numberOfQueries) {
this.numberOfQueries += numberOfQueries;
}
/**
* get the BufferedReader ready for action
*/
protected void setUp() throws Exception {
random = new Random(System.currentTimeMillis());
GZIPInputStream gzipStream = new GZIPInputStream(new FileInputStream(dataFile));
DataInputStream inStream = new DataInputStream(gzipStream);
reader = new BufferedReader(new InputStreamReader(inStream));
}
/**
* The teardown method for JUnit
*/
protected void tearDown() throws Exception {
if (stringPool != null) stringPool.close();
}
class TestThirdThread extends Thread {
private int numberOfStringPoolQueries = 0;
private int threadNumber = 0;
private StringPoolLoadTest parentTest = null;
private List<StringPoolTestEntry> entries;
/**
* Constructs this thread's dta structure.
* @param group The group for this thread.
* @param threadNumber The id for this thread.
* @param parentTest The test object that owns this object.
* @param entries The data to query for.
*/
public TestThirdThread(ThreadGroup group, int threadNumber,
StringPoolLoadTest parentTest, List<StringPoolTestEntry> entries) {
super(group, "Thread number :" + String.valueOf(threadNumber));
this.threadNumber = threadNumber;
numberOfStringPoolQueries = 0;
this.parentTest = parentTest;
this.entries = entries;
}
public void run() {
try {
boolean stopQueries = false;
int i;
System.out.print(String.valueOf(threadNumber) + "..>");
long endTime = System.currentTimeMillis() + (60 * 1000);
while (!stopQueries) {
i = Math.abs(random.nextInt()) % testEntries.size();
StringPoolTestEntry entry = entries.get(i);
long gNode = stringPool.findGNode(entry.spObject);
assertTrue("StringPool.findGNode returned NONE for gNode/spObject: " + entry.gNode + "/" + entry.spObject,
gNode != NodePool.NONE);
assertTrue("The graph node found for the SPObject " + entry.spObject + " was incorrect. Expected " + entry.gNode + " but found " + gNode,
gNode == entry.gNode);
i = Math.abs(random.nextInt()) % testEntries.size();
entry = entries.get(i);
SPObject spObject = stringPool.findSPObject(entry.gNode);
assertTrue("StringPool.findSPObject returned null for node/SPObject: " + entry.gNode + "/" + entry.spObject,
spObject != null);
assertTrue("The spObject found for the node " + entry.gNode + " was incorrect. Expected " + entry.spObject + " but found " + spObject,
spObject.equals(entry.spObject));
numberOfStringPoolQueries++;
if (System.currentTimeMillis() > endTime) {
stopQueries = true;
break;
}
}
System.out.print("<..." + String.valueOf(threadNumber));
parentTest.addNumberOfQueries(numberOfStringPoolQueries);
} catch (StringPoolException spe) {
System.out.println("string pool exception during multithreading query");
}
}
}
/**
* this class is just a structure to store the node/string pair
*/
static protected class StringPoolTestEntry {
/** The node associated with the data. */
public int gNode;
/** The stored data. */
public SPObject spObject;
/**
* Constructor.
* @param gNode The node for this data
* @param spObject The data for this node
*/
public StringPoolTestEntry(int gNode, SPObject spObject) {
this.gNode = gNode;
this.spObject = spObject;
}
}
}