You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2002/09/02 14:38:29 UTC
cvs commit: jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/test DataSourceJdbcTestCase.java DataSourceJdbcTestCase.xtest
leif 2002/09/02 05:38:29
Modified: datasource build.xml
datasource/src/java/org/apache/avalon/excalibur/datasource/ids
AbstractDataSourceIdGenerator.java
TableIdGenerator.java
datasource/src/test/org/apache/avalon/excalibur/datasource/ids/test
TableIdGeneratorJdbcTestCase.java
datasource/src/test/org/apache/avalon/excalibur/datasource/test
DataSourceJdbcTestCase.java
DataSourceJdbcTestCase.xtest
Log:
Modify the way ids are allocated so that it will work with a wider variety of
databases.
Revision Changes Path
1.29 +4 -0 jakarta-avalon-excalibur/datasource/build.xml
Index: build.xml
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/build.xml,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- build.xml 10 Aug 2002 21:14:34 -0000 1.28
+++ build.xml 2 Sep 2002 12:38:28 -0000 1.29
@@ -14,6 +14,8 @@
<pathelement location="${build.classes}"/>
<pathelement location="${checkstyle.jar}"/>
<pathelement location="${jdbc.jar}"/>
+ <pathelement location="${mysql.jar}"/>
+ <pathelement location="${hsqldb.jar}"/>
<pathelement location="${informix.jar}"/>
<pathelement location="${informix-extra.jar}"/>
<pathelement location="${avalon-framework.jar}"/>
@@ -346,6 +348,8 @@
<batchtest todir="${build.tests}">
<fileset dir="${build.testclasses}">
<include name="**/test/*TestCase.class"/>
+ <exclude name="**/test/*JdbcTestCase.class" unless="test.jdbc"/>
+ <exclude name="**/test/DataSourceJdbcTestCase.class"/>
<exclude name="**/Abstract*"/>
</fileset>
</batchtest>
1.3 +1 -32 jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceIdGenerator.java
Index: AbstractDataSourceIdGenerator.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceIdGenerator.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- AbstractDataSourceIdGenerator.java 13 Jun 2002 17:24:51 -0000 1.2
+++ AbstractDataSourceIdGenerator.java 2 Sep 2002 12:38:29 -0000 1.3
@@ -30,16 +30,12 @@
extends AbstractIdGenerator
implements IdGenerator, Composable, Configurable, Initializable, Disposable, ThreadSafe
{
- protected static final int DBTYPE_STANDARD = 0;
- protected static final int DBTYPE_MYSQL = 1;
-
/** ComponentLocator which created this component */
protected ComponentManager m_manager;
private String m_dataSourceName;
private ComponentSelector m_dbSelector;
protected DataSourceComponent m_dataSource;
- protected int m_dbType;
/**
* Number of allocated Ids remaining before another block must be allocated.
@@ -119,33 +115,6 @@
// Get a reference to a data source
m_dbSelector = (ComponentSelector)m_manager.lookup( DataSourceComponent.ROLE + "Selector" );
m_dataSource = (DataSourceComponent)m_dbSelector.select( m_dataSourceName );
-
- // Resolve the type of database that is being used.
- try
- {
- Connection conn = getConnection();
- try
- {
- Statement statement = conn.createStatement();
- String className = statement.getClass().getName();
- if( className.indexOf( "mysql" ) > 0 )
- {
- m_dbType = DBTYPE_MYSQL;
- }
- else
- {
- m_dbType = DBTYPE_STANDARD;
- }
- }
- finally
- {
- conn.close();
- }
- }
- catch( SQLException e )
- {
- getLogger().error( "Unable to open connection to resolve database type.", e );
- }
}
/*---------------------------------------------------------------
1.2 +94 -219 jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ids/TableIdGenerator.java
Index: TableIdGenerator.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ids/TableIdGenerator.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TableIdGenerator.java 22 Apr 2002 03:04:27 -0000 1.1
+++ TableIdGenerator.java 2 Sep 2002 12:38:29 -0000 1.2
@@ -117,221 +117,116 @@
Connection conn = getConnection();
try
{
- // Turn off auto commit so that we are working in a transaction,
- // but keep the old value.
- boolean oldAutoCommit = conn.getAutoCommit();
- conn.setAutoCommit( false );
+ boolean autoCommit = conn.getAutoCommit();
+
+ Statement stmt = conn.createStatement();
try
{
- int oldIsolation = conn.getTransactionIsolation();
- conn.setTransactionIsolation( Connection.TRANSACTION_SERIALIZABLE );
- try
- {
- try
+ // Try to get a block without using transactions. This makes this code
+ // portable, but works on the assumption that requesting blocks of ids
+ // is a fairly rare thing.
+ int tries = 0;
+ while( tries < 50 )
+ {
+ // Find out what the next available id is.
+ String query = "SELECT next_id FROM " + m_table + " WHERE table_name = '"
+ + m_tableName + "'";
+ ResultSet rs = stmt.executeQuery( query );
+ if ( !rs.next() )
{
- Statement stmt = conn.createStatement();
-
- int tries = 0;
- // May run into conflicts with other processes, so try this up to 50
- // times before giving up.
- while( tries < 50 )
+ // The row does not exist.
+ String msg =
+ "Unable to allocate a block of Ids, no row with table_name='"
+ + m_tableName + "' exists in the " + m_table + " table.";
+ getLogger().error( msg );
+ if ( !autoCommit )
{
- // Get the nextId from the table
- ResultSet rs = stmt.executeQuery(
- "SELECT next_id FROM " + m_table + " WHERE table_name = '" + m_tableName + "'" );
- if( !rs.next() )
- {
- // The row does not exist.
- String msg = "Unable to allocate a block of Ids, no row with table_name='" +
- m_tableName + "' exists in the " + m_table + " table.";
- getLogger().error( msg );
- conn.rollback();
-
- throw new IdException( msg );
- }
+ conn.rollback();
+ }
- // Get the next_id using the appropriate data type.
- Object nextId;
- if( useBigDecimals )
- {
- nextId = rs.getBigDecimal( 1 );
- }
- else
+ throw new IdException( msg );
+ }
+
+ // Get the next_id using the appropriate data type.
+ Object nextId;
+ Object newNextId;
+ if( useBigDecimals )
+ {
+ BigDecimal oldNextId = rs.getBigDecimal( 1 );
+ newNextId = oldNextId.add( new BigDecimal( blockSize ) );
+ nextId = oldNextId;
+ }
+ else
+ {
+ long oldNextId = rs.getLong( 1 );
+ newNextId = new Long( oldNextId + blockSize );
+ nextId = new Long( oldNextId );
+ }
+
+ // Update the value of next_id in the database so it reflects the full block
+ // being allocated. If another process has done the same thing, then this
+ // will either throw an exception due to transaction isolation or return
+ // an update count of 0. In either case, we will need to try again.
+ try
+ {
+ // Need to quote next_id values so that MySQL handles large BigDecimals
+ // correctly.
+ query = "UPDATE " + m_table
+ + " SET next_id = '" + newNextId + "' "
+ + " WHERE table_name = '" + m_tableName + "' "
+ + " AND next_id = '" + nextId + "'";
+ int updated = stmt.executeUpdate( query );
+ if( updated >= 1 )
+ {
+ // Update was successful.
+ if ( !autoCommit )
{
- nextId = new Long( rs.getLong( 1 ) );
+ conn.commit();
}
- // Update the value of next_id in the database so it reflects the full block
- // being allocated. If another process has done the same thing, then this
- // will throw an exception due to transaction isolation.
- try
- {
- int updated = stmt.executeUpdate( "UPDATE " + m_table +
- " SET next_id = next_id + " + blockSize +
- " WHERE table_name = '" + m_tableName + "'" );
- if( updated >= 1 )
- {
- // Update was successful.
- conn.commit();
-
- // Return the next id obtained above.
- return nextId;
- }
- else
- {
- // May have been a transaction confict. Try again.
- if( getLogger().isDebugEnabled() )
- {
- getLogger().debug(
- "Update resulted in no rows being changed." );
- }
- }
- }
- catch( SQLException e )
+ // Return the next id obtained above.
+ return nextId;
+ }
+ else
+ {
+ // May have been a transaction confict. Try again.
+ if( getLogger().isDebugEnabled() )
{
- // Assume that this was caused by a transaction conflict. Try again.
- if( getLogger().isDebugEnabled() )
- {
- getLogger().debug(
- "Encountered an exception attempting to update the " +
- m_table + " table. May be a transaction confict. " +
- "Trying again: " + e.getMessage() );
- }
+ getLogger().debug(
+ "Update resulted in no rows being changed." );
}
-
- // If we got here, then we failed, roll back the connection so we can
- // try again.
- conn.rollback();
-
- tries++;
}
- // If we got here then we ran out of tries.
- getLogger().error( "Unable to allocate a block of Ids. Too many retries." );
- return null;
}
- catch( SQLException e )
+ catch ( SQLException e )
+ {
+ // Assume that this was caused by a transaction conflict. Try again.
+ if( getLogger().isDebugEnabled() )
+ {
+ // Just show the exception message to keep the output small.
+ getLogger().debug(
+ "Encountered an exception attempting to update the "
+ + m_table + " table. May be a transaction confict. "
+ + "Trying again: " + e.getMessage() );
+ }
+ }
+
+ // If we got here, then we failed, roll back the connection so we can
+ // try again.
+ if ( !autoCommit )
{
- // Need this catch so that the connection can be rolled back before
- // the transaction is set in the finally block.
- String msg = "Unable to allocate a block of Ids.";
- getLogger().error( msg, e );
-
- // Rollback after the error is logged so that any problems rolling back
- // will not prevent the error from being logged.
conn.rollback();
-
- throw new IdException( msg, e );
}
- }
- finally
- {
- // Restore the isolation level
- conn.setTransactionIsolation( oldIsolation );
- }
- }
- finally
- {
- // restore Auto commit
- conn.setAutoCommit( oldAutoCommit );
- }
- }
- finally
- {
- conn.close();
- }
- }
- catch( SQLException e )
- {
- String msg = "Unable to allocate a block of Ids.";
- getLogger().error( msg, e );
- throw new IdException( msg, e );
- }
- }
-
- /**
- * Allocates a block of ids of the given size and returns the first id.
- * MySQL does not support transactions so this method handles synchronization
- * by making use of table locking.
- *
- * @param blockSize number of ids to allocate.
- * @param useBigDecimals returns the first id as a BigDecimal if true, otherwise as a Long.
- *
- * @return either a Long or a BigDecimal depending on the value of useBigDecimals
- *
- * @throws IdException if a block of ids can not be allocated.
- */
- private Object allocateIdBlockMySQL( int blockSize, boolean useBigDecimals )
- throws IdException
- {
- if( getLogger().isDebugEnabled() )
- {
- getLogger().debug( "Allocating a new block of " + blockSize + " ids." );
- }
-
- try
- {
- Connection conn = getConnection();
- try
- {
- Statement stmt = conn.createStatement();
- // Obtain a lock on the table
- stmt.executeUpdate( "LOCK TABLES " + m_table + " WRITE" );
- try
- {
- // Get the nextId from the table
- ResultSet rs = stmt.executeQuery(
- "SELECT next_id FROM " + m_table + " WHERE table_name = '" + m_tableName + "'" );
- if( !rs.next() )
- {
- // The row does not exist.
- String msg = "Unable to allocate a block of Ids, no row with table_name='" +
- m_tableName + "' exists in the " + m_table + " table.";
- getLogger().error( msg );
-
- throw new IdException( msg );
- }
-
- // Get the next_id using the appropriate data type.
- Object nextId;
- Object nextSavedId;
- if( useBigDecimals )
- {
- BigDecimal id = rs.getBigDecimal( 1 );
- nextId = id;
- nextSavedId = id.add( new BigDecimal( blockSize ) );
- }
- else
- {
- Long id = new Long( rs.getLong( 1 ) );
- nextId = id;
- nextSavedId = new Long( id.longValue() + blockSize );
- }
-
- // Update the value of next_id in the database so it reflects the full block
- // being allocated.
- //
- // Queries that set next_id = next_id + 10 do not work with large decimal values on MySQL 3.23.31
- int updated = stmt.executeUpdate( "UPDATE " + m_table +
- " SET next_id = " + nextSavedId +
- " WHERE table_name = '" + m_tableName + "'" );
- if( updated >= 1 )
- {
- // Return the next id obtained above.
- return nextId;
- }
- else
- {
- String msg = "Update resulted in no rows being changed.";
- getLogger().error( msg );
-
- throw new IdException( msg );
+ tries++;
}
+
+ // If we got here then we ran out of tries.
+ getLogger().error( "Unable to allocate a block of Ids. Too many retries." );
+ return null;
}
finally
{
- // Make absolutely sure that the lock is always released.
- stmt.executeUpdate( "UNLOCK TABLES" );
+ stmt.close();
}
}
finally
@@ -339,7 +234,7 @@
conn.close();
}
}
- catch( SQLException e )
+ catch ( SQLException e )
{
String msg = "Unable to allocate a block of Ids.";
getLogger().error( msg, e );
@@ -362,18 +257,7 @@
protected BigDecimal allocateBigDecimalIdBlock( int blockSize )
throws IdException
{
- BigDecimal id;
- switch( m_dbType )
- {
- case AbstractDataSourceIdGenerator.DBTYPE_MYSQL:
- id = (BigDecimal)allocateIdBlockMySQL( blockSize, true );
- break;
-
- default:
- id = (BigDecimal)allocateIdBlock( blockSize, true );
- }
-
- return id;
+ return (BigDecimal)allocateIdBlock( blockSize, true );
}
/**
@@ -388,16 +272,7 @@
protected long allocateLongIdBlock( int blockSize )
throws IdException
{
- Long id;
- switch( m_dbType )
- {
- case AbstractDataSourceIdGenerator.DBTYPE_MYSQL:
- id = (Long)allocateIdBlockMySQL( blockSize, false );
- break;
-
- default:
- id = (Long)allocateIdBlock( blockSize, false );
- }
+ Long id = (Long)allocateIdBlock( blockSize, false );
return id.longValue();
}
1.3 +3 -1 jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.java
Index: TableIdGeneratorJdbcTestCase.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- TableIdGeneratorJdbcTestCase.java 13 Jun 2002 13:11:15 -0000 1.2
+++ TableIdGeneratorJdbcTestCase.java 2 Sep 2002 12:38:29 -0000 1.3
@@ -505,8 +505,10 @@
{
Statement statement = conn.createStatement();
+ // Need to quote the BigDecimal as it is larger than normal numbers can be.
+ // Was causing problems with MySQL
statement.executeUpdate( "INSERT INTO ids (table_name, next_id) VALUES ('" +
- tableName + "', " + nextId.toString() + ")" );
+ tableName + "', '" + nextId.toString() + "')" );
}
finally
{
1.6 +3 -0 jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/test/DataSourceJdbcTestCase.java
Index: DataSourceJdbcTestCase.java
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/test/DataSourceJdbcTestCase.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- DataSourceJdbcTestCase.java 13 Jun 2002 13:11:15 -0000 1.5
+++ DataSourceJdbcTestCase.java 2 Sep 2002 12:38:29 -0000 1.6
@@ -36,10 +36,12 @@
public DataSourceJdbcTestCase( String name )
{
super( name );
+ System.out.println("1");
}
public void testOverAllocation()
{
+ System.out.println("2");
DataSourceComponent ds = null;
this.isSuccessful = false;
LinkedList connectionList = new LinkedList();
@@ -97,6 +99,7 @@
public void testNormalUse()
{
+ System.out.println("3");
DataSourceComponent ds = null;
this.isSuccessful = true;
1.3 +1 -1 jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/test/DataSourceJdbcTestCase.xtest
Index: DataSourceJdbcTestCase.xtest
===================================================================
RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/src/test/org/apache/avalon/excalibur/datasource/test/DataSourceJdbcTestCase.xtest,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- DataSourceJdbcTestCase.xtest 13 Apr 2002 08:30:06 -0000 1.2
+++ DataSourceJdbcTestCase.xtest 2 Sep 2002 12:38:29 -0000 1.3
@@ -34,7 +34,7 @@
</targets>
<categories>
- <category name="test" log-level="INFO">
+ <category name="test" log-level="DEBUG">
<log-target id-ref="console"/>
<log-target id-ref="file"/>
</category>
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>