You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by aw...@apache.org on 2006/09/20 20:40:29 UTC

svn commit: r448298 - in /incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel: AbstractJDBCSeq.java ClassTableJDBCSeq.java NativeJDBCSeq.java TableJDBCSeq.java

Author: awhite
Date: Wed Sep 20 11:40:28 2006
New Revision: 448298

URL: http://svn.apache.org/viewvc?view=rev&rev=448298
Log:
Perform JDBC sequence ops outside of synchronization blocks in case of JDBC
hangs.  Also should improve concurrency.


Modified:
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java
    incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java?view=diff&rev=448298&r1=448297&r2=448298
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractJDBCSeq.java Wed Sep 20 11:40:28 2006
@@ -41,10 +41,6 @@
     protected int type = TYPE_DEFAULT;
     protected Object current = null;
 
-    // used to track current conn so that we can close it
-    private Connection _conn = null;
-    private boolean _commit = false;
-
     /**
      * Records the sequence type.
      */
@@ -52,7 +48,7 @@
         this.type = type;
     }
 
-    public synchronized Object next(StoreContext ctx, ClassMetaData meta) {
+    public Object next(StoreContext ctx, ClassMetaData meta) {
         JDBCStore store = getStore(ctx);
         try {
             current = nextInternal(store, (ClassMapping) meta);
@@ -63,12 +59,10 @@
             throw SQLExceptions.getStore(se, store.getDBDictionary());
         } catch (Exception e) {
             throw new StoreException(e);
-        } finally {
-            closeConnection();
         }
     }
 
-    public synchronized Object current(StoreContext ctx, ClassMetaData meta) {
+    public Object current(StoreContext ctx, ClassMetaData meta) {
         JDBCStore store = getStore(ctx);
         try {
             return currentInternal(store, (ClassMapping) meta);
@@ -78,13 +72,10 @@
             throw SQLExceptions.getStore(se, store.getDBDictionary());
         } catch (Exception e) {
             throw new StoreException(e);
-        } finally {
-            closeConnection();
         }
     }
 
-    public synchronized void allocate(int additional, StoreContext ctx,
-        ClassMetaData meta) {
+    public void allocate(int additional, StoreContext ctx, ClassMetaData meta) {
         JDBCStore store = getStore(ctx);
         try {
             allocateInternal(additional, store, (ClassMapping) meta);
@@ -94,8 +85,6 @@
             throw SQLExceptions.getStore(se, store.getDBDictionary());
         } catch (Exception e) {
             throw new StoreException(e);
-        } finally {
-            closeConnection();
         }
     }
 
@@ -121,7 +110,7 @@
     /**
      * Return the current sequence object. By default returns the last
      * sequence value used, or null if no sequence values have been requested
-     * yet.
+     * yet. Default implementation is not threadsafe.
      */
     protected Object currentInternal(JDBCStore store, ClassMapping mapping)
         throws Exception {
@@ -149,41 +138,31 @@
      */
     protected Connection getConnection(JDBCStore store)
         throws SQLException {
-        // close previous connection if user is asking for another connection
-        closeConnection();
-
         if (type == TYPE_TRANSACTIONAL || type == TYPE_CONTIGUOUS)
-            _conn = store.getConnection();
-        else {
-            JDBCConfiguration conf = store.getConfiguration();
-            DataSource ds = conf.getDataSource2(store.getContext());
-            _conn = ds.getConnection();
-            if (_conn.getAutoCommit())
-                _conn.setAutoCommit(false);
-            _commit = true;
-        }
-        return _conn;
+            return store.getConnection();
+
+        JDBCConfiguration conf = store.getConfiguration();
+        DataSource ds = conf.getDataSource2(store.getContext());
+        Connection conn = ds.getConnection();
+        if (conn.getAutoCommit())
+            conn.setAutoCommit(false);
+        return conn;
     }
 
     /**
      * Close the current connection.
      */
-    protected void closeConnection() {
-        if (_conn == null)
+    protected void closeConnection(Connection conn) {
+        if (conn == null)
             return;
 
         try {
-            if (_commit)
-                _conn.commit();
+            if (type == TYPE_TRANSACTIONAL || type == TYPE_CONTIGUOUS)
+                conn.commit();
         } catch (SQLException se) {
             throw SQLExceptions.getStore(se);
         } finally {
-            try {
-                _conn.close();
-            } catch (SQLException se) {
-            }
-            _conn = null;
-            _commit = false;
+            try { conn.close(); } catch (SQLException se) {}
         }
     }
 }

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java?view=diff&rev=448298&r1=448297&r2=448298
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java Wed Sep 20 11:40:28 2006
@@ -44,8 +44,8 @@
 public class ClassTableJDBCSeq 
     extends TableJDBCSeq {
 
-    private static final Localizer _loc = Localizer
-        .forPackage(ClassTableJDBCSeq.class);
+    private static final Localizer _loc = Localizer.forPackage
+        (ClassTableJDBCSeq.class);
 
     private final Map _stats = new HashMap();
     private boolean _ignore = false;
@@ -95,7 +95,7 @@
         _aliases = aliases;
     }
 
-    protected Status getStatus(ClassMapping mapping) {
+    protected synchronized Status getStatus(ClassMapping mapping) {
         if (mapping == null)
             return null;
         String key = getKey(mapping, false);

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java?view=diff&rev=448298&r1=448297&r2=448298
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java Wed Sep 20 11:40:28 2006
@@ -199,8 +199,12 @@
 
     protected Object nextInternal(JDBCStore store, ClassMapping mapping)
         throws SQLException {
-        long next = getSequence(getConnection(store));
-        return Numbers.valueOf(next);
+        Connection conn = getConnection(store);
+        try {
+            return Numbers.valueOf(getSequence(conn));
+        } finally {
+            closeConnection(conn);
+        }
     }
 
     /**

Modified: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java?view=diff&rev=448298&r1=448297&r2=448298
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java (original)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java Wed Sep 20 11:40:28 2006
@@ -213,20 +213,29 @@
             throw new InvalidStateException(_loc.get("bad-seq-type",
                 getClass(), mapping));
 
-        // make sure seq is at least 1, since autoassigned ids of 0 can
-        // conflict with uninitialized values
-        stat.seq = Math.max(stat.seq, 1);
-        if (stat.seq >= stat.max)
+        while (true) {
+            synchronized (stat) {
+                // make sure seq is at least 1, since autoassigned ids of 0 can
+                // conflict with uninitialized values
+                stat.seq = Math.max(stat.seq, 1);
+                if (stat.seq < stat.max)
+                    return Numbers.valueOf(stat.seq++);
+            }
             allocateSequence(store, mapping, stat, _alloc, true);
-        return Numbers.valueOf(stat.seq++);
+        }
     }
 
     protected Object currentInternal(JDBCStore store, ClassMapping mapping)
         throws Exception {
         if (current == null) {
-            long cur = getSequence(mapping, getConnection(store));
-            if (cur != -1)
-                current = Numbers.valueOf(cur);
+            Connection conn = getConnection(store);
+            try {
+                long cur = getSequence(mapping, getConnection(store));
+                if (cur != -1)
+                    current = Numbers.valueOf(cur);
+            } finally {
+                closeConnection(conn);
+            }
         }
         return super.currentInternal(store, mapping);
     }
@@ -235,9 +244,18 @@
         ClassMapping mapping)
         throws SQLException {
         Status stat = getStatus(mapping);
-        if (stat != null && stat.max - stat.seq < count)
-            allocateSequence(store, mapping, stat,
-                count - (int) (stat.max - stat.seq), false);
+        if (stat == null)
+            return;
+
+        while (true) {
+            int available;
+            synchronized (stat) {
+                available = (int) (stat.max - stat.seq);
+                if (available >= count)
+                    return;
+            }
+            allocateSequence(store, mapping, stat, count - available, false);
+        }
     }
 
     /**
@@ -295,40 +313,45 @@
      * Updates the max available sequence value.
      */
     private void allocateSequence(JDBCStore store, ClassMapping mapping,
-        Status stat, int alloc, boolean updateStatSeq) {
+        Status stat, int alloc, boolean updateStatSeq) 
+        throws SQLException {
+        Connection conn = getConnection(store);
+        try { 
+            if (setSequence(mapping, stat, alloc, updateStatSeq, conn))
+                return;
+        } catch (SQLException se) {
+            throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
+                se, _conf.getDBDictionaryInstance());
+        } finally {
+            closeConnection(conn);
+        }
+        
         try {
-            // if the update fails, probably because row doesn't exist yet
-            if (!setSequence(mapping, stat, alloc, updateStatSeq,
-                getConnection(store))) {
-                closeConnection();
-
-                // possible that we might get errors when inserting if
-                // another thread/process is inserting same pk at same time
-                SQLException err = null;
-                Connection conn = _conf.getDataSource2(store.getContext()).
-                    getConnection();
-                try {
-                    insertSequence(mapping, conn);
-                } catch (SQLException se) {
-                    err = se;
-                } finally {
-                    try {
-                        conn.close();
-                    } catch (SQLException se) {
-                    }
-                }
-
-                // now we should be able to update...
-                if (!setSequence(mapping, stat, alloc, updateStatSeq,
-                    getConnection(store)))
-                    throw(err != null) ? err : new SQLException(_loc.get
+            // possible that we might get errors when inserting if
+            // another thread/process is inserting same pk at same time
+            SQLException err = null;
+            conn = _conf.getDataSource2(store.getContext()).getConnection();
+            try {
+                insertSequence(mapping, conn);
+            } catch (SQLException se) {
+                err = se;
+            } finally {
+                try { conn.close(); } catch (SQLException se) {}
+            }
+
+            // now we should be able to update...
+            conn = getConnection(store);
+            try {
+                if (!setSequence(mapping, stat, alloc, updateStatSeq, conn))
+                    throw (err != null) ? err : new SQLException(_loc.get
                         ("no-seq-row", mapping, _table).getMessage());
+            } finally {
+                closeConnection(conn);
             }
-        }
-        catch (SQLException se2) {
+        } catch (SQLException se2) {
             throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
                 se2, _conf.getDBDictionaryInstance());
-        }
+        } 
     }
 
     /**
@@ -362,10 +385,7 @@
             stmnt.executeUpdate();
         } finally {
             if (stmnt != null)
-                try {
-                    stmnt.close();
-                } catch (SQLException se) {
-                }
+                try { stmnt.close(); } catch (SQLException se) {}
             if (!wasAuto)
                 conn.setAutoCommit(false);
         }
@@ -401,14 +421,8 @@
             return dict.getLong(rs, 1);
         } finally {
             if (rs != null)
-                try {
-                    rs.close();
-                } catch (SQLException se) {
-                }
-            try {
-                stmnt.close();
-            } catch (SQLException se) {
-            }
+                try { rs.close(); } catch (SQLException se) {}
+            try { stmnt.close(); } catch (SQLException se) {}
         }
     }
 
@@ -433,8 +447,7 @@
         SQLBuffer where = new SQLBuffer(dict).append(_pkColumn).append(" = ").
             appendValue(pk, _pkColumn);
 
-        // not all databases support locking, so loop until we have a
-        // successful atomic select/update sequence
+        // loop until we have a successful atomic select/update sequence
         long cur = 0;
         PreparedStatement stmnt;
         ResultSet rs;
@@ -459,23 +472,20 @@
                 stmnt = upd.prepareStatement(conn);
                 updates = stmnt.executeUpdate();
             } finally {
-                if (rs != null)
-                    try {
-                        rs.close();
-                    } catch (SQLException se) {
-                    }
+                if (rs != null) 
+                    try { rs.close(); } catch (SQLException se) {}
                 if (stmnt != null)
-                    try {
-                        stmnt.close();
-                    } catch (SQLException se) {
-                    }
+                    try { stmnt.close(); } catch (SQLException se) {}
             }
         }
 
         // setup new sequence range
-        if (updateStatSeq)
-            stat.seq = cur;
-        stat.max = cur + inc;
+        synchronized (stat) {
+            if (updateStatSeq && stat.seq < cur)
+                stat.seq = cur;
+            if (stat.max < cur + inc)
+                stat.max = cur + inc;
+        }
         return true;
     }