changeset 290:d477b3103a8b

Optimised MonetStatement memory resource usage by only creating an ArrayList and ReentrantLock object when the batch methods addBatch() or executeBatch() are called. In most Statement usages those methods are not called. Also implemented some other small optimisations in executeBatch().
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Wed, 31 Jul 2019 17:12:39 +0200 (2019-07-31)
parents cce8a1803f68
children 611c0954b0e6
files ChangeLog src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
diffstat 2 files changed, 34 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,9 @@
 # This file is updated with Maddlog
 
 * Wed Jul 31 2019 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
+- Optimised MonetStatement memory resource usage by only creating an ArrayList
+  and ReentrantLock object when the batch methods addBatch() or executeBatch()
+  are called. In most Statement usages those methods are not called.
 - Implemented method MonetClob.getAsciiStream()
 
 * Thu Mar 21 2019 Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
+++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetStatement.java
@@ -18,7 +18,6 @@ import java.sql.SQLFeatureNotSupportedEx
 import java.sql.SQLWarning;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 /**
@@ -80,7 +79,8 @@ public class MonetStatement
 	private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
 
 	/** A List to hold all queries of a batch */
-	private List<String> batch = new ArrayList<String>();
+	private ArrayList<String> batch = null;
+	private ReentrantLock batchLock = null;
 
 
 	/**
@@ -142,6 +142,10 @@ public class MonetStatement
 	 */
 	@Override
 	public void addBatch(String sql) throws SQLException {
+		if (batch == null) {
+			// create the ArrayList at first time use
+			batch = new ArrayList<String>();
+		}
 		batch.add(sql);
 	}
 
@@ -150,11 +154,10 @@ public class MonetStatement
 	 */
 	@Override
 	public void clearBatch() {
-		batch.clear();
+		if (batch != null)
+			batch.clear();
 	}
 
-	Lock batchLock = new ReentrantLock();
-
 	/**
 	 * Submits a batch of commands to the database for execution and if
 	 * all commands execute successfully, returns an array of update
@@ -195,26 +198,30 @@ public class MonetStatement
 	 */
 	@Override
 	public int[] executeBatch() throws SQLException {
-		// this method is synchronized to make sure noone gets inbetween the
+		if (batch == null || batch.isEmpty()) {
+			return new int[0];
+		}
+
+		// this method is synchronized/locked to make sure no one gets in between the
 		// operations we execute below
-
+		if (batchLock == null) {
+			// create a ReentrantLock at first time use
+			batchLock = new ReentrantLock();
+		}
 		batchLock.lock();
 		try {
-			// don't think long if there isn't much to do
-			if (batch.isEmpty())
-				return new int[0];
-
 			int[] counts = new int[batch.size()];
 			int offset = 0;
 			boolean first = true;
 			boolean error = false;
-
+			String sep = connection.queryTempl[2];
+			int sepLen = sep.length();
 			BatchUpdateException e = new BatchUpdateException("Error(s) occurred while executing the batch, see next SQLExceptions for details", "22000", counts);
 			StringBuilder tmpBatch = new StringBuilder(MapiSocket.BLOCK);
-			String sep = connection.queryTempl[2];
+
 			for (int i = 0; i < batch.size(); i++) {
 				String tmp = batch.get(i);
-				if (sep.length() + tmp.length() > MapiSocket.BLOCK) {
+				if (sepLen + tmp.length() > MapiSocket.BLOCK) {
 					// The thing is too big.  Way too big.  Since it won't
 					// be optimal anyway, just add it to whatever we have
 					// and continue.
@@ -222,25 +229,27 @@ public class MonetStatement
 						tmpBatch.append(sep);
 					tmpBatch.append(tmp);
 					// send and receive
-					error |= internalBatch(tmpBatch.toString(), counts, offset, i + 1, e);
+					error |= internalBatch(tmpBatch, counts, offset, i + 1, e);
 					offset = i;
 					tmpBatch.delete(0, tmpBatch.length());
 					first = true;
 					continue;
 				}
-				if (tmpBatch.length() + sep.length() + tmp.length() >= MapiSocket.BLOCK) {
+				if (tmpBatch.length() + sepLen + tmp.length() >= MapiSocket.BLOCK) {
 					// send and receive
-					error |= internalBatch(tmpBatch.toString(), counts, offset, i + 1, e);
+					error |= internalBatch(tmpBatch, counts, offset, i + 1, e);
 					offset = i;
 					tmpBatch.delete(0, tmpBatch.length());
 					first = true;
 				}
-				if (!first) tmpBatch.append(sep);
-				first = false;
+				if (first)
+					first = false;
+				else
+					tmpBatch.append(sep);
 				tmpBatch.append(tmp);
 			}
 			// send and receive
-			error |= internalBatch(tmpBatch.toString(), counts, offset, counts.length, e);
+			error |= internalBatch(tmpBatch, counts, offset, counts.length, e);
 
 			// throw BatchUpdateException if it contains something
 			if (error)
@@ -253,7 +262,7 @@ public class MonetStatement
 	}
 
 	private boolean internalBatch(
-			String batch,
+			StringBuilder batch,
 			int[] counts,
 			int offset,
 			int max,
@@ -261,7 +270,7 @@ public class MonetStatement
 		throws BatchUpdateException
 	{
 		try {
-			boolean type = internalExecute(batch);
+			boolean type = internalExecute(batch.toString());
 			int count = -1;
 			if (!type)
 				count = getUpdateCount();