You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by ht...@apache.org on 2011/07/11 21:54:32 UTC

svn commit: r1145315 - in /openjpa/branches/1.3.x: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/ openjpa-pr...

Author: hthomann
Date: Mon Jul 11 19:54:31 2011
New Revision: 1145315

URL: http://svn.apache.org/viewvc?rev=1145315&view=rev
Log:
OPENJPA-1376: Backported trunk changes to 1.3.x where possible, made code gated by a system property.

Modified:
    openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java
    openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
    openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
    openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
    openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java
    openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java
    openjpa/branches/1.3.x/openjpa-project/src/doc/manual/jpa_overview_mapping.xml
    openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml
    openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_optimization.xml
    openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_runtime.xml

Modified: openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java (original)
+++ openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java Mon Jul 11 19:54:31 2011
@@ -54,6 +54,8 @@ import serp.util.Strings;
 /**
  * {@link JDBCSeq} implementation that uses a database sequences
  * to generate numbers.
+ * Supports allocation (caching). In order for allocation to work properly, the database sequence must be defined
+ * with INCREMENT BY value equal to allocate * increment.
  *
  * @see JDBCSeq
  * @see AbstractJDBCSeq
@@ -72,9 +74,12 @@ public class NativeJDBCSeq
     private String _seqName = "OPENJPA_SEQUENCE";
     private int _increment = 1;
     private int _initial = 1;
-    private int _allocate = 0;
+    private int _allocate = 50;
     private Sequence _seq = null;
     private String _select = null;
+    private long _nextValue = 0;
+    private long _maxValue = -1;
+    
 
     // for deprecated auto-configuration support
     private String _format = null;
@@ -194,30 +199,77 @@ public class NativeJDBCSeq
 
     public void endConfiguration() {
         buildSequence();
-
-        DBDictionary dict = _conf.getDBDictionaryInstance();
-        if (_format == null) {
-            _format = dict.nextSequenceQuery;
-            if (_format == null)
-                throw new MetaDataException(_loc.get("no-seq-sql", _seqName));
-        }
+        
         if (_tableName == null)
             _tableName = "DUAL";
 
+        DBDictionary dict = _conf.getDBDictionaryInstance();
         String name = dict.getFullName(_seq);
-        Object[] subs = (_subTable) ? new Object[]{ name, _tableName }
+        
+        if (dict.useNativeSequenceCache){
+            if (_format == null) {
+            	_format = dict.nextSequenceQuery;
+            	if (_format == null)
+            		throw new MetaDataException(_loc.get("no-seq-sql", _seqName));
+            }
+            
+            Object[] subs = (_subTable) ? new Object[]{ name, _tableName }
             : new Object[]{ name };
-        _select = MessageFormat.format(_format, subs);
+            _select = MessageFormat.format(_format, subs);
+        }
+        else {           
+        	String format = dict.nextSequenceQuery;
+            if (format == null) {
+                throw new MetaDataException(_loc.get("no-seq-sql", _seqName));
+            }
+            
+            // Increment step is needed for Firebird which uses non-standard sequence fetch syntax.
+            // Use String.valueOf to get rid of possible locale-specific number formatting.
+            _select = MessageFormat.format(format, new Object[]{name,
+                 String.valueOf(_allocate * _increment)});            
+        }       
         
         type = dict.nativeSequenceType;
     }
     
     @Override
-    protected Object nextInternal(JDBCStore store, ClassMapping mapping)
+    protected synchronized Object nextInternal(JDBCStore store, ClassMapping mapping)
         throws SQLException {
+        DBDictionary dict = _conf.getDBDictionaryInstance();
+        
+        //To maintain existing behavior call allocateInternal to get the next 
+        //sequence value, which it stores in _nextValue, and simply return the value.
+        if (dict.useNativeSequenceCache){
+        	allocateInternal(0, store, mapping);
+        	return _nextValue;
+        }
+        
+        if (_nextValue < _maxValue) {
+            long result = _nextValue;
+            _nextValue += _increment;
+            return result;
+        }
+
+        allocateInternal(0, store, mapping);
+        long result = _nextValue;
+        _nextValue += _increment;
+        return result;
+    }
+
+    /**
+     * Allocate additional sequence values.
+     * @param additional ignored - the allocation size is fixed and determined by allocate and increment properties. 
+     * @param store used to obtain connection
+     * @param mapping ignored
+     */
+    @Override
+    protected synchronized void allocateInternal(int additional, JDBCStore store, ClassMapping mapping)
+        throws SQLException {
+    	
         Connection conn = getConnection(store);
         try {
-            return Numbers.valueOf(getSequence(conn));
+            _nextValue = Numbers.valueOf(getSequence(conn));
+            _maxValue = _nextValue + _allocate * _increment;            
         } finally {
             closeConnection(conn);
         }
@@ -281,9 +333,7 @@ public class NativeJDBCSeq
         ResultSet rs = null;
         try {
             stmnt = conn.prepareStatement(_select);
-            synchronized(this) {
-                rs = stmnt.executeQuery();
-            }
+            rs = stmnt.executeQuery();
             if (rs.next())
                 return rs.getLong(1);
 
@@ -308,13 +358,12 @@ public class NativeJDBCSeq
      *  Where the following options are recognized.
      * <ul>
      * <li><i>-properties/-p &lt;properties file or resource&gt;</i>: The
-     * path or resource name of a OpenJPA properties file containing
-     * information such as the license key	and connection data as
+     * path or resource name of an OpenJPA properties file containing
+     * information such as connection data as
      * outlined in {@link JDBCConfiguration}. Optional.</li>
      * <li><i>-&lt;property name&gt; &lt;property value&gt;</i>: All bean
      * properties of the OpenJPA {@link JDBCConfiguration} can be set by
-     * using their	names and supplying a value. For example:
-     * <code>-licenseKey adslfja83r3lkadf</code></li>
+     * using their names and supplying a value.</li>
      * </ul>
      *  The various actions are as follows.
      * <ul>
@@ -354,7 +403,7 @@ public class NativeJDBCSeq
     }
 
     /**
-     * Run the tool. Return false if an invalid option was given.
+     * Run the tool. Returns false if an invalid option was given.
      */
     public static boolean run(JDBCConfiguration conf, String[] args,
         String action)

Modified: openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java (original)
+++ openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DB2Dictionary.java Mon Jul 11 19:54:31 2011
@@ -222,12 +222,15 @@ public class DB2Dictionary
         return getJDBCType(metaTypeCode, lob && !xml, precis, scale);        
     }
 
-    public String[] getCreateSequenceSQL(Sequence seq) {
-        String[] sql = super.getCreateSequenceSQL(seq);
-        if (seq.getAllocate() > 1)
-            sql[0] += " CACHE " + seq.getAllocate();
-        return sql;
-    }
+    public String[] getCreateSequenceSQL(Sequence seq) {    
+    	String[] sql = super.getCreateSequenceSQL(seq);
+    	
+    	if (seq.getAllocate() > 1 && useNativeSequenceCache){    	
+    		sql[0] += " CACHE " + seq.getAllocate();
+    	}
+    	
+    	return sql;
+    }   
 
     protected String getSequencesSQL(String schemaName, String sequenceName) {
         StringBuffer buf = new StringBuffer();

Modified: openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Mon Jul 11 19:54:31 2011
@@ -335,6 +335,7 @@ public class DBDictionary
     public String sequenceNameSQL = null;
     // most native sequences can be run inside the business transaction
     public int nativeSequenceType= Seq.TYPE_CONTIGUOUS;
+    public boolean useNativeSequenceCache = true;
 
     protected JDBCConfiguration conf = null;
     protected Log log = null;
@@ -3261,8 +3262,12 @@ public class DBDictionary
         buf.append(seqName);
         if (seq.getInitialValue() != 0)
             buf.append(" START WITH ").append(seq.getInitialValue());
-        if (seq.getIncrement() > 1)
-            buf.append(" INCREMENT BY ").append(seq.getIncrement());
+        if (seq.getIncrement() > 1 && useNativeSequenceCache){
+        	buf.append(" INCREMENT BY ").append(seq.getIncrement());
+        }
+        else if ((seq.getIncrement() > 1) || (seq.getAllocate() > 1)){
+            buf.append(" INCREMENT BY ").append(seq.getIncrement() * seq.getAllocate());
+        }
         return new String[]{ buf.toString() };
     }
 

Modified: openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java (original)
+++ openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/OracleDictionary.java Mon Jul 11 19:54:31 2011
@@ -974,12 +974,15 @@ public class OracleDictionary
         return getJDBCType(metaTypeCode, lob && !xml, precis, scale);        
     }
 
-    public String[] getCreateSequenceSQL(Sequence seq) {
-        String[] sql = super.getCreateSequenceSQL(seq);
-        if (seq.getAllocate() > 1)
-            sql[0] += " CACHE " + seq.getAllocate();
-        return sql;
-    }
+    public String[] getCreateSequenceSQL(Sequence seq) {    
+    	String[] sql = super.getCreateSequenceSQL(seq);
+    	
+    	if (seq.getAllocate() > 1 && useNativeSequenceCache){
+    		sql[0] += " CACHE " + seq.getAllocate();
+    	}
+    	
+    	return sql;    	
+     }
 
     protected String getSequencesSQL(String schemaName, String sequenceName) {
         StringBuffer buf = new StringBuffer();

Modified: openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java (original)
+++ openjpa/branches/1.3.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/PostgresDictionary.java Mon Jul 11 19:54:31 2011
@@ -311,11 +311,15 @@ public class PostgresDictionary
 
     public String[] getCreateSequenceSQL(Sequence seq) {
         String[] sql = super.getCreateSequenceSQL(seq);
-        if (seq.getAllocate() > 1)
+        
+        if (seq.getAllocate() > 1 && useNativeSequenceCache){
             sql[0] += " CACHE " + seq.getAllocate();
+        }
+        
         return sql;
     }
 
+    
     protected boolean supportsDeferredUniqueConstraints() {
         // Postgres only supports deferred foreign key constraints.
         return false;

Modified: openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java (original)
+++ openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SQLListenerTestCase.java Mon Jul 11 19:54:31 2011
@@ -35,7 +35,6 @@ public abstract class SQLListenerTestCas
     extends SingleEMFTestCase {
     private static String _nl = System.getProperty("line.separator");
     protected List<String> sql = new ArrayList<String>();
-    protected int sqlCount;
     
     @Override
     public void setUp(Object... props) {
@@ -98,17 +97,17 @@ public abstract class SQLListenerTestCas
      * Gets the number of SQL issued since last reset.
      */
     public int getSQLCount() {
-    	return sqlCount;
+    	return sql.size();
     }
     
     /**
      * Resets SQL count.
      * @return number of SQL counted since last reset.
      */
-    public int resetSQLCount() {
-    	int tmp = sqlCount;
-    	sqlCount = 0;
-    	return tmp;
+    public int resetSQL() {
+        int tmp = sql.size();
+        sql.clear();
+        return tmp;
     }
 
     public String toString(List<String> list) {
@@ -125,7 +124,6 @@ public abstract class SQLListenerTestCas
         public void beforeExecuteStatement(JDBCEvent event) {
             if (event.getSQL() != null && sql != null) {
                 sql.add(event.getSQL());
-                sqlCount++;
             }
 		}
 	}
@@ -153,4 +151,44 @@ public abstract class SQLListenerTestCas
             fail(sb.toString());
         }
     }
+
+    /**
+     * Confirm the list of expected SQL expressions have been executed in the
+     * exact number and order specified.
+     * 
+     * @param expected
+     *            SQL expressions. E.g., ("SELECT FOO .*", "UPDATE .*")
+     */
+    public void assertAllExactSQLInOrder(String... expected) {
+        assertSQLInOrder(true, expected);
+    }
+
+    private void assertSQLInOrder(boolean exact, String... expected) {
+        boolean match = false;
+        int sqlSize = sql.size();
+        if (expected.length <= sqlSize) {
+            int hits = 0;
+            for (String executedSQL : sql) {
+                if (executedSQL.matches(expected[hits])) {
+                    if (++hits == expected.length)
+                        break;
+                }
+            }
+            match = hits == (exact ? sqlSize : expected.length);
+        }
+
+        if (!match) {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Did not find SQL in expected order : ").append(_nl);
+            for (String s : expected) {
+                sb.append(s).append(_nl);
+            }
+
+            sb.append("SQL Statements issued : ");
+            for (String s : sql) {
+                sb.append(s).append(_nl);
+            }
+            fail(sb.toString());
+        }
+    }
 }

Modified: openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java (original)
+++ openjpa/branches/1.3.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/SingleEMFTestCase.java Mon Jul 11 19:54:31 2011
@@ -23,6 +23,7 @@ import java.util.List;
 import javax.persistence.EntityManager;
 
 import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
 
 /**
@@ -127,6 +128,10 @@ public abstract class SingleEMFTestCase
     public int count(Class c) {
     	return count(c.getSimpleName());
     }
+
+    protected Log getLog() {
+        return emf.getConfiguration().getLog("Tests");
+    }
     
     /**
      * Get all the instances of given type.

Modified: openjpa/branches/1.3.x/openjpa-project/src/doc/manual/jpa_overview_mapping.xml
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-project/src/doc/manual/jpa_overview_mapping.xml?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-project/src/doc/manual/jpa_overview_mapping.xml (original)
+++ openjpa/branches/1.3.x/openjpa-project/src/doc/manual/jpa_overview_mapping.xml Mon Jul 11 19:54:31 2011
@@ -960,10 +960,11 @@ default.
                             allocationSize property
                         </secondary>
                     </indexterm>
-<literal>int allocationSize</literal>: Some databases can pre-allocate groups
-of sequence values. This allows the database to service sequence requests from
-cache, rather than physically incrementing the sequence with every request. This
-allocation size defaults to 50.
+<literal>int allocationSize</literal>: The number of values to allocate in
+memory for each trip to the database. Allocating values in memory allows the JPA
+runtime to avoid accessing the database for every sequence request.
+This number also specifies the amount that the sequence value is incremented
+each time the sequence is accessed. Defaults to 50.
                     </para>
                 </listitem>
             </itemizedlist>

Modified: openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml (original)
+++ openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_dbsetup.xml Mon Jul 11 19:54:31 2011
@@ -1672,8 +1672,9 @@ table name. Defaults to 128.
                     </indexterm>
 <literal>NextSequenceQuery</literal>: A SQL string for obtaining a native
 sequence value. May use a placeholder of <literal>{0}</literal> for the variable
-sequence name. Defaults to a database-appropriate value.  For example, 
-<literal>"SELECT {0}.NEXTVAL FROM DUAL"</literal> for Oracle.
+sequence name and <literal>{1}</literal> for sequence increment.
+Defaults to a database-appropriate value. For example, 
+<literal>"SELECT {0}.NEXTVAL FROM DUAL"</literal> for Oracle database.
                     </para>
                 </listitem>
                 <listitem id="DBDictionary.NullTypeName">

Modified: openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_optimization.xml
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_optimization.xml?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_optimization.xml (original)
+++ openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_optimization.xml Mon Jul 11 19:54:31 2011
@@ -295,8 +295,7 @@ it can become a factor.
                     </entry>
                     <entry colname="desc">
 For applications that perform large bulk inserts, the retrieval of sequence 
-numbers can be a bottleneck.  Increasing sequence increments and using 
-table-based rather than native database sequences can reduce or eliminate 
+numbers can be a bottleneck. Increasing sequence allocation sizes can reduce or eliminate 
 this bottleneck. In some cases, implementing your own sequence factory can 
 further optimize sequence number retrieval.
                     </entry>

Modified: openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_runtime.xml
URL: http://svn.apache.org/viewvc/openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_runtime.xml?rev=1145315&r1=1145314&r2=1145315&view=diff
==============================================================================
--- openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_runtime.xml (original)
+++ openjpa/branches/1.3.x/openjpa-project/src/doc/manual/ref_guide_runtime.xml Mon Jul 11 19:54:31 2011
@@ -1620,8 +1620,11 @@ properties:
                     </listitem>
                     <listitem>
                         <para>
-<literal>Allocate</literal>: Some database can allocate values in-memory to
-service subsequent sequence requests faster.
+<literal>Allocate</literal>: The number of values to allocate on each database
+trip. Defaults to 50, meaning the class will set aside the next 50 numbers each
+time it accesses the sequence, which in turn means it only has to make a
+database trip to get new sequence numbers once every 50 sequence number
+requests.
                         </para>
                     </listitem>
                 </itemizedlist>