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>