leif 02/02/08 09:38:09
Modified: src/scratchpad/org/apache/avalon/excalibur/datasource/ids
AbstractDataSourceBlockIdGenerator.java
AbstractDataSourceIdGenerator.java
TableIdGenerator.java
src/scratchpad/org/apache/avalon/excalibur/datasource/ids/test
TableIdGeneratorJdbcTestCase.java
TableIdGeneratorJdbcTestCase.xtest
Log:
Fix some problems with IdGenerator and make things work with MySQL databases.
Revision Changes Path
1.2 +8 -1
jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceBlockIdGenerator.java
Index: AbstractDataSourceBlockIdGenerator.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceBlockIdGenerator.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AbstractDataSourceBlockIdGenerator.java 8 Feb 2002 12:27:32 -0000
1.1
+++ AbstractDataSourceBlockIdGenerator.java 8 Feb 2002 17:38:09 -0000
1.2
@@ -22,7 +22,7 @@
* the DataSource.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Leif Mortenson</a>
- * @version CVS $Revision: 1.1 $ $Date: 2002/02/08 12:27:32 $
+ * @version CVS $Revision: 1.2 $ $Date: 2002/02/08 17:38:09 $
* @since 4.1
*/
public abstract class AbstractDataSourceBlockIdGenerator
@@ -152,6 +152,13 @@
// We know that at least one id is available.
// Get an id out of the currently allocated block.
long id = m_firstLong + m_allocated;
+ if ( id < 0 )
+ {
+ // The value wrapped
+ String msg = "No more Ids are available, the maximum long value
has been reached.";
+ getLogger().error( msg );
+ throw new IdException( msg );
+ }
m_allocated++;
return id;
1.2 +33 -1
jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceIdGenerator.java
Index: AbstractDataSourceIdGenerator.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/AbstractDataSourceIdGenerator.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AbstractDataSourceIdGenerator.java 8 Feb 2002 12:27:32 -0000
1.1
+++ AbstractDataSourceIdGenerator.java 8 Feb 2002 17:38:09 -0000
1.2
@@ -9,6 +9,7 @@
import java.math.BigDecimal;
import java.sql.Connection;
+import java.sql.Statement;
import java.sql.SQLException;
import org.apache.avalon.excalibur.datasource.DataSourceComponent;
@@ -26,19 +27,23 @@
/**
* @author <a href="mailto:[EMAIL PROTECTED]">Leif Mortenson</a>
- * @version CVS $Revision: 1.1 $ $Date: 2002/02/08 12:27:32 $
+ * @version CVS $Revision: 1.2 $ $Date: 2002/02/08 17:38:09 $
* @since 4.1
*/
public abstract class AbstractDataSourceIdGenerator
extends AbstractIdGenerator
implements IdGenerator, Composable, Configurable, Initializable,
Disposable, ThreadSafe
{
+ protected static final int DBTYPE_STANDARD = 0;
+ protected static final int DBTYPE_MYSQL = 1;
+
/** ComponentManager 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.
@@ -116,6 +121,33 @@
// 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 +133 -3
jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/TableIdGenerator.java
Index: TableIdGenerator.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/src/scratchpad/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 8 Feb 2002 12:27:32 -0000 1.1
+++ TableIdGenerator.java 8 Feb 2002 17:38:09 -0000 1.2
@@ -57,9 +57,18 @@
*
* Your component obtains a reference to an IdGenerator using the same
method as it obtains a
* DataSource, by making use of a ComponentSelector.
+ * <p>
+ * Depending on your database, the ids table should look something like the
following:
+ * <pre>
+ * CREATE TABLE ids (
+ * table_name varchar(16) NOT NULL,
+ * next_id INTEGER NOT NULL,
+ * PRIMARY KEY (table_name)
+ * );
+ * </pre>
*
* @author <a href="mailto:[EMAIL PROTECTED]">Leif Mortenson</a>
- * @version CVS $Revision: 1.1 $ $Date: 2002/02/08 12:27:32 $
+ * @version CVS $Revision: 1.2 $ $Date: 2002/02/08 17:38:09 $
* @since 4.1
*/
public class TableIdGenerator
@@ -236,6 +245,105 @@
}
}
+ /**
+ * 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.
+ *
+ * @returns 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 );
+ }
+ }
+ finally
+ {
+ // Make absolutely sure that the lock is always released.
+ stmt.executeUpdate( "UNLOCK TABLES" );
+ }
+ }
+ finally
+ {
+ conn.close();
+ }
+ }
+ catch (SQLException e)
+ {
+ String msg = "Unable to allocate a block of Ids.";
+ getLogger().error( msg, e );
+ throw new IdException( msg, e );
+ }
+ }
+
/*---------------------------------------------------------------
* AbstractDataSourceBlockIdGenerator Methods
*-------------------------------------------------------------*/
@@ -251,7 +359,18 @@
protected BigDecimal allocateBigDecimalIdBlock( int blockSize )
throws IdException
{
- return (BigDecimal)allocateIdBlock( blockSize, true );
+ BigDecimal id;
+ switch( m_dbType )
+ {
+ case AbstractDataSourceIdGenerator.DBTYPE_MYSQL:
+ id = (BigDecimal)allocateIdBlockMySQL( blockSize, true );
+ break;
+
+ default:
+ id = (BigDecimal)allocateIdBlock( blockSize, true );
+ }
+
+ return id;
}
/**
@@ -266,7 +385,18 @@
protected long allocateLongIdBlock( int blockSize )
throws IdException
{
- return ((Long)allocateIdBlock( blockSize, false )).longValue();
+ Long id;
+ switch( m_dbType )
+ {
+ case AbstractDataSourceIdGenerator.DBTYPE_MYSQL:
+ id = (Long)allocateIdBlockMySQL( blockSize, false );
+ break;
+
+ default:
+ id = (Long)allocateIdBlock( blockSize, false );
+ }
+
+ return id.longValue();
}
/*---------------------------------------------------------------
1.2 +88 -27
jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.java
Index: TableIdGeneratorJdbcTestCase.java
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TableIdGeneratorJdbcTestCase.java 8 Feb 2002 12:27:32 -0000 1.1
+++ TableIdGeneratorJdbcTestCase.java 8 Feb 2002 17:38:09 -0000 1.2
@@ -158,7 +158,7 @@
getLogger().info( "testNonExistingTableName" );
IdGenerator idGenerator =
- (IdGenerator)m_idGeneratorSelector.select(
"ids-size-does-not-exist" );
+ (IdGenerator)m_idGeneratorSelector.select(
"ids-testNonExistingTableName" );
try
{
try
@@ -181,7 +181,8 @@
{
getLogger().info( "testSimpleRequestIdsSize1" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-1" );
+ IdGenerator idGenerator =
+ (IdGenerator)m_idGeneratorSelector.select(
"ids-testSimpleRequestIdsSize1" );
try
{
int testCount = 100;
@@ -208,7 +209,8 @@
{
getLogger().info( "testSimpleRequestIdsSize10" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10" );
+ IdGenerator idGenerator =
+ (IdGenerator)m_idGeneratorSelector.select(
"ids-testSimpleRequestIdsSize10" );
try
{
int testCount = 100;
@@ -235,7 +237,8 @@
{
getLogger().info( "testSimpleRequestIdsSize100" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-100" );
+ IdGenerator idGenerator =
+ (IdGenerator)m_idGeneratorSelector.select(
"ids-testSimpleRequestIdsSize100" );
try
{
int testCount = 100;
@@ -262,28 +265,36 @@
{
getLogger().info( "testBigDecimalRequestIdsSize10" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10-bd" );
- try
+ if ( isBigDecimalImplemented() )
{
- int testCount = 100;
- BigDecimal initial = new BigDecimal( Long.MAX_VALUE + "00" );
-
- // Initialize the counter in the database.
- initializeNextBigDecimalId( "test", initial );
-
- for ( int i = 0; i < testCount; i++ )
+ IdGenerator idGenerator =
+ (IdGenerator)m_idGeneratorSelector.select(
"ids-testBigDecimalRequestIdsSize10" );
+ try
{
- BigDecimal id = idGenerator.getNextBigDecimalId();
- assertEquals( "The returned id was not what was expected.",
- initial.add( new BigDecimal( i ) ), id );
+ int testCount = 100;
+ BigDecimal initial = new BigDecimal( Long.MAX_VALUE + "00" );
+
+ // Initialize the counter in the database.
+ initializeNextBigDecimalId( "test", initial );
+
+ for ( int i = 0; i < testCount; i++ )
+ {
+ BigDecimal id = idGenerator.getNextBigDecimalId();
+ assertEquals( "The returned id was not what was
expected.",
+ initial.add( new BigDecimal( i ) ), id );
+ }
+
+ assertEquals( "The next_id column in the database did not
have the expected value.",
+ initial.add( new BigDecimal( testCount ) ),
peekNextBigDecimalId( "test" ) );
+ }
+ finally
+ {
+ m_idGeneratorSelector.release( idGenerator );
}
-
- assertEquals( "The next_id column in the database did not have
the expected value.",
- initial.add( new BigDecimal( testCount ) ),
peekNextBigDecimalId( "test" ) );
}
- finally
+ else
{
- m_idGeneratorSelector.release( idGenerator );
+ getLogger().warn( "Test Skipped because BigDecimals are not
implemented in current driver." );
}
}
@@ -291,7 +302,7 @@
{
getLogger().info( "testMaxByteIds" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10" );
+ IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-testMaxByteIds" );
try
{
int testCount = 100;
@@ -328,7 +339,7 @@
{
getLogger().info( "testMaxShortIds" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10" );
+ IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-testMaxShortIds" );
try
{
int testCount = 100;
@@ -365,7 +376,7 @@
{
getLogger().info( "testMaxIntegerIds" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10" );
+ IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-testMaxIntegerIds" );
try
{
int testCount = 100;
@@ -402,7 +413,7 @@
{
getLogger().info( "testMaxLongIds" );
- IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-size-10" );
+ IdGenerator idGenerator = (IdGenerator)m_idGeneratorSelector.select(
"ids-testMaxLongIds" );
try
{
int testCount = 100;
@@ -438,6 +449,56 @@
/*---------------------------------------------------------------
* Utilitity Methods
*-------------------------------------------------------------*/
+ /**
+ * Tests to see whether or not the current DataSource supports BigDecimal
+ */
+ private boolean isBigDecimalImplemented()
+ {
+ String tableName = "foorbar_table";
+
+ // Add a row that can be selected.
+ initializeNextLongId( tableName, 1 );
+
+ try
+ {
+ Connection conn = m_dataSource.getConnection();
+ try
+ {
+ Statement statement = conn.createStatement();
+
+ ResultSet rs = statement.executeQuery( "SELECT next_id FROM
ids " +
+ "WHERE table_name = '" + tableName + "'" );
+ if ( rs.next() )
+ {
+ BigDecimal id = rs.getBigDecimal( 1 );
+ }
+ else
+ {
+ fail( tableName + " row not in ids table." );
+ return false; // for compiler
+ }
+ }
+ finally
+ {
+ conn.close();
+ }
+
+ // Implemented
+ return true;
+ }
+ catch ( SQLException e )
+ {
+ if ( e.toString().indexOf( "NotImplemented" ) > 0 )
+ {
+ // Not implemented
+ return false;
+ }
+ getLogger().error( "Unable to peek next_id.", e );
+ fail( "Unable to peek next_id. " + e );
+ return false; // for compiler
+ }
+ }
+
private void initializeNextBigDecimalId( String tableName, BigDecimal
nextId )
{
try
@@ -503,7 +564,7 @@
}
else
{
- fail( "next_id row not in ids table." );
+ fail( tableName + " row not in ids table." );
return null; // for compiler
}
}
@@ -537,7 +598,7 @@
}
else
{
- fail( "next_id row not in ids table." );
+ fail( tableName + " row not in ids table." );
return -1; // for compiler
}
}
1.2 +29 -7
jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.xtest
Index: TableIdGeneratorJdbcTestCase.xtest
===================================================================
RCS file:
/home/cvs/jakarta-avalon-excalibur/src/scratchpad/org/apache/avalon/excalibur/datasource/ids/test/TableIdGeneratorJdbcTestCase.xtest,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TableIdGeneratorJdbcTestCase.xtest 8 Feb 2002 12:27:32 -0000
1.1
+++ TableIdGeneratorJdbcTestCase.xtest 8 Feb 2002 17:38:09 -0000
1.2
@@ -41,7 +41,7 @@
<log-target id-ref="file"/>
</category>
- <category name="id-gen" log-level="DEBUG">
+ <category name="id-gen" log-level="INFO">
<log-target id-ref="console"/>
<log-target id-ref="file"/>
</category>
@@ -87,25 +87,47 @@
</datasources>
<id-generators>
- <table name="ids-size-does-not-exist" block-size="1" table="ids"
+ <table name="ids-testNonExistingTableName" block-size="1"
table="ids"
key-table="does-not-exist" logger="id-gen">
<dbpool>test-db</dbpool>
</table>
- <table name="ids-size-1" block-size="1" table="ids"
key-table="test" logger="id-gen">
+ <table name="ids-testSimpleRequestIdsSize1" block-size="1"
table="ids"
+ key-table="test" logger="id-gen">
<dbpool>test-db</dbpool>
</table>
- <table name="ids-size-10" block-size="10" table="ids"
key-table="test" logger="id-gen">
+ <table name="ids-testSimpleRequestIdsSize10" block-size="10"
table="ids"
+ key-table="test" logger="id-gen">
<dbpool>test-db</dbpool>
</table>
- <table name="ids-size-100" block-size="100" table="ids"
key-table="test"
- logger="id-gen">
+ <table name="ids-testSimpleRequestIdsSize100" block-size="100"
table="ids"
+ key-table="test" logger="id-gen">
<dbpool>test-db</dbpool>
</table>
- <table name="ids-size-10-bd" big-decimals="true" block-size="10"
table="ids"
+ <table name="ids-testBigDecimalRequestIdsSize10"
big-decimals="true"
+ block-size="10" table="ids" key-table="test"
logger="id-gen">
+ <dbpool>test-db</dbpool>
+ </table>
+
+ <table name="ids-testMaxByteIds" block-size="10" table="ids"
+ key-table="test" logger="id-gen">
+ <dbpool>test-db</dbpool>
+ </table>
+
+ <table name="ids-testMaxShortIds" block-size="10" table="ids"
+ key-table="test" logger="id-gen">
+ <dbpool>test-db</dbpool>
+ </table>
+
+ <table name="ids-testMaxIntegerIds" block-size="10" table="ids"
+ key-table="test" logger="id-gen">
+ <dbpool>test-db</dbpool>
+ </table>
+
+ <table name="ids-testMaxLongIds" block-size="10" table="ids"
key-table="test" logger="id-gen">
<dbpool>test-db</dbpool>
</table>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>