You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ol...@apache.org on 2003/02/16 18:28:53 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch BatchConnection.java

olegnitz    2003/02/16 09:28:53

  Modified:    src/java/org/apache/ojb/broker/util/batch
                        BatchConnection.java
  Log:
  Greately improved the algorithm of grouping statements into batches:
  it is supposed to work correctly absolutely in all cases :-)
  
  Revision  Changes    Path
  1.8       +139 -12   db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnection.java
  
  Index: BatchConnection.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnection.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- BatchConnection.java	24 Jan 2003 21:52:48 -0000	1.7
  +++ BatchConnection.java	16 Feb 2003 17:28:53 -0000	1.8
  @@ -62,7 +62,9 @@
   import java.sql.SQLException;
   import java.util.ArrayList;
   import java.util.HashMap;
  +import java.util.HashSet;
   import java.util.Iterator;
  +import java.util.List;
   
   //#ifdef JDK13
   import java.lang.reflect.Proxy;
  @@ -72,6 +74,11 @@
   */
   //#endif
   
  +import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.metadata.ClassDescriptor;
  +import org.apache.ojb.broker.metadata.DescriptorRepository;
  +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
  +
   /**
    * The implementation of {@link java.sql.Connection} which
    * automatically gathers INSERT, UPDATE and DELETE
  @@ -82,13 +89,57 @@
    */
   public class BatchConnection extends WrappedConnection
   {
  +    /**
  +     * Maps PBKey to another HashMap,
  +     * which maps table name to List of related tables (N:1 or 1:1)
  +     */
  +    private static HashMap _pbkeyToFKInfo = new HashMap();
  +
       private boolean _useBatchInserts = true;
       private HashMap _statements = new HashMap();
       private ArrayList _order = new ArrayList();
  +    private HashMap _fkInfo;
  +    private HashSet _deleted;
  +    private HashSet _dontInsert;
   
  -    public BatchConnection(Connection conn)
  +    public BatchConnection(Connection conn, PersistenceBroker broker)
       {
           super(conn);
  +
  +        _fkInfo = (HashMap) _pbkeyToFKInfo.get(broker.getPBKey());
  +        if (_fkInfo != null)
  +        {
  +            return;
  +        }
  +
  +        DescriptorRepository repos = broker.getDescriptorRepository();
  +        _fkInfo = new HashMap();
  +        for (Iterator it = repos.iterator(); it.hasNext(); )
  +        {
  +            ClassDescriptor desc = (ClassDescriptor) it.next();
  +            List ordList = desc.getObjectReferenceDescriptors();
  +
  +            if (ordList != null && !ordList.isEmpty()) {
  +                String tableName = desc.getFullTableName();
  +                HashSet fkTables = (HashSet) _fkInfo.get(tableName);
  +
  +                if (fkTables == null)
  +                {
  +                    fkTables = new HashSet();
  +                    _fkInfo.put(tableName, fkTables);
  +                }
  +
  +                for (Iterator it2 = ordList.iterator(); it2.hasNext(); )
  +                {
  +                    ObjectReferenceDescriptor ord =
  +                            (ObjectReferenceDescriptor) it2.next();
  +                    ClassDescriptor fkDesc =
  +                            repos.getDescriptorFor(ord.getItemClass());
  +                    fkTables.add(fkDesc.getFullTableName());
  +                }
  +            }
  +        }
  +        _pbkeyToFKInfo.put(broker.getPBKey(), _fkInfo);
       }
   
       public void setUseBatchInserts(boolean useBatchInserts)
  @@ -99,17 +150,74 @@
       /**
        * Remember the order of execution
        */
  -    void nextExecuted(String sql)
  +    void nextExecuted(String sql) throws SQLException
       {
  -        if (!_order.contains(sql))
  +        if (_order.contains(sql)) {
  +            return;
  +        }
  +
  +        String sqlCmd = sql.substring(0, 7);
  +        String rest = sql.substring(
  +                sqlCmd.equals("UPDATE ") ? 7    // "UPDATE "
  +                                         : 12); // "INSERT INTO " or "DELETE FROM "
  +        String tableName = rest.substring(0, rest.indexOf(' '));
  +        HashSet fkTables = (HashSet) _fkInfo.get(tableName);
  +
  +        if (sqlCmd.equals("INSERT "))
           {
  -            _order.add(sql);
  +            if (_dontInsert != null && _dontInsert.contains(tableName))
  +            {
  +                // one of the previous INSERTs contained a table
  +                // that references this table.
  +                // Let's execute that previous INSERT right now so that
  +                // in the future INSERTs into this table will go first
  +                // in the _order array.
  +                executeBatch();
  +            }
           }
  -        else if (sql.startsWith("DELETE "))
  +        else //if (sqlCmd.equals("DELETE ") || sqlCmd.equals("UPDATE "))
           {
  -            // Put deletion of master objects after all dependent objects
  -            _order.remove(sql);
  -            _order.add(sql);
  +            // We process UPDATEs in the same way as DELETEs
  +            // because setting FK to NULL in UPDATE is equivalent
  +            // to DELETE from the referential integrity point of view.
  +
  +            if (_deleted != null && fkTables != null)
  +            {
  +                HashSet intersection = (HashSet) _deleted.clone();
  +
  +                intersection.retainAll(fkTables);
  +                if (!intersection.isEmpty())
  +                {
  +                    // one of the previous DELETEs contained a table
  +                    // that is referenced from this table.
  +                    // Let's execute that previous DELETE right now so that
  +                    // in the future DELETEs into this table will go first
  +                    // in the _order array.
  +                    executeBatch();
  +                }
  +            }
  +        }
  +
  +        _order.add(sql);
  +
  +        if (sqlCmd.equals("INSERT "))
  +        {
  +            if (fkTables != null)
  +            {
  +                if (_dontInsert == null)
  +                {
  +                    _dontInsert = new HashSet();
  +                }
  +                _dontInsert.addAll(fkTables);
  +            }
  +        }
  +        else if (sqlCmd.equals("DELETE "))
  +        {
  +            if (_deleted == null)
  +            {
  +                _deleted = new HashSet();
  +            }
  +            _deleted.add(tableName);
           }
       }
   
  @@ -182,7 +290,16 @@
           finally
           {
               _order.clear();
  -            _statements.clear();
  +
  +            if (_dontInsert != null)
  +            {
  +                _dontInsert.clear();
  +            }
  +
  +            if (_deleted != null)
  +            {
  +                _deleted.clear();
  +            }
           }
       }
   
  @@ -190,18 +307,28 @@
       {
           _order.clear();
           _statements.clear();
  +
  +        if (_dontInsert != null)
  +        {
  +            _dontInsert.clear();
  +        }
  +
  +        if (_deleted != null)
  +        {
  +            _deleted.clear();
  +        }
       }
   
       public void commit() throws SQLException
       {
           executeBatch();
  +        _statements.clear();
           getDelegate().commit();
       }
   
       public void rollback() throws SQLException
       {
  -        _order.clear();
  -        _statements.clear();
  +        clearBatch();
           getDelegate().rollback();
       }
   }
  
  
  

Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch BatchConnection.java

Posted by Oleg Nitz <on...@ukr.net>.
On Friday 21 February 2003 00:30, Oleg Nitz wrote:
> I thought more on this... I there were some listener mechanism for metadata
Typo:              I meant "If there were..."

> changes I could refresh _pbkeyToFKInfo on each global change.


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch BatchConnection.java

Posted by Oleg Nitz <on...@ukr.net>.
Hi Armin,

I thought more on this... I there were some listener mechanism for metadata 
changes I could refresh _pbkeyToFKInfo on each global change.
Also I could add ThreadLocal version of it to reflect per thread changes.
Of course this makes sense only if metadata changes are done between 
transactions, no changes during transaction.

Regards,
 Oleg

On Monday 17 February 2003 16:56, Armin Waibel wrote:
> Hi Oleg,
>
> looks very smart!
> But there is one problem,  the static HashMap
> _pbkeyToFKInfo.
> In current version of OJB we only use one
> global DescriptorRepository for all databases (different PBKey),
> but it is allowed to change metadata at runtime (global and per thread),
> thus metadata of a PB instance could change. Thus it's not allowed to
> hold references of object metadata.
>
> Maybe we should discuss if it is necessary to allow
> per thread modifications of metadata?
>
> regards,
> Armin
>
> ----- Original Message -----
> From: <ol...@apache.org>
> To: <db...@apache.org>
> Sent: Sunday, February 16, 2003 6:28 PM
> Subject: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch
> BatchConnection.java
>
> > olegnitz    2003/02/16 09:28:53
> >
> >   Modified:    src/java/org/apache/ojb/broker/util/batch
> >                         BatchConnection.java
> >   Log:
> >   Greately improved the algorithm of grouping statements into batches:
> >   it is supposed to work correctly absolutely in all cases :-)
> >
> >   Revision  Changes    Path
> >   1.8       +139 -12
>
> db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnection.java
>
> >   Index: BatchConnection.java
> >   ===================================================================
> >   RCS file:
>
> /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnecti
> on.java,v
>
> >   retrieving revision 1.7
> >   retrieving revision 1.8
> >   diff -u -r1.7 -r1.8
> >   --- BatchConnection.java 24 Jan 2003 21:52:48 -0000 1.7
> >   +++ BatchConnection.java 16 Feb 2003 17:28:53 -0000 1.8
> >   @@ -62,7 +62,9 @@
> >    import java.sql.SQLException;
> >    import java.util.ArrayList;
> >    import java.util.HashMap;
> >   +import java.util.HashSet;
> >    import java.util.Iterator;
> >   +import java.util.List;
> >
> >    file://#ifdef JDK13
> >    import java.lang.reflect.Proxy;
> >   @@ -72,6 +74,11 @@
> >    */
> >    file://#endif
> >
> >   +import org.apache.ojb.broker.PersistenceBroker;
> >   +import org.apache.ojb.broker.metadata.ClassDescriptor;
> >   +import org.apache.ojb.broker.metadata.DescriptorRepository;
> >   +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
> >   +
> >    /**
> >     * The implementation of {@link java.sql.Connection} which
> >     * automatically gathers INSERT, UPDATE and DELETE
> >   @@ -82,13 +89,57 @@
> >     */
> >    public class BatchConnection extends WrappedConnection
> >    {
> >   +    /**
> >   +     * Maps PBKey to another HashMap,
> >   +     * which maps table name to List of related tables (N:1 or 1:1)
> >   +     */
> >   +    private static HashMap _pbkeyToFKInfo = new HashMap();
> >   +
> >        private boolean _useBatchInserts = true;
> >        private HashMap _statements = new HashMap();
> >        private ArrayList _order = new ArrayList();
> >   +    private HashMap _fkInfo;
> >   +    private HashSet _deleted;
> >   +    private HashSet _dontInsert;
> >
> >   -    public BatchConnection(Connection conn)
> >   +    public BatchConnection(Connection conn, PersistenceBroker
>
> broker)
>
> >        {
> >            super(conn);
> >   +
> >   +        _fkInfo = (HashMap) _pbkeyToFKInfo.get(broker.getPBKey());
> >   +        if (_fkInfo != null)
> >   +        {
> >   +            return;
> >   +        }
> >   +
> >   +        DescriptorRepository repos =
>
> broker.getDescriptorRepository();
>
> >   +        _fkInfo = new HashMap();
> >   +        for (Iterator it = repos.iterator(); it.hasNext(); )
> >   +        {
> >   +            ClassDescriptor desc = (ClassDescriptor) it.next();
> >   +            List ordList = desc.getObjectReferenceDescriptors();
> >   +
> >   +            if (ordList != null && !ordList.isEmpty()) {
> >   +                String tableName = desc.getFullTableName();
> >   +                HashSet fkTables = (HashSet)
>
> _fkInfo.get(tableName);
>
> >   +
> >   +                if (fkTables == null)
> >   +                {
> >   +                    fkTables = new HashSet();
> >   +                    _fkInfo.put(tableName, fkTables);
> >   +                }
> >   +
> >   +                for (Iterator it2 = ordList.iterator();
>
> it2.hasNext(); )
>
> >   +                {
> >   +                    ObjectReferenceDescriptor ord =
> >   +                            (ObjectReferenceDescriptor) it2.next();
> >   +                    ClassDescriptor fkDesc =
> >   +
>
> repos.getDescriptorFor(ord.getItemClass());
>
> >   +                    fkTables.add(fkDesc.getFullTableName());
> >   +                }
> >   +            }
> >   +        }
> >   +        _pbkeyToFKInfo.put(broker.getPBKey(), _fkInfo);
> >        }
> >
> >        public void setUseBatchInserts(boolean useBatchInserts)
> >   @@ -99,17 +150,74 @@
> >        /**
> >         * Remember the order of execution
> >         */
> >   -    void nextExecuted(String sql)
> >   +    void nextExecuted(String sql) throws SQLException
> >        {
> >   -        if (!_order.contains(sql))
> >   +        if (_order.contains(sql)) {
> >   +            return;
> >   +        }
> >   +
> >   +        String sqlCmd = sql.substring(0, 7);
> >   +        String rest = sql.substring(
> >   +                sqlCmd.equals("UPDATE ") ? 7    // "UPDATE "
> >   +                                         : 12); // "INSERT INTO "
>
> or "DELETE FROM "
>
> >   +        String tableName = rest.substring(0, rest.indexOf(' '));
> >   +        HashSet fkTables = (HashSet) _fkInfo.get(tableName);
> >   +
> >   +        if (sqlCmd.equals("INSERT "))
> >            {
> >   -            _order.add(sql);
> >   +            if (_dontInsert != null &&
>
> _dontInsert.contains(tableName))
>
> >   +            {
> >   +                // one of the previous INSERTs contained a table
> >   +                // that references this table.
> >   +                // Let's execute that previous INSERT right now so
>
> that
>
> >   +                // in the future INSERTs into this table will go
>
> first
>
> >   +                // in the _order array.
> >   +                executeBatch();
> >   +            }
> >            }
> >   -        else if (sql.startsWith("DELETE "))
> >   +        else file://if (sqlCmd.equals("DELETE ") ||
>
> sqlCmd.equals("UPDATE "))
>
> >            {
> >   -            // Put deletion of master objects after all dependent
>
> objects
>
> >   -            _order.remove(sql);
> >   -            _order.add(sql);
> >   +            // We process UPDATEs in the same way as DELETEs
> >   +            // because setting FK to NULL in UPDATE is equivalent
> >   +            // to DELETE from the referential integrity point of
>
> view.
>
> >   +
> >   +            if (_deleted != null && fkTables != null)
> >   +            {
> >   +                HashSet intersection = (HashSet) _deleted.clone();
> >   +
> >   +                intersection.retainAll(fkTables);
> >   +                if (!intersection.isEmpty())
> >   +                {
> >   +                    // one of the previous DELETEs contained a
>
> table
>
> >   +                    // that is referenced from this table.
> >   +                    // Let's execute that previous DELETE right now
>
> so that
>
> >   +                    // in the future DELETEs into this table will
>
> go first
>
> >   +                    // in the _order array.
> >   +                    executeBatch();
> >   +                }
> >   +            }
> >   +        }
> >   +
> >   +        _order.add(sql);
> >   +
> >   +        if (sqlCmd.equals("INSERT "))
> >   +        {
> >   +            if (fkTables != null)
> >   +            {
> >   +                if (_dontInsert == null)
> >   +                {
> >   +                    _dontInsert = new HashSet();
> >   +                }
> >   +                _dontInsert.addAll(fkTables);
> >   +            }
> >   +        }
> >   +        else if (sqlCmd.equals("DELETE "))
> >   +        {
> >   +            if (_deleted == null)
> >   +            {
> >   +                _deleted = new HashSet();
> >   +            }
> >   +            _deleted.add(tableName);
> >            }
> >        }
> >
> >   @@ -182,7 +290,16 @@
> >            finally
> >            {
> >                _order.clear();
> >   -            _statements.clear();
> >   +
> >   +            if (_dontInsert != null)
> >   +            {
> >   +                _dontInsert.clear();
> >   +            }
> >   +
> >   +            if (_deleted != null)
> >   +            {
> >   +                _deleted.clear();
> >   +            }
> >            }
> >        }
> >
> >   @@ -190,18 +307,28 @@
> >        {
> >            _order.clear();
> >            _statements.clear();
> >   +
> >   +        if (_dontInsert != null)
> >   +        {
> >   +            _dontInsert.clear();
> >   +        }
> >   +
> >   +        if (_deleted != null)
> >   +        {
> >   +            _deleted.clear();
> >   +        }
> >        }
> >
> >        public void commit() throws SQLException
> >        {
> >            executeBatch();
> >   +        _statements.clear();
> >            getDelegate().commit();
> >        }
> >
> >        public void rollback() throws SQLException
> >        {
> >   -        _order.clear();
> >   -        _statements.clear();
> >   +        clearBatch();
> >            getDelegate().rollback();
> >        }
> >    }
> >
> >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> > For additional commands, e-mail: ojb-dev-help@db.apache.org
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch BatchConnection.java

Posted by Oleg Nitz <on...@ukr.net>.
Armin,

please, don't tell anyone about the possible problems! :-)
That was rather hard task to solve problems with all possible static schemas! 
If one would change table relations at runtime, he would better forget about 
batch updates at all!!!

Oleg

On Monday 17 February 2003 16:56, Armin Waibel wrote:
> Hi Oleg,
>
> looks very smart!
> But there is one problem,  the static HashMap
> _pbkeyToFKInfo.
> In current version of OJB we only use one
> global DescriptorRepository for all databases (different PBKey),
> but it is allowed to change metadata at runtime (global and per thread),
> thus metadata of a PB instance could change. Thus it's not allowed to
> hold references of object metadata.
>
> Maybe we should discuss if it is necessary to allow
> per thread modifications of metadata?
>
> regards,
> Armin
>
> ----- Original Message -----
> From: <ol...@apache.org>
> To: <db...@apache.org>
> Sent: Sunday, February 16, 2003 6:28 PM
> Subject: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch
> BatchConnection.java
>
> > olegnitz    2003/02/16 09:28:53
> >
> >   Modified:    src/java/org/apache/ojb/broker/util/batch
> >                         BatchConnection.java
> >   Log:
> >   Greately improved the algorithm of grouping statements into batches:
> >   it is supposed to work correctly absolutely in all cases :-)
> >
> >   Revision  Changes    Path
> >   1.8       +139 -12
>
> db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnection.java
>
> >   Index: BatchConnection.java
> >   ===================================================================
> >   RCS file:
>
> /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnecti
> on.java,v
>
> >   retrieving revision 1.7
> >   retrieving revision 1.8
> >   diff -u -r1.7 -r1.8
> >   --- BatchConnection.java 24 Jan 2003 21:52:48 -0000 1.7
> >   +++ BatchConnection.java 16 Feb 2003 17:28:53 -0000 1.8
> >   @@ -62,7 +62,9 @@
> >    import java.sql.SQLException;
> >    import java.util.ArrayList;
> >    import java.util.HashMap;
> >   +import java.util.HashSet;
> >    import java.util.Iterator;
> >   +import java.util.List;
> >
> >    file://#ifdef JDK13
> >    import java.lang.reflect.Proxy;
> >   @@ -72,6 +74,11 @@
> >    */
> >    file://#endif
> >
> >   +import org.apache.ojb.broker.PersistenceBroker;
> >   +import org.apache.ojb.broker.metadata.ClassDescriptor;
> >   +import org.apache.ojb.broker.metadata.DescriptorRepository;
> >   +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
> >   +
> >    /**
> >     * The implementation of {@link java.sql.Connection} which
> >     * automatically gathers INSERT, UPDATE and DELETE
> >   @@ -82,13 +89,57 @@
> >     */
> >    public class BatchConnection extends WrappedConnection
> >    {
> >   +    /**
> >   +     * Maps PBKey to another HashMap,
> >   +     * which maps table name to List of related tables (N:1 or 1:1)
> >   +     */
> >   +    private static HashMap _pbkeyToFKInfo = new HashMap();
> >   +
> >        private boolean _useBatchInserts = true;
> >        private HashMap _statements = new HashMap();
> >        private ArrayList _order = new ArrayList();
> >   +    private HashMap _fkInfo;
> >   +    private HashSet _deleted;
> >   +    private HashSet _dontInsert;
> >
> >   -    public BatchConnection(Connection conn)
> >   +    public BatchConnection(Connection conn, PersistenceBroker
>
> broker)
>
> >        {
> >            super(conn);
> >   +
> >   +        _fkInfo = (HashMap) _pbkeyToFKInfo.get(broker.getPBKey());
> >   +        if (_fkInfo != null)
> >   +        {
> >   +            return;
> >   +        }
> >   +
> >   +        DescriptorRepository repos =
>
> broker.getDescriptorRepository();
>
> >   +        _fkInfo = new HashMap();
> >   +        for (Iterator it = repos.iterator(); it.hasNext(); )
> >   +        {
> >   +            ClassDescriptor desc = (ClassDescriptor) it.next();
> >   +            List ordList = desc.getObjectReferenceDescriptors();
> >   +
> >   +            if (ordList != null && !ordList.isEmpty()) {
> >   +                String tableName = desc.getFullTableName();
> >   +                HashSet fkTables = (HashSet)
>
> _fkInfo.get(tableName);
>
> >   +
> >   +                if (fkTables == null)
> >   +                {
> >   +                    fkTables = new HashSet();
> >   +                    _fkInfo.put(tableName, fkTables);
> >   +                }
> >   +
> >   +                for (Iterator it2 = ordList.iterator();
>
> it2.hasNext(); )
>
> >   +                {
> >   +                    ObjectReferenceDescriptor ord =
> >   +                            (ObjectReferenceDescriptor) it2.next();
> >   +                    ClassDescriptor fkDesc =
> >   +
>
> repos.getDescriptorFor(ord.getItemClass());
>
> >   +                    fkTables.add(fkDesc.getFullTableName());
> >   +                }
> >   +            }
> >   +        }
> >   +        _pbkeyToFKInfo.put(broker.getPBKey(), _fkInfo);
> >        }
> >
> >        public void setUseBatchInserts(boolean useBatchInserts)
> >   @@ -99,17 +150,74 @@
> >        /**
> >         * Remember the order of execution
> >         */
> >   -    void nextExecuted(String sql)
> >   +    void nextExecuted(String sql) throws SQLException
> >        {
> >   -        if (!_order.contains(sql))
> >   +        if (_order.contains(sql)) {
> >   +            return;
> >   +        }
> >   +
> >   +        String sqlCmd = sql.substring(0, 7);
> >   +        String rest = sql.substring(
> >   +                sqlCmd.equals("UPDATE ") ? 7    // "UPDATE "
> >   +                                         : 12); // "INSERT INTO "
>
> or "DELETE FROM "
>
> >   +        String tableName = rest.substring(0, rest.indexOf(' '));
> >   +        HashSet fkTables = (HashSet) _fkInfo.get(tableName);
> >   +
> >   +        if (sqlCmd.equals("INSERT "))
> >            {
> >   -            _order.add(sql);
> >   +            if (_dontInsert != null &&
>
> _dontInsert.contains(tableName))
>
> >   +            {
> >   +                // one of the previous INSERTs contained a table
> >   +                // that references this table.
> >   +                // Let's execute that previous INSERT right now so
>
> that
>
> >   +                // in the future INSERTs into this table will go
>
> first
>
> >   +                // in the _order array.
> >   +                executeBatch();
> >   +            }
> >            }
> >   -        else if (sql.startsWith("DELETE "))
> >   +        else file://if (sqlCmd.equals("DELETE ") ||
>
> sqlCmd.equals("UPDATE "))
>
> >            {
> >   -            // Put deletion of master objects after all dependent
>
> objects
>
> >   -            _order.remove(sql);
> >   -            _order.add(sql);
> >   +            // We process UPDATEs in the same way as DELETEs
> >   +            // because setting FK to NULL in UPDATE is equivalent
> >   +            // to DELETE from the referential integrity point of
>
> view.
>
> >   +
> >   +            if (_deleted != null && fkTables != null)
> >   +            {
> >   +                HashSet intersection = (HashSet) _deleted.clone();
> >   +
> >   +                intersection.retainAll(fkTables);
> >   +                if (!intersection.isEmpty())
> >   +                {
> >   +                    // one of the previous DELETEs contained a
>
> table
>
> >   +                    // that is referenced from this table.
> >   +                    // Let's execute that previous DELETE right now
>
> so that
>
> >   +                    // in the future DELETEs into this table will
>
> go first
>
> >   +                    // in the _order array.
> >   +                    executeBatch();
> >   +                }
> >   +            }
> >   +        }
> >   +
> >   +        _order.add(sql);
> >   +
> >   +        if (sqlCmd.equals("INSERT "))
> >   +        {
> >   +            if (fkTables != null)
> >   +            {
> >   +                if (_dontInsert == null)
> >   +                {
> >   +                    _dontInsert = new HashSet();
> >   +                }
> >   +                _dontInsert.addAll(fkTables);
> >   +            }
> >   +        }
> >   +        else if (sqlCmd.equals("DELETE "))
> >   +        {
> >   +            if (_deleted == null)
> >   +            {
> >   +                _deleted = new HashSet();
> >   +            }
> >   +            _deleted.add(tableName);
> >            }
> >        }
> >
> >   @@ -182,7 +290,16 @@
> >            finally
> >            {
> >                _order.clear();
> >   -            _statements.clear();
> >   +
> >   +            if (_dontInsert != null)
> >   +            {
> >   +                _dontInsert.clear();
> >   +            }
> >   +
> >   +            if (_deleted != null)
> >   +            {
> >   +                _deleted.clear();
> >   +            }
> >            }
> >        }
> >
> >   @@ -190,18 +307,28 @@
> >        {
> >            _order.clear();
> >            _statements.clear();
> >   +
> >   +        if (_dontInsert != null)
> >   +        {
> >   +            _dontInsert.clear();
> >   +        }
> >   +
> >   +        if (_deleted != null)
> >   +        {
> >   +            _deleted.clear();
> >   +        }
> >        }
> >
> >        public void commit() throws SQLException
> >        {
> >            executeBatch();
> >   +        _statements.clear();
> >            getDelegate().commit();
> >        }
> >
> >        public void rollback() throws SQLException
> >        {
> >   -        _order.clear();
> >   -        _statements.clear();
> >   +        clearBatch();
> >            getDelegate().rollback();
> >        }
> >    }
> >
> >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> > For additional commands, e-mail: ojb-dev-help@db.apache.org
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> For additional commands, e-mail: ojb-dev-help@db.apache.org


Re: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch BatchConnection.java

Posted by Armin Waibel <ar...@code-au-lait.de>.
Hi Oleg,

looks very smart!
But there is one problem,  the static HashMap
_pbkeyToFKInfo.
In current version of OJB we only use one
global DescriptorRepository for all databases (different PBKey),
but it is allowed to change metadata at runtime (global and per thread),
thus metadata of a PB instance could change. Thus it's not allowed to
hold references of object metadata.

Maybe we should discuss if it is necessary to allow
per thread modifications of metadata?

regards,
Armin

----- Original Message -----
From: <ol...@apache.org>
To: <db...@apache.org>
Sent: Sunday, February 16, 2003 6:28 PM
Subject: cvs commit: db-ojb/src/java/org/apache/ojb/broker/util/batch
BatchConnection.java


> olegnitz    2003/02/16 09:28:53
>
>   Modified:    src/java/org/apache/ojb/broker/util/batch
>                         BatchConnection.java
>   Log:
>   Greately improved the algorithm of grouping statements into batches:
>   it is supposed to work correctly absolutely in all cases :-)
>
>   Revision  Changes    Path
>   1.8       +139 -12
db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnection.java
>
>   Index: BatchConnection.java
>   ===================================================================
>   RCS file:
/home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/batch/BatchConnecti
on.java,v
>   retrieving revision 1.7
>   retrieving revision 1.8
>   diff -u -r1.7 -r1.8
>   --- BatchConnection.java 24 Jan 2003 21:52:48 -0000 1.7
>   +++ BatchConnection.java 16 Feb 2003 17:28:53 -0000 1.8
>   @@ -62,7 +62,9 @@
>    import java.sql.SQLException;
>    import java.util.ArrayList;
>    import java.util.HashMap;
>   +import java.util.HashSet;
>    import java.util.Iterator;
>   +import java.util.List;
>
>    file://#ifdef JDK13
>    import java.lang.reflect.Proxy;
>   @@ -72,6 +74,11 @@
>    */
>    file://#endif
>
>   +import org.apache.ojb.broker.PersistenceBroker;
>   +import org.apache.ojb.broker.metadata.ClassDescriptor;
>   +import org.apache.ojb.broker.metadata.DescriptorRepository;
>   +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
>   +
>    /**
>     * The implementation of {@link java.sql.Connection} which
>     * automatically gathers INSERT, UPDATE and DELETE
>   @@ -82,13 +89,57 @@
>     */
>    public class BatchConnection extends WrappedConnection
>    {
>   +    /**
>   +     * Maps PBKey to another HashMap,
>   +     * which maps table name to List of related tables (N:1 or 1:1)
>   +     */
>   +    private static HashMap _pbkeyToFKInfo = new HashMap();
>   +
>        private boolean _useBatchInserts = true;
>        private HashMap _statements = new HashMap();
>        private ArrayList _order = new ArrayList();
>   +    private HashMap _fkInfo;
>   +    private HashSet _deleted;
>   +    private HashSet _dontInsert;
>
>   -    public BatchConnection(Connection conn)
>   +    public BatchConnection(Connection conn, PersistenceBroker
broker)
>        {
>            super(conn);
>   +
>   +        _fkInfo = (HashMap) _pbkeyToFKInfo.get(broker.getPBKey());
>   +        if (_fkInfo != null)
>   +        {
>   +            return;
>   +        }
>   +
>   +        DescriptorRepository repos =
broker.getDescriptorRepository();
>   +        _fkInfo = new HashMap();
>   +        for (Iterator it = repos.iterator(); it.hasNext(); )
>   +        {
>   +            ClassDescriptor desc = (ClassDescriptor) it.next();
>   +            List ordList = desc.getObjectReferenceDescriptors();
>   +
>   +            if (ordList != null && !ordList.isEmpty()) {
>   +                String tableName = desc.getFullTableName();
>   +                HashSet fkTables = (HashSet)
_fkInfo.get(tableName);
>   +
>   +                if (fkTables == null)
>   +                {
>   +                    fkTables = new HashSet();
>   +                    _fkInfo.put(tableName, fkTables);
>   +                }
>   +
>   +                for (Iterator it2 = ordList.iterator();
it2.hasNext(); )
>   +                {
>   +                    ObjectReferenceDescriptor ord =
>   +                            (ObjectReferenceDescriptor) it2.next();
>   +                    ClassDescriptor fkDesc =
>   +
repos.getDescriptorFor(ord.getItemClass());
>   +                    fkTables.add(fkDesc.getFullTableName());
>   +                }
>   +            }
>   +        }
>   +        _pbkeyToFKInfo.put(broker.getPBKey(), _fkInfo);
>        }
>
>        public void setUseBatchInserts(boolean useBatchInserts)
>   @@ -99,17 +150,74 @@
>        /**
>         * Remember the order of execution
>         */
>   -    void nextExecuted(String sql)
>   +    void nextExecuted(String sql) throws SQLException
>        {
>   -        if (!_order.contains(sql))
>   +        if (_order.contains(sql)) {
>   +            return;
>   +        }
>   +
>   +        String sqlCmd = sql.substring(0, 7);
>   +        String rest = sql.substring(
>   +                sqlCmd.equals("UPDATE ") ? 7    // "UPDATE "
>   +                                         : 12); // "INSERT INTO "
or "DELETE FROM "
>   +        String tableName = rest.substring(0, rest.indexOf(' '));
>   +        HashSet fkTables = (HashSet) _fkInfo.get(tableName);
>   +
>   +        if (sqlCmd.equals("INSERT "))
>            {
>   -            _order.add(sql);
>   +            if (_dontInsert != null &&
_dontInsert.contains(tableName))
>   +            {
>   +                // one of the previous INSERTs contained a table
>   +                // that references this table.
>   +                // Let's execute that previous INSERT right now so
that
>   +                // in the future INSERTs into this table will go
first
>   +                // in the _order array.
>   +                executeBatch();
>   +            }
>            }
>   -        else if (sql.startsWith("DELETE "))
>   +        else file://if (sqlCmd.equals("DELETE ") ||
sqlCmd.equals("UPDATE "))
>            {
>   -            // Put deletion of master objects after all dependent
objects
>   -            _order.remove(sql);
>   -            _order.add(sql);
>   +            // We process UPDATEs in the same way as DELETEs
>   +            // because setting FK to NULL in UPDATE is equivalent
>   +            // to DELETE from the referential integrity point of
view.
>   +
>   +            if (_deleted != null && fkTables != null)
>   +            {
>   +                HashSet intersection = (HashSet) _deleted.clone();
>   +
>   +                intersection.retainAll(fkTables);
>   +                if (!intersection.isEmpty())
>   +                {
>   +                    // one of the previous DELETEs contained a
table
>   +                    // that is referenced from this table.
>   +                    // Let's execute that previous DELETE right now
so that
>   +                    // in the future DELETEs into this table will
go first
>   +                    // in the _order array.
>   +                    executeBatch();
>   +                }
>   +            }
>   +        }
>   +
>   +        _order.add(sql);
>   +
>   +        if (sqlCmd.equals("INSERT "))
>   +        {
>   +            if (fkTables != null)
>   +            {
>   +                if (_dontInsert == null)
>   +                {
>   +                    _dontInsert = new HashSet();
>   +                }
>   +                _dontInsert.addAll(fkTables);
>   +            }
>   +        }
>   +        else if (sqlCmd.equals("DELETE "))
>   +        {
>   +            if (_deleted == null)
>   +            {
>   +                _deleted = new HashSet();
>   +            }
>   +            _deleted.add(tableName);
>            }
>        }
>
>   @@ -182,7 +290,16 @@
>            finally
>            {
>                _order.clear();
>   -            _statements.clear();
>   +
>   +            if (_dontInsert != null)
>   +            {
>   +                _dontInsert.clear();
>   +            }
>   +
>   +            if (_deleted != null)
>   +            {
>   +                _deleted.clear();
>   +            }
>            }
>        }
>
>   @@ -190,18 +307,28 @@
>        {
>            _order.clear();
>            _statements.clear();
>   +
>   +        if (_dontInsert != null)
>   +        {
>   +            _dontInsert.clear();
>   +        }
>   +
>   +        if (_deleted != null)
>   +        {
>   +            _deleted.clear();
>   +        }
>        }
>
>        public void commit() throws SQLException
>        {
>            executeBatch();
>   +        _statements.clear();
>            getDelegate().commit();
>        }
>
>        public void rollback() throws SQLException
>        {
>   -        _order.clear();
>   -        _statements.clear();
>   +        clearBatch();
>            getDelegate().rollback();
>        }
>    }
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
> For additional commands, e-mail: ojb-dev-help@db.apache.org
>
>
>