svn commit: r1621438 - in /ofbiz/trunk/framework: common/config/general.properties entity/src/org/ofbiz/entity/GenericDelegator.java entity/src/org/ofbiz/entity/test/EntityTestSuite.java entity/src/org/ofbiz/entity/util/SequenceUtil.java

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r1621438 - in /ofbiz/trunk/framework: common/config/general.properties entity/src/org/ofbiz/entity/GenericDelegator.java entity/src/org/ofbiz/entity/test/EntityTestSuite.java entity/src/org/ofbiz/entity/util/SequenceUtil.java

jacopoc
Author: jacopoc
Date: Sat Aug 30 09:17:07 2014
New Revision: 1621438

URL: http://svn.apache.org/r1621438
Log:
Completely refactored the SequenceUtil class:
* the class is now thread safe
* the class is now cleaner (no references to delegator etc...)
* replaced the collision detection algorithm with a simpler/reliable/efficient one based on: update with no changes (to get a lock) + select + update (to increase the last sequence id)
* removed ugly special code for "clusters" that is no more needed


Modified:
    ofbiz/trunk/framework/common/config/general.properties
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
    ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java

Modified: ofbiz/trunk/framework/common/config/general.properties
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/common/config/general.properties?rev=1621438&r1=1621437&r2=1621438&view=diff
==============================================================================
--- ofbiz/trunk/framework/common/config/general.properties (original)
+++ ofbiz/trunk/framework/common/config/general.properties Sat Aug 30 09:17:07 2014
@@ -130,7 +130,3 @@ mail.spam.value=YES
 
 # -- Y if you want to display the multi-tenant textbox in the login page and install specify components which related to each tenant
 multitenant=N
-
-# -- Y if you use a cluster. Most of the time this should not be needed. Setting distributed-cache-clear-enabled="true" is enough
-# -- to guarantee no sequenceIds duplicates. See OFBIZ-2353 and look for "DCC" in wiki for details
-clustered=N

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1621438&r1=1621437&r2=1621438&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Sat Aug 30 09:17:07 2014
@@ -48,6 +48,7 @@ import org.ofbiz.base.util.UtilFormatOut
 import org.ofbiz.base.util.UtilGenerics;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilObject;
+import org.ofbiz.base.util.UtilProperties;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.base.util.UtilXml;
 import org.ofbiz.entity.cache.Cache;
@@ -72,7 +73,6 @@ import org.ofbiz.entity.model.ModelRelat
 import org.ofbiz.entity.model.ModelViewEntity;
 import org.ofbiz.entity.serialize.SerializeException;
 import org.ofbiz.entity.serialize.XmlSerializer;
-import org.ofbiz.entity.transaction.GenericTransactionException;
 import org.ofbiz.entity.transaction.TransactionUtil;
 import org.ofbiz.entity.util.DistributedCacheClear;
 import org.ofbiz.entity.util.EntityCrypto;
@@ -2533,24 +2533,14 @@ public class GenericDelegator implements
     /* (non-Javadoc)
      * @see org.ofbiz.entity.Delegator#getNextSeqIdLong(java.lang.String, long)
      */
-    @Override
     public Long getNextSeqIdLong(String seqName, long staggerMax) {
-        boolean beganTransaction = false;
         try {
-            if (alwaysUseTransaction) {
-                beganTransaction = TransactionUtil.begin();
-            }
-
             SequenceUtil sequencer = this.AtomicRefSequencer.get();
             if (sequencer == null) {
                 ModelEntity seqEntity = this.getModelEntity("SequenceValueItem");
-                sequencer = new SequenceUtil(this, this.getEntityHelperInfo("SequenceValueItem"), seqEntity, "seqName", "seqId");
-                try {
-                    if (!AtomicRefSequencer.compareAndSet(null, sequencer)) {
-                        sequencer = this.AtomicRefSequencer.get();
-                    }
-                } catch (Exception e) {
-                    throw new IllegalStateException("Error thrown while creating AtomicReference<SequenceUtil> in getNextSeqIdLong()" + e);
+                sequencer = new SequenceUtil(this.getEntityHelperInfo("SequenceValueItem"), seqEntity, "seqName", "seqId");
+                if (!AtomicRefSequencer.compareAndSet(null, sequencer)) {
+                    sequencer = this.AtomicRefSequencer.get();
                 }
             }
 
@@ -2558,16 +2548,10 @@ public class GenericDelegator implements
             ModelEntity seqModelEntity = this.getModelEntity(seqName);
 
             Long newSeqId = sequencer == null ? null : sequencer.getNextSeqId(seqName, staggerMax, seqModelEntity);
-            TransactionUtil.commit(beganTransaction);
             return newSeqId;
         } catch (Exception e) {
             String errMsg = "Failure in getNextSeqIdLong operation for seqName [" + seqName + "]: " + e.toString() + ". Rolling back transaction.";
             Debug.logError(e, errMsg, module);
-            try {
-                TransactionUtil.rollback(beganTransaction, errMsg, e);
-            } catch (GenericTransactionException e1) {
-                Debug.logError(e1, "Exception thrown while rolling back transaction: ", module);
-            }
             throw new GeneralRuntimeException(errMsg, e);
         }
     }

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1621438&r1=1621437&r2=1621438&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java Sat Aug 30 09:17:07 2014
@@ -1093,7 +1093,7 @@ public class EntityTestSuite extends Ent
     }
 
     public void testSequenceValueItem() {
-        SequenceUtil sequencer = new SequenceUtil((GenericDelegator)delegator, delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")),
+        SequenceUtil sequencer = new SequenceUtil(delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")),
                                                   delegator.getModelEntity("SequenceValueItem"),
                                                   "seqName", "seqId");
         UUID id = UUID.randomUUID();
@@ -1108,7 +1108,7 @@ public class EntityTestSuite extends Ent
     }
 
     public void testSequenceValueItemWithConcurrentThreads() {
-        final SequenceUtil sequencer = new SequenceUtil((GenericDelegator)delegator, delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")),
+        final SequenceUtil sequencer = new SequenceUtil(delegator.getGroupHelperInfo(delegator.getEntityGroupName("SequenceValueItem")),
                                                   delegator.getModelEntity("SequenceValueItem"),
                                                   "seqName", "seqId");
         UUID id = UUID.randomUUID();

Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java?rev=1621438&r1=1621437&r2=1621438&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/util/SequenceUtil.java Sat Aug 30 09:17:07 2014
@@ -22,14 +22,12 @@ import java.sql.Connection;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
-import java.util.Hashtable;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import javax.transaction.Transaction;
 
 import org.ofbiz.base.util.Debug;
-import org.ofbiz.base.util.UtilProperties;
-import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.datasource.GenericHelperInfo;
 import org.ofbiz.entity.model.ModelEntity;
@@ -40,20 +38,18 @@ import org.ofbiz.entity.transaction.Tran
 
 /**
  * Sequence Utility to get unique sequences from named sequence banks
- * Uses a collision detection approach to safely get unique sequenced ids in banks from the database
  */
 public class SequenceUtil {
 
     public static final String module = SequenceUtil.class.getName();
 
-    private final Map<String, SequenceBank> sequences = new Hashtable<String, SequenceBank>();
+    private final ConcurrentMap<String, SequenceBank> sequences = new ConcurrentHashMap<String, SequenceBank>();
     private final GenericHelperInfo helperInfo;
     private final String tableName;
     private final String nameColName;
     private final String idColName;
-    private final boolean clustered;
 
-    public SequenceUtil(Delegator delegator, GenericHelperInfo helperInfo, ModelEntity seqEntity, String nameFieldName, String idFieldName) {
+    public SequenceUtil(GenericHelperInfo helperInfo, ModelEntity seqEntity, String nameFieldName, String idFieldName) {
         this.helperInfo = helperInfo;
         if (seqEntity == null) {
             throw new IllegalArgumentException("The sequence model entity was null but is required.");
@@ -73,7 +69,6 @@ public class SequenceUtil {
             throw new IllegalArgumentException("Could not find the field definition for the sequence id field " + idFieldName);
         }
         this.idColName = idField.getColName();
-        clustered = delegator.useDistributedCacheClear() || "Y".equals(UtilProperties.getPropertyValue("general.properties", "clustered"));                
     }
 
     public Long getNextSeqId(String seqName, long staggerMax, ModelEntity seqModelEntity) {
@@ -95,18 +90,14 @@ public class SequenceUtil {
         SequenceBank bank = sequences.get(seqName);
 
         if (bank == null) {
-            synchronized(this) {
-                bank = sequences.get(seqName);
-                if (bank == null) {
-                    long bankSize = SequenceBank.defaultBankSize;
-                    if (seqModelEntity != null && seqModelEntity.getSequenceBankSize() != null) {
-                        bankSize = seqModelEntity.getSequenceBankSize().longValue();
-                        if (bankSize > SequenceBank.maxBankSize) bankSize = SequenceBank.maxBankSize;
-                    }
-                    bank = new SequenceBank(seqName, bankSize);
-                    sequences.put(seqName, bank);
-                }
+            long bankSize = SequenceBank.defaultBankSize;
+            if (seqModelEntity != null && seqModelEntity.getSequenceBankSize() != null) {
+                bankSize = seqModelEntity.getSequenceBankSize().longValue();
+                if (bankSize > SequenceBank.maxBankSize) bankSize = SequenceBank.maxBankSize;
             }
+            bank = new SequenceBank(seqName, bankSize);
+            SequenceBank bankFromCache = sequences.putIfAbsent(seqName, bank);
+            bank = bankFromCache != null ? bankFromCache : bank;
         }
 
         return bank;
@@ -116,43 +107,41 @@ public class SequenceUtil {
         public static final long defaultBankSize = 10;
         public static final long maxBankSize = 5000;
         public static final long startSeqId = 10000;
-        public static final long minWaitMillis = 5;
-        public static final long maxWaitMillis = 50;
-        public static final int maxTries = 5;
 
-        private long curSeqId;
-        private long maxSeqId;
         private final String seqName;
         private final long bankSize;
 
+        private long curSeqId;
+        private long maxSeqId;
+
         private SequenceBank(String seqName, long bankSize) {
             this.seqName = seqName;
             curSeqId = 0;
             maxSeqId = 0;
             this.bankSize = bankSize;
-            fillBank(1);
         }
 
-        private synchronized Long getNextSeqId(long staggerMax) {
+        private Long getNextSeqId(long staggerMax) {
             long stagger = 1;
             if (staggerMax > 1) {
-                stagger = Math.round(Math.random() * staggerMax);
+                stagger = (long)Math.ceil(Math.random() * staggerMax);
                 if (stagger == 0) stagger = 1;
             }
-
-            if ((curSeqId + stagger) <= maxSeqId) {
-                Long retSeqId = Long.valueOf(curSeqId);
-                curSeqId += stagger;
-                return retSeqId;
-            } else {
-                fillBank(stagger);
+            synchronized (this) {
                 if ((curSeqId + stagger) <= maxSeqId) {
                     Long retSeqId = Long.valueOf(curSeqId);
                     curSeqId += stagger;
                     return retSeqId;
                 } else {
-                    Debug.logError("[SequenceUtil.SequenceBank.getNextSeqId] Fill bank failed, returning null", module);
-                    return null;
+                    fillBank(stagger);
+                    if ((curSeqId + stagger) <= maxSeqId) {
+                        Long retSeqId = Long.valueOf(curSeqId);
+                        curSeqId += stagger;
+                        return retSeqId;
+                    } else {
+                        Debug.logError("Fill bank failed, returning null", module);
+                        return null;
+                    }
                 }
             }
         }
@@ -162,9 +151,7 @@ public class SequenceUtil {
             this.fillBank(staggerMax);
         }
 
-        private synchronized void fillBank(long stagger) {
-            //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Starting fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);
-
+        private void fillBank(long stagger) {
             // no need to get a new bank, SeqIds available
             if ((curSeqId + stagger) <= maxSeqId) return;
 
@@ -176,178 +163,120 @@ public class SequenceUtil {
 
             if (bankSize > maxBankSize) bankSize = maxBankSize;
 
-            long val1 = 0;
-            long val2 = 0;
+            Transaction suspendedTransaction = null;
+            try {
+                suspendedTransaction = TransactionUtil.suspend();
+
+                boolean beganTransaction = false;
+                try {
+                    beganTransaction = TransactionUtil.begin();
+
+                    Connection connection = null;
+                    Statement stmt = null;
+                    ResultSet rs = null;
 
-            // NOTE: the fancy ethernet type stuff is for the case where transactions not available, or something funny happens with really sensitive timing (between first select and update, for example)
-            int numTries = 0;
-
-            while (val1 + bankSize != val2) {
-                if (Debug.verboseOn()) Debug.logVerbose("[SequenceUtil.SequenceBank.fillBank] Trying to get a bank of sequenced ids for " +
-                        this.seqName + "; start of loop val1=" + val1 + ", val2=" + val2 + ", bankSize=" + bankSize, module);
-
-                // not sure if this synchronized block is totally necessary, the method is synchronized but it does do a wait/sleep
-                // outside of this block, and this is the really sensitive block, so making sure it is isolated; there is some overhead
-                // to this, but very bad things can happen if we try to do too many of these at once for a single sequencer
-                synchronized (this) {
-                    Transaction suspendedTransaction = null;
                     try {
-                        //if we can suspend the transaction, we'll try to do this in a local manual transaction
-                        suspendedTransaction = TransactionUtil.suspend();
-
-                        boolean beganTransaction = false;
-                        try {
-                            beganTransaction = TransactionUtil.begin();
-
-                            Connection connection = null;
-                            Statement stmt = null;
-                            ResultSet rs = null;
-
-                            try {
-                                connection = TransactionFactoryLoader.getInstance().getConnection(SequenceUtil.this.helperInfo);
-                            } catch (SQLException sqle) {
-                                Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was:" + sqle.toString(), module);
-                                throw sqle;
-                            } catch (GenericEntityException e) {
-                                Debug.logWarning("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database... Error was: " + e.toString(), module);
-                                throw e;
-                            }
-
-                            if (connection == null) {
-                                throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank]: Unable to esablish a connection with the database, connection was null...");
-                            }
-
-                            String sql = null;
-
-                            try {
-                                // we shouldn't need this, and some TX managers complain about it, so not including it: connection.setAutoCommit(false);
-
-                                stmt = connection.createStatement();
-                                if (clustered) {
-                                    sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'" + " FOR UPDATE";                                    
-                                } else {
-                                    sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
-                                }
-                                rs = stmt.executeQuery(sql);
-                                boolean gotVal1 = false;
-                                if (rs.next()) {
-                                    val1 = rs.getLong(SequenceUtil.this.idColName);
-                                    gotVal1 = true;
-                                }
-                                rs.close();
+                        connection = TransactionFactoryLoader.getInstance().getConnection(SequenceUtil.this.helperInfo);
+                    } catch (SQLException sqle) {
+                        Debug.logWarning("Unable to esablish a connection with the database. Error was:" + sqle.toString(), module);
+                        throw sqle;
+                    } catch (GenericEntityException e) {
+                        Debug.logWarning("Unable to esablish a connection with the database. Error was: " + e.toString(), module);
+                        throw e;
+                    }
+                    if (connection == null) {
+                        throw new GenericEntityException("Unable to esablish a connection with the database, connection was null...");
+                    }
 
-                                if (!gotVal1) {
-                                    Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] first select failed: will try to add new row, result set was empty for sequence [" + seqName + "] \nUsed SQL: " + sql + " \n Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);
-                                    sql = "INSERT INTO " + SequenceUtil.this.tableName + " (" + SequenceUtil.this.nameColName + ", " + SequenceUtil.this.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")";
-                                    if (stmt.executeUpdate(sql) <= 0) {
-                                        throw new GenericEntityException("No rows changed when trying insert new sequence row with this SQL: " + sql);
-                                    }
-                                    continue;
-                                }
+                    String sql = null;
+                    try {
+                        stmt = connection.createStatement();
 
-                                sql = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + "+" + bankSize + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
+                        // run an update with no changes to get a lock on the record
+                        sql = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
+                        if (stmt.executeUpdate(sql) <= 0) {
+                            Debug.logWarning("First select failed: will try to add new row, result set was empty for sequence [" + seqName + "] \nUsed SQL: " + sql + " \n ", module);
+                            sql = "INSERT INTO " + SequenceUtil.this.tableName + " (" + SequenceUtil.this.nameColName + ", " + SequenceUtil.this.idColName + ") VALUES ('" + this.seqName + "', " + startSeqId + ")";
+                            if (stmt.executeUpdate(sql) <= 0) {
+                                // insert failed: this means that another thread inserted the record; then retry to run an update with no changes to get a lock on the record
+                                sql = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
                                 if (stmt.executeUpdate(sql) <= 0) {
-                                    throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] update failed, no rows changes for seqName: " + seqName);
-                                }
-                                if (clustered) {
-                                    sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'" + " FOR UPDATE";                                    
-
-                                } else {
-                                    sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
-                                }
-                                rs = stmt.executeQuery(sql);
-                                boolean gotVal2 = false;
-                                if (rs.next()) {
-                                    val2 = rs.getLong(SequenceUtil.this.idColName);
-                                    gotVal2 = true;
-                                }
-
-                                rs.close();
-
-                                if (!gotVal2) {
-                                    throw new GenericEntityException("[SequenceUtil.SequenceBank.fillBank] second select failed: aborting, result set was empty for sequence: " + seqName);
-                                }
-
-                                // got val1 and val2 at this point, if we don't have the right difference between them, force a rollback (with
-                                //setRollbackOnly and NOT with an exception because we don't want to break from the loop, just err out and
-                                //continue), then flow out to allow the wait and loop thing to happen
-                                if (val1 + bankSize != val2) {
-                                    TransactionUtil.setRollbackOnly("Forcing transaction rollback in sequence increment because we didn't get a clean update, ie a conflict was found, so not saving the results", null);
-                                }
-                            } catch (SQLException sqle) {
-                                Debug.logWarning(sqle, "[SequenceUtil.SequenceBank.fillBank] SQL Exception while executing the following:\n" + sql + "\nError was:" + sqle.getMessage(), module);
-                                throw sqle;
-                            } finally {
-                                try {
-                                    if (stmt != null) stmt.close();
-                                } catch (SQLException sqle) {
-                                    Debug.logWarning(sqle, "Error closing statement in sequence util", module);
-                                }
-                                try {
-                                    if (connection != null) connection.close();
-                                } catch (SQLException sqle) {
-                                    Debug.logWarning(sqle, "Error closing connection in sequence util", module);
+                                    // This should never happen
+                                    throw new GenericEntityException("No rows changed when trying insert new sequence row with this SQL: " + sql);
                                 }
                             }
-                        } catch (Exception e) {
-                            String errMsg = "General error in getting a sequenced ID";
-                            Debug.logError(e, errMsg, module);
-                            try {
-                                TransactionUtil.rollback(beganTransaction, errMsg, e);
-                            } catch (GenericTransactionException gte2) {
-                                Debug.logError(gte2, "Unable to rollback transaction", module);
-                            }
-
-                            // error, break out of the loop to not try to continue forever
-                            break;
-                        } finally {
-                            try {
-                                TransactionUtil.commit(beganTransaction);
-                            } catch (GenericTransactionException gte) {
-                                Debug.logError(gte, "Unable to commit sequence increment transaction, continuing anyway though", module);
-                            }
                         }
-                    } catch (GenericTransactionException e) {
-                        Debug.logError(e, "System Error suspending transaction in sequence util", module);
+                        // select the record (now locked) to get the curSeqId
+                        sql = "SELECT " + SequenceUtil.this.idColName + " FROM " + SequenceUtil.this.tableName + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
+                        rs = stmt.executeQuery(sql);
+                        boolean gotVal = false;
+                        if (rs.next()) {
+                            curSeqId = rs.getLong(SequenceUtil.this.idColName);
+                            gotVal = true;
+                        }
+                        rs.close();
+                        if (!gotVal) {
+                            throw new GenericEntityException("Failed to find the sequence record: " + sql);
+                        }
+                        // increment the sequence
+                        sql = "UPDATE " + SequenceUtil.this.tableName + " SET " + SequenceUtil.this.idColName + "=" + SequenceUtil.this.idColName + "+" + bankSize + " WHERE " + SequenceUtil.this.nameColName + "='" + this.seqName + "'";
+                        if (stmt.executeUpdate(sql) <= 0) {
+                            throw new GenericEntityException("Update failed, no rows changes for seqName: " + seqName);
+                        }
+
+                        TransactionUtil.commit(beganTransaction);
+
+                    } catch (SQLException sqle) {
+                        Debug.logWarning(sqle, "SQL Exception while executing the following:\n" + sql + "\nError was:" + sqle.getMessage(), module);
+                        throw sqle;
                     } finally {
-                        if (suspendedTransaction != null) {
-                            try {
-                                TransactionUtil.resume(suspendedTransaction);
-                            } catch (GenericTransactionException e) {
-                                Debug.logError(e, "Error resuming suspended transaction in sequence util", module);
-                            }
+                        try {
+                            if (stmt != null) stmt.close();
+                        } catch (SQLException sqle) {
+                            Debug.logWarning(sqle, "Error closing statement in sequence util", module);
+                        }
+                        try {
+                            if (connection != null) connection.close();
+                        } catch (SQLException sqle) {
+                            Debug.logWarning(sqle, "Error closing connection in sequence util", module);
                         }
                     }
-                }
-
-                if (val1 + bankSize != val2) {
-                    if (numTries >= maxTries) {
-                        String errMsg = "[SequenceUtil.SequenceBank.fillBank] maxTries (" + maxTries + ") reached for seqName [" + this.seqName + "], giving up.";
-                        Debug.logError(errMsg, module);
-                        return;
+                } catch (Exception e) {
+                    // reset the sequence fields and return (note: it would be better to throw an exception)
+                    curSeqId = 0;
+                    maxSeqId = 0;
+                    String errMsg = "General error in getting a sequenced ID";
+                    Debug.logError(e, errMsg, module);
+                    try {
+                        TransactionUtil.rollback(beganTransaction, errMsg, e);
+                    } catch (GenericTransactionException gte2) {
+                        Debug.logError(gte2, "Unable to rollback transaction", module);
                     }
-
-                    // collision happened, wait a bounded random amount of time then continue
-                    long waitTime = (long) (Math.random() * (maxWaitMillis - minWaitMillis) + minWaitMillis);
-
-                    Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Collision found for seqName [" + seqName + "], val1=" + val1 + ", val2=" + val2 + ", val1+bankSize=" + (val1 + bankSize) + ", bankSize=" + bankSize + ", waitTime=" + waitTime, module);
-
+                    return;
+                }
+            } catch (GenericTransactionException e) {
+                Debug.logError(e, "System Error suspending transaction in sequence util", module);
+                // reset the sequence fields and return (note: it would be better to throw an exception)
+                curSeqId = 0;
+                maxSeqId = 0;
+                return;
+            } finally {
+                if (suspendedTransaction != null) {
                     try {
-                        // using the Thread.sleep to more reliably lock this thread: this.wait(waitTime);
-                        java.lang.Thread.sleep(waitTime);
-                    } catch (Exception e) {
-                        Debug.logWarning(e, "Error waiting in sequence util", module);
+                        TransactionUtil.resume(suspendedTransaction);
+                    } catch (GenericTransactionException e) {
+                        Debug.logError(e, "Error resuming suspended transaction in sequence util", module);
+                        // reset the sequence fields and return (note: it would be better to throw an exception)
+                        curSeqId = 0;
+                        maxSeqId = 0;
                         return;
                     }
                 }
-
-                numTries++;
             }
 
-            curSeqId = val1;
-            maxSeqId = val2;
+            maxSeqId = curSeqId + bankSize;
             if (Debug.infoOn()) Debug.logInfo("Got bank of sequenced IDs for [" + this.seqName + "]; curSeqId=" + curSeqId + ", maxSeqId=" + maxSeqId + ", bankSize=" + bankSize, module);
-            //Debug.logWarning("[SequenceUtil.SequenceBank.fillBank] Ending fillBank Thread Name is: " + Thread.currentThread().getName() + ":" + Thread.currentThread().toString(), module);
         }
     }
 }
+