You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by mi...@apache.org on 2005/03/17 03:35:54 UTC
svn commit: r157861 [2/2] - in incubator/derby/code/trunk: ./
java/engine/org/apache/derby/iapi/sql/compile/
java/engine/org/apache/derby/iapi/store/access/
java/engine/org/apache/derby/impl/sql/compile/
java/engine/org/apache/derby/impl/sql/execute/
java/engine/org/apache/derby/impl/store/access/
java/testing/org/apache/derbyTesting/functionTests/master/
java/testing/org/apache/derbyTesting/functionTests/suites/
java/testing/org/apache/derbyTesting/functionTests/tests/lang/
java/testing/org/apache/derbyTesting/functionTests/tests/store/
Added: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/TestDiskHashtable.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/TestDiskHashtable.java?view=auto&rev=157861
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/TestDiskHashtable.java (added)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/store/TestDiskHashtable.java Wed Mar 16 18:35:44 2005
@@ -0,0 +1,432 @@
+/*
+
+ Derby - Class org.apache.derbyTesting.functionTests.tests.store.TestDiskHashtable
+
+ Copyright 2005 The Apache Software Foundation or its licensors, as applicable.
+
+ Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+
+package org.apache.derbyTesting.functionTests.tests.store;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import java.util.BitSet;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Vector;
+
+import org.apache.derby.iapi.error.PublicAPI;
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.sql.conn.ConnectionUtil;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.store.access.DiskHashtable;
+import org.apache.derby.iapi.store.access.KeyHasher;
+import org.apache.derby.iapi.store.access.TransactionController;
+import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.iapi.types.Orderable;
+import org.apache.derby.iapi.types.SQLInteger;
+import org.apache.derby.iapi.types.SQLLongint;
+import org.apache.derby.iapi.types.SQLVarchar;
+import org.apache.derby.tools.ij;
+import org.apache.derbyTesting.functionTests.util.TestUtil;
+
+/**
+ * This program tests the org.apache.derby.iapi.store.access.DiskHashtable class.
+ * The unit test interface is not used because that is undocumented and very difficult to decipher.
+ * Furthermore it is difficult to diagnose problems when using the unit test interface.
+ *
+ * Created: Wed Feb 09 15:44:12 2005
+ *
+ * @author <a href="mailto:klebanof@us.ibm.com">Jack Klebanoff</a>
+ * @version 1.0
+ */
+public class TestDiskHashtable
+{
+ private TransactionController tc;
+ private int failed = 0;
+
+ public static void main( String args[])
+ {
+ int failed = 1;
+
+ REPORT("Test DiskHashtable starting");
+ try
+ {
+ // use the ij utility to read the property file and
+ // make the initial connection.
+ ij.getPropertyArg(args);
+ Connection conn = ij.startJBMS();
+ Statement stmt = conn.createStatement();
+ stmt.execute("CREATE FUNCTION testDiskHashtable() returns INTEGER EXTERNAL NAME 'org.apache.derbyTesting.functionTests.tests.store.TestDiskHashtable.runTests' LANGUAGE JAVA PARAMETER STYLE JAVA");
+ ResultSet rs = stmt.executeQuery( "values( testDiskHashtable())");
+ if( rs.next())
+ failed = rs.getInt(1);
+ stmt.close();
+ conn.close();
+ }
+ catch( SQLException e)
+ {
+ TestUtil.dumpSQLExceptions( e);
+ failed = 1;
+ }
+ catch( Throwable t)
+ {
+ REPORT("FAIL -- unexpected exception:" + t.toString());
+ failed = 1;
+ }
+ REPORT( (failed == 0) ? "OK" : "FAILED");
+ System.exit( (failed == 0) ? 0 : 1);
+ }
+
+ private void REPORT_FAILURE(String msg)
+ {
+ failed = 1;
+ REPORT( msg);
+ }
+
+ private static void REPORT(String msg)
+ {
+ System.out.println( msg);
+ }
+
+ public static int runTests() throws SQLException
+ {
+ TestDiskHashtable tester = new TestDiskHashtable();
+ return tester.doIt();
+ }
+
+ private TestDiskHashtable() throws SQLException
+ {
+ LanguageConnectionContext lcc = ConnectionUtil.getCurrentLCC();
+ if( lcc == null)
+ throw new SQLException( "Cannot get the LCC");
+ tc = lcc.getTransactionExecute();
+ }
+
+ private int doIt() throws SQLException
+ {
+ try {
+
+
+ REPORT( "Starting single key, keep duplicates test");
+ testOneVariant( tc, false, singleKeyTemplate, singleKeyCols, singleKeyRows);
+ REPORT( "Starting single key, remove duplicates test");
+ testOneVariant( tc, true, singleKeyTemplate, singleKeyCols, singleKeyRows);
+ REPORT( "Starting multiple key, keep duplicates test");
+ testOneVariant( tc, false, multiKeyTemplate, multiKeyCols, multiKeyRows);
+ REPORT( "Starting multiple key, remove duplicates test");
+ testOneVariant( tc, true, multiKeyTemplate, multiKeyCols, multiKeyRows);
+
+ tc.commit();
+ }
+ catch (StandardException se)
+ {
+ throw PublicAPI.wrapStandardException( se);
+ }
+ return failed;
+ } // end of doIt
+
+ private static final DataValueDescriptor[] singleKeyTemplate = { new SQLInteger(), new SQLVarchar()};
+ private static final int[] singleKeyCols = {0};
+ private static final DataValueDescriptor[][] singleKeyRows =
+ {
+ {new SQLInteger(1), new SQLVarchar("abcd")},
+ {new SQLInteger(2), new SQLVarchar("abcd")},
+ {new SQLInteger(3), new SQLVarchar("e")},
+ {new SQLInteger(1), new SQLVarchar("zz")}
+ };
+
+ private static final DataValueDescriptor[] multiKeyTemplate = { new SQLLongint(), new SQLVarchar(), new SQLInteger()};
+ private static final int[] multiKeyCols = {1, 0};
+ private static final DataValueDescriptor[][] multiKeyRows =
+ {
+ {new SQLLongint(1), new SQLVarchar( "aa"), multiKeyTemplate[2].getNewNull()},
+ {new SQLLongint(2), new SQLVarchar( "aa"), new SQLInteger(1)},
+ {new SQLLongint(2), new SQLVarchar( "aa"), new SQLInteger(2)},
+ {new SQLLongint(2), new SQLVarchar( "b"), new SQLInteger(1)}
+ };
+
+ private static final int LOTS_OF_ROWS_COUNT = 50000;
+
+ private void testOneVariant( TransactionController tc,
+ boolean removeDups,
+ DataValueDescriptor[] template,
+ int[] keyCols,
+ DataValueDescriptor[][] rows)
+ throws StandardException
+ {
+ DiskHashtable dht = new DiskHashtable(tc, template, keyCols, removeDups, false);
+ boolean[] isDuplicate = new boolean[ rows.length];
+ boolean[] found = new boolean[ rows.length];
+ HashMap simpleHash = new HashMap( rows.length);
+
+ testElements( removeDups, dht, keyCols, 0, rows, simpleHash, isDuplicate, found);
+
+ for( int i = 0; i < rows.length; i++)
+ {
+ Object key = KeyHasher.buildHashKey( rows[i], keyCols);
+ Vector al = (Vector) simpleHash.get( key);
+ isDuplicate[i] = (al != null);
+ if( al == null)
+ {
+ al = new Vector(4);
+ simpleHash.put( key, al);
+ }
+ if( (!removeDups) || !isDuplicate[i])
+ al.add( rows[i]);
+
+ if( dht.put( key, rows[i]) != (removeDups ? (!isDuplicate[i]) : true))
+ REPORT_FAILURE( " put returned wrong value on row " + i);
+
+ for( int j = 0; j <= i; j++)
+ {
+ key = KeyHasher.buildHashKey( rows[j], keyCols);
+ if( ! rowsEqual( dht.get( key), simpleHash.get( key)))
+ REPORT_FAILURE( " get returned wrong value on key " + j);
+ }
+
+ testElements( removeDups, dht, keyCols, i+1, rows, simpleHash, isDuplicate, found);
+ }
+ // Remove them
+ for( int i = 0; i < rows.length; i++)
+ {
+ Object key = KeyHasher.buildHashKey( rows[i], keyCols);
+ if( ! rowsEqual( dht.remove( key), simpleHash.get( key)))
+ REPORT_FAILURE( " remove returned wrong value on key " + i);
+ simpleHash.remove( key);
+ if( dht.get( key) != null)
+ REPORT_FAILURE( " remove did not delete key " + i);
+ }
+ testElements( removeDups, dht, keyCols, 0, rows, simpleHash, isDuplicate, found);
+
+ testLargeTable( dht, keyCols, rows[0]);
+ dht.close();
+ } // end of testOneVariant
+
+ private void testLargeTable( DiskHashtable dht,
+ int[] keyCols,
+ DataValueDescriptor[] aRow)
+ throws StandardException
+ {
+ // Add a lot of elements
+ // If there are two or more key columns then we will vary the first two key columns, using an approximately
+ // square matrix of integer key values. Because the hash generator is commutative key (i,j) hashes into the
+ // same bucket as key (j,i), testing the case where different keys hash into the same bucket.
+ int key1Count = (keyCols.length > 1) ? ((int) Math.round( Math.sqrt( (double) LOTS_OF_ROWS_COUNT))) : 1;
+ int key0Count = (LOTS_OF_ROWS_COUNT + key1Count - 1)/key1Count;
+
+ DataValueDescriptor[] row = new DataValueDescriptor[ aRow.length];
+ for( int i = 0; i < row.length; i++)
+ row[i] = aRow[i].getClone();
+
+ for( int key0Idx = 0; key0Idx < key0Count; key0Idx++)
+ {
+ row[ keyCols[0]].setValue( key0Idx);
+ for( int key1Idx = 0; key1Idx < key1Count; key1Idx++)
+ {
+ if( keyCols.length > 1)
+ row[ keyCols[1]].setValue( key1Idx);
+ Object key = KeyHasher.buildHashKey( row, keyCols);
+ if( ! dht.put( key, row))
+ {
+ REPORT_FAILURE( " put returned wrong value for key(" + key0Idx + "," + key1Idx + ")");
+ key0Idx = key0Count;
+ break;
+ }
+ }
+ }
+ for( int key0Idx = 0; key0Idx < key0Count; key0Idx++)
+ {
+ row[ keyCols[0]].setValue( key0Idx);
+ for( int key1Idx = 0; key1Idx < key1Count; key1Idx++)
+ {
+ if( keyCols.length > 1)
+ row[ keyCols[1]].setValue( key1Idx);
+ Object key = KeyHasher.buildHashKey( row, keyCols);
+ if( ! rowsEqual( dht.get( key), row))
+ {
+ REPORT_FAILURE( " large table get returned wrong value for key(" + key0Idx + "," + key1Idx + ")");
+ key0Idx = key0Count;
+ break;
+ }
+ }
+ }
+ BitSet found = new BitSet(key0Count * key1Count);
+ Enumeration elements = dht.elements();
+ while( elements.hasMoreElements())
+ {
+ Object el = elements.nextElement();
+ if( ! (el instanceof DataValueDescriptor[]))
+ {
+ REPORT_FAILURE( " large table enumeration returned wrong element type");
+ break;
+ }
+ DataValueDescriptor[] fetchedRow = (DataValueDescriptor[]) el;
+
+ int i = fetchedRow[ keyCols[0]].getInt() * key1Count;
+ if( keyCols.length > 1)
+ i += fetchedRow[ keyCols[1]].getInt();
+ if( i >= key0Count * key1Count)
+ {
+ REPORT_FAILURE( " large table enumeration returned invalid element");
+ break;
+ }
+
+ if( found.get(i))
+ {
+ REPORT_FAILURE( " large table enumeration returned same element twice");
+ break;
+ }
+ found.set(i);
+ }
+ for( int i = key0Count * key1Count - 1; i >= 0; i--)
+ {
+ if( !found.get(i))
+ {
+ REPORT_FAILURE( " large table enumeration missed at least one element");
+ break;
+ }
+ }
+ } // end of testLargeTable
+
+ private void testElements( boolean removeDups,
+ DiskHashtable dht,
+ int[] keyCols,
+ int rowCount,
+ DataValueDescriptor[][] rows,
+ HashMap simpleHash,
+ boolean[] isDuplicate,
+ boolean[] found)
+ throws StandardException
+ {
+ for( int i = 0; i < rowCount; i++)
+ found[i] = false;
+
+ for( Enumeration e = dht.elements(); e.hasMoreElements();)
+ {
+ Object el = e.nextElement();
+ if( el == null)
+ {
+ REPORT_FAILURE( " table enumeration returned a null element");
+ return;
+ }
+ if( el instanceof DataValueDescriptor[])
+ checkElement( (DataValueDescriptor[]) el, rowCount, rows, found);
+ else if( el instanceof Vector)
+ {
+ Vector v = (Vector) el;
+ for( int i = 0; i < v.size(); i++)
+ checkElement( (DataValueDescriptor[]) v.get(i), rowCount, rows, found);
+ }
+ else if( el == null)
+ {
+ REPORT_FAILURE( " table enumeration returned an incorrect element type");
+ return;
+ }
+ }
+ for( int i = 0; i < rowCount; i++)
+ {
+ if( (removeDups && isDuplicate[i]))
+ {
+ if( found[i])
+ {
+ REPORT_FAILURE( " table enumeration did not remove duplicates");
+ return;
+ }
+ }
+ else if( ! found[i])
+ {
+ REPORT_FAILURE( " table enumeration missed at least one element");
+ return;
+ }
+ }
+ } // end of testElements
+
+ private void checkElement( DataValueDescriptor[] fetchedRow,
+ int rowCount,
+ DataValueDescriptor[][] rows,
+ boolean[] found)
+ throws StandardException
+ {
+ for( int i = 0; i < rowCount; i++)
+ {
+ if( rowsEqual( fetchedRow, rows[i]))
+ {
+ if( found[i])
+ {
+ REPORT_FAILURE( " table enumeration returned the same element twice");
+ return;
+ }
+ found[i] = true;
+ return;
+ }
+ }
+ REPORT_FAILURE( " table enumeration returned an incorrect element");
+ } // end of checkElement
+
+ private boolean rowsEqual( Object r1, Object r2)
+ throws StandardException
+ {
+ if( r1 == null)
+ return r2 == null;
+
+ if( r1 instanceof DataValueDescriptor[])
+ {
+ DataValueDescriptor[] row1 = (DataValueDescriptor[]) r1;
+ DataValueDescriptor[] row2;
+
+ if( r2 instanceof Vector)
+ {
+ Vector v2 = (Vector) r2;
+ if( v2.size() != 1)
+ return false;
+ row2 = (DataValueDescriptor[]) v2.elementAt(0);
+ }
+ else if( r2 instanceof DataValueDescriptor[])
+ row2 = (DataValueDescriptor[]) r2;
+ else
+ return false;
+
+ if( row1.length != row2.length)
+ return false;
+ for( int i = 0; i < row1.length; i++)
+ {
+ if( ! row1[i].compare( Orderable.ORDER_OP_EQUALS, row2[i], true, true))
+ return false;
+ }
+ return true;
+ }
+ if( r1 instanceof Vector)
+ {
+ if( !(r2 instanceof Vector))
+ return false;
+ Vector v1 = (Vector) r1;
+ Vector v2 = (Vector) r2;
+ if( v1.size() != v2.size())
+ return false;
+ for( int i = v1.size() - 1; i >= 0; i--)
+ {
+ if( ! rowsEqual( v1.elementAt( i), v2.elementAt(i)))
+ return false;
+ }
+ return true;
+ }
+ // What is it then?
+ return r1.equals( r2);
+ } // end of rowsEqual
+}