You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2019/07/22 19:49:55 UTC

[jmeter] branch master updated: implemented preinit of jdbc connection pool (#477)

This is an automated email from the ASF dual-hosted git repository.

pmouawad pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new 031807a  implemented preinit of jdbc connection pool (#477)
031807a is described below

commit 031807aed3d8365513b9e0689ce599bc5d97ddc1
Author: Franz Schwab <fr...@users.noreply.github.com>
AuthorDate: Mon Jul 22 21:49:47 2019 +0200

    implemented preinit of jdbc connection pool (#477)
    
    * implemented pre-init of jdbc connection pool
    
    
    Former-commit-id: f742eff6f3d7ad699610599890360eb9c00216ff
    
    * added french translation, used JMeter built-in logging mechanism for sql exception, default value for pr-einit changed to FALSE to not break existing behavior
    
    * removed whitespace due to checkstyle ant target error
    
    * added documentation to the user manual
    
    * changed screenshot of jdbc connection configuration dialogue
    
    * add Exasol jdbc driver to documentation
    
    * added a detailed comment about what we do exactly and why, and sorrounded the log output with is...Enabled() checks
    
    * added assertion for pre-init of pool in batchtest JDBC_TESTS
    
    * better assertion message for the pre-init test
---
 bin/jmeter.properties                              |   4 +--
 bin/testfiles/JDBC_TESTS.csv                       |   1 +
 bin/testfiles/JDBC_TESTS.jmx                       |  37 +++++++++++++++++++++
 bin/testfiles/JDBC_TESTS.xml                       |   7 ++++
 .../protocol/jdbc/config/DataSourceElement.java    |  35 +++++++++++++++++++
 .../jdbc/config/DataSourceElementBeanInfo.java     |   5 ++-
 .../config/DataSourceElementResources.properties   |   2 ++
 .../DataSourceElementResources_fr.properties       |   2 ++
 .../screenshots/jdbc-config/jdbc-conn-config.png   | Bin 14933 -> 26380 bytes
 xdocs/usermanual/component_reference.xml           |  16 +++++++--
 xdocs/usermanual/properties_reference.xml          |   2 +-
 11 files changed, 105 insertions(+), 6 deletions(-)

diff --git a/bin/jmeter.properties b/bin/jmeter.properties
index 6fa7808..f5753f4 100644
--- a/bin/jmeter.properties
+++ b/bin/jmeter.properties
@@ -793,7 +793,7 @@ wmlParser.types=text/vnd.wap.wml
 # Database validation query
 # based in https://stackoverflow.com/questions/10684244/dbcp-validationquery-for-different-databases list
 jdbc.config.check.query=select 1 from INFORMATION_SCHEMA.SYSTEM_USERS|select 1 from dual|select 1 from sysibm.sysdummy1|select 1|select 1 from rdb$database
-jdbc.config.jdbc.driver.class=com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver
+jdbc.config.jdbc.driver.class=com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver|com.exasol.jdbc.EXADriver
 
 #---------------------------------------------------------------------------
 # OS Process Sampler configuration
@@ -1343,4 +1343,4 @@ jmeter.reportgenerator.apdex_tolerated_threshold=1500
 
 # Path to XSL file used to generate Schematic View of Test Plan
 # When empty, JMeter will use the embedded one in src/core/org/apache/jmeter/gui/action/schematic.xsl
-#docgeneration.schematic_xsl=
\ No newline at end of file
+#docgeneration.schematic_xsl=
diff --git a/bin/testfiles/JDBC_TESTS.csv b/bin/testfiles/JDBC_TESTS.csv
index c7d06a6..d405c8f 100644
--- a/bin/testfiles/JDBC_TESTS.csv
+++ b/bin/testfiles/JDBC_TESTS.csv
@@ -1,4 +1,5 @@
 label,responseCode,responseMessage,threadName,dataType,success,grpThreads,allThreads,SampleCount,ErrorCount
+JSR223_CHECK_POOL_PREINIT,200,OK,setUp Thread Group 1-1,text,true,1,1,1,0
 JDBC_DROP_PROCEDURE,200,OK,setUp Thread Group 1-1,text,true,1,1,1,0
 JDBC_DROP_PROCEDURE,200,OK,setUp Thread Group 1-1,text,true,1,1,1,0
 JDBC_DROP_TABLE,200,OK,setUp Thread Group 1-1,text,true,1,1,1,0
diff --git a/bin/testfiles/JDBC_TESTS.jmx b/bin/testfiles/JDBC_TESTS.jmx
index 2ead07b..6f35336 100644
--- a/bin/testfiles/JDBC_TESTS.jmx
+++ b/bin/testfiles/JDBC_TESTS.jmx
@@ -25,6 +25,7 @@
         <stringProp name="transactionIsolation">DEFAULT</stringProp>
         <stringProp name="trimInterval">60000</stringProp>
         <stringProp name="username">SA</stringProp>
+        <boolProp name="preinit">true</boolProp>
       </JDBCDataSource>
       <hashTree/>
       <SetupThreadGroup guiclass="SetupThreadGroupGui" testclass="SetupThreadGroup" testname="setUp Thread Group" enabled="true">
@@ -42,6 +43,42 @@
         <stringProp name="ThreadGroup.delay"></stringProp>
       </SetupThreadGroup>
       <hashTree>
+        <JSR223Sampler guiclass="TestBeanGUI" testclass="JSR223Sampler" testname="JSR223_CHECK_POOL_PREINIT" enabled="true">
+          <stringProp name="scriptLanguage">groovy</stringProp>
+          <stringProp name="parameters"></stringProp>
+          <stringProp name="filename"></stringProp>
+          <stringProp name="cacheKey">true</stringProp>
+          <stringProp name="script">//dummy sampler, just needed for the assertion</stringProp>
+        </JSR223Sampler>
+        <hashTree>
+          <JSR223Assertion guiclass="TestBeanGUI" testclass="JSR223Assertion" testname="JSR223_CHECK_POOL_PREINIT_ASSERTION" enabled="true">
+            <stringProp name="scriptLanguage">groovy</stringProp>
+            <stringProp name="parameters"></stringProp>
+            <stringProp name="filename"></stringProp>
+            <stringProp name="cacheKey">true</stringProp>
+            <stringProp name="script">
+import groovy.sql.Sql
+
+def url = &apos;jdbc:hsqldb:mem:mymemdb&apos;
+def user = &apos;SA&apos;
+def password = &apos;&apos;
+def driver = &apos;org.hsqldb.jdbcDriver&apos;
+def sql = Sql.newInstance(url, user, password, driver)
+def row = sql.firstRow(&apos;select count(*) from INFORMATION_SCHEMA.system_sessions&apos;) 
+def sessionNum = row[0]
+
+try {
+    assert sessionNum == 2
+} catch (Error err) {
+    AssertionResult.setFailure(true)
+    AssertionResult.setFailureMessage(&quot;Got &quot; + sessionNum + &quot; sessions on the database, but expected 2 sessions. (1 preinitialized session from the connection pool, and 1 from the above jdbc call.)&quot;);
+}
+
+sql.close()
+</stringProp>
+          </JSR223Assertion>
+          <hashTree/>
+        </hashTree>
         <JDBCSampler guiclass="TestBeanGUI" testclass="JDBCSampler" testname="JDBC_DROP_PROCEDURE" enabled="true">
           <stringProp name="dataSource">dbConfig</stringProp>
           <stringProp name="query">drop PROCEDURE new_user IF EXISTS;
diff --git a/bin/testfiles/JDBC_TESTS.xml b/bin/testfiles/JDBC_TESTS.xml
index 62eb164..27b0726 100644
--- a/bin/testfiles/JDBC_TESTS.xml
+++ b/bin/testfiles/JDBC_TESTS.xml
@@ -1,5 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <testResults version="1.2">
+<sample s="true" lb="JSR223_CHECK_POOL_PREINIT" rc="200" rm="OK" tn="setUp Thread Group 1-1" dt="text" sc="1" ec="0" ng="1" na="1">
+  <assertionResult>
+    <name>JSR223_CHECK_POOL_PREINIT_ASSERTION</name>
+    <failure>false</failure>
+    <error>false</error>
+  </assertionResult>
+</sample>
 <sample s="true" lb="JDBC_DROP_PROCEDURE" rc="200" rm="OK" tn="setUp Thread Group 1-1" dt="text" sc="1" ec="0" ng="1" na="1">
   <assertionResult>
     <name>RA</name>
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElement.java b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElement.java
index 35ec44a..8887dcb 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElement.java
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElement.java
@@ -59,6 +59,7 @@ public class DataSourceElement extends AbstractTestElement
 
     private transient boolean keepAlive;
     private transient boolean autocommit;
+    private transient boolean preinit;
 
     /*
      *  The datasource is set up by testStarted and cleared by testEnded.
@@ -218,6 +219,8 @@ public class DataSourceElement extends AbstractTestElement
             sb.append(getTrimInterval());
             sb.append(" Auto-Commit: ");
             sb.append(isAutocommit());
+            sb.append(" Preinit: ");
+            sb.append(isPreinit());
             log.debug(sb.toString());
         }
         int poolSize = Integer.parseInt(maxPool);
@@ -288,6 +291,23 @@ public class DataSourceElement extends AbstractTestElement
             dataSource.setPassword(getPassword());
         }
 
+        if(isPreinit()) {
+            // side effect - connection pool init - that is what we want
+            // see also https://commons.apache.org/proper/commons-dbcp/apidocs/org/apache/commons/dbcp2/BasicDataSource.html#setInitialSize-int-
+            // it says: "The pool is initialized the first time one of the following methods is invoked: getConnection, setLogwriter, setLoginTimeout, getLoginTimeout, getLogWriter."
+            // so we get a connection and close it - which releases it back to the pool (but stays open)
+            try {
+                dataSource.getConnection().close();
+                if (log.isDebugEnabled()) {
+                    log.debug("Preinitializing the connection pool: {}@{}", getDataSourceName(), System.identityHashCode(dataSource));
+                }
+            } catch (SQLException ex) {
+                if (log.isErrorEnabled()) {
+                    log.error("Error preinitializing the connection pool: {}@{}", getDataSourceName(), System.identityHashCode(dataSource), ex);
+                }
+            }
+        }
+
         log.debug("PoolConfiguration:{}", this.dataSource);
         return dataSource;
     }
@@ -544,6 +564,21 @@ public class DataSourceElement extends AbstractTestElement
     }
 
     /**
+     * @return Returns the preinit.
+     */
+    public boolean isPreinit() {
+        return preinit;
+    }
+
+    /**
+     * @param preinit
+     *            The preinit to set.
+     */
+    public void setPreinit(boolean preinit) {
+        this.preinit = preinit;
+    }
+
+    /**
      * @return Returns the keepAlive.
      */
     public boolean isKeepAlive() {
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementBeanInfo.java b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementBeanInfo.java
index c3a5a7d..2474cf1 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementBeanInfo.java
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementBeanInfo.java
@@ -54,7 +54,7 @@ public class DataSourceElementBeanInfo extends BeanInfoSupport {
         createPropertyGroup("varName", new String[] { "dataSource" });
 
         createPropertyGroup("pool", new String[] { "poolMax", "timeout",
-                "trimInterval", "autocommit", "transactionIsolation", "initQuery"  });
+                "trimInterval", "autocommit", "transactionIsolation", "preinit", "initQuery" });
 
         createPropertyGroup("keep-alive", new String[] { "keepAlive", "connectionAge", "checkQuery" });
 
@@ -82,6 +82,9 @@ public class DataSourceElementBeanInfo extends BeanInfoSupport {
         Set<String> modesSet = TRANSACTION_ISOLATION_MAP.keySet();
         String[] modes = modesSet.toArray(new String[modesSet.size()]);
         p.setValue(TAGS, modes);
+        p = property("preinit");
+        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
+        p.setValue(DEFAULT, Boolean.FALSE);
         p = property("initQuery", TypeEditor.TextAreaEditor);
         p.setValue(NOT_UNDEFINED, Boolean.TRUE);
         p.setValue(DEFAULT, "");
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources.properties b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources.properties
index d5acb59..16571c0 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources.properties
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources.properties
@@ -46,3 +46,5 @@ keepAlive.displayName=Test While Idle
 keepAlive.shortDescription=Whether the pool should validate connections while they are idle in Pool.  If no, Soft Min Evictable Idle Time and Validation Query are ignored.
 transactionIsolation.displayName=Transaction Isolation
 transactionIsolation.shortDescription=Transaction Isolation Level
+preinit.displayName=Preinit Pool
+preinit.shortDescription=Preinitialize the whole connection pool by requesting one connection from it.
diff --git a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources_fr.properties b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources_fr.properties
index fb2d2f1..0ff2a48 100644
--- a/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources_fr.properties
+++ b/src/protocol/jdbc/org/apache/jmeter/protocol/jdbc/config/DataSourceElementResources_fr.properties
@@ -47,3 +47,5 @@ username.shortDescription=L'identifiant à utiliser pour la connexion à la base
 varName.displayName=Nom de liaison du pool
 transactionIsolation.displayName=Isolation de la Transaction
 transactionIsolation.shortDescription=Niveau d'isolation de la transaction
+preinit.displayName=Préinit Pool
+preinit.shortDescription=Préinitialise l'ensemble du pool de connexions en lui demandant une connexion.
diff --git a/xdocs/images/screenshots/jdbc-config/jdbc-conn-config.png b/xdocs/images/screenshots/jdbc-config/jdbc-conn-config.png
index b31811b..7834bce 100644
Binary files a/xdocs/images/screenshots/jdbc-config/jdbc-conn-config.png and b/xdocs/images/screenshots/jdbc-config/jdbc-conn-config.png differ
diff --git a/xdocs/usermanual/component_reference.xml b/xdocs/usermanual/component_reference.xml
index 1003901..49f5f05 100644
--- a/xdocs/usermanual/component_reference.xml
+++ b/xdocs/usermanual/component_reference.xml
@@ -3910,7 +3910,7 @@ instead. (see figures 12 and 13).</p>
 </component>
 
 <component name="JDBC Connection Configuration" index="&sect-num;.4.10" 
-                 width="697" height="656" screenshot="jdbc-config/jdbc-conn-config.png">
+                 width="687" height="669" screenshot="jdbc-config/jdbc-conn-config.png">
     <description>Creates a database connection (used by <complink name="JDBC Request"/>Sampler)
      from the supplied JDBC Connection settings. The connection may be optionally pooled between threads.
      Otherwise each thread gets its own connection.
@@ -3941,6 +3941,7 @@ instead. (see figures 12 and 13).</p>
         See <a href="https://commons.apache.org/proper/commons-dbcp/api-2.1.1/org/apache/commons/dbcp2/BasicDataSource.html#getTimeBetweenEvictionRunsMillis--" >BasicDataSource.html#getTimeBetweenEvictionRunsMillis</a></property>
         <property name="Auto Commit" required="Yes">Turn auto commit on or off for the connections.</property>
         <property name="Transaction isolation" required="Yes">Transaction isolation level</property>
+        <property name="Preinit Pool" required="No">The connection pool can be intialized instantly. If set to <code>False</code> (default), the JDBC request samplers using this pool might measure higher response times for the first queries – as the connection establishment time for the whole pool is included.</property>
         <property name="Init SQL statements separated by new line" required="No">A Collection of SQL statements that will be used to initialize physical connections when they are first created. These statements are executed only once - when the configured connection factory creates the connection. </property>
         <property name="Test While Idle" required="Yes">Test idle connections of the pool, see <a href="https://commons.apache.org/proper/commons-dbcp/api-2.1.1/org/apache/commons/dbcp2/BasicDataSource.html#getTestWhileIdle--">BasicDataSource.html#getTestWhileIdle</a>. 
         Validation Query will be used to test it.</property>
@@ -3963,6 +3964,7 @@ instead. (see figures 12 and 13).</p>
               <dt>Derby</dt><dd><code>values 1</code></dd>
               <dt>H2</dt><dd><code>select 1</code></dd>
               <dt>Firebird</dt><dd><code>select 1 from rdb$database</code></dd>
+              <dt>Exasol</dt><dd><code>select 1</code></dd>
             </dl>
         <note>The list come from <a href="https://stackoverflow.com/questions/10684244/dbcp-validationquery-for-different-databases">stackoverflow entry on different database validation queries</a> and it can be incorrect</note>
         <note>Note this validation query is used on pool creation to validate it even if "<code>Test While Idle</code>" suggests query would only be used on idle connections.
@@ -3971,7 +3973,7 @@ instead. (see figures 12 and 13).</p>
         <property name="Database URL" required="Yes">JDBC Connection string for the database.</property>
         <property name="JDBC Driver class" required="Yes">Fully qualified name of driver class. (Must be in
         JMeter's classpath - easiest to copy <code>.jar</code> file into JMeter's <code>/lib</code> directory).
-        <p>The list of the validation queries can be configured with <code>jdbc.config.jdbc.driver.class</code> property and are by default:</p>
+        <p>The list of the preconfigured jdbc driver classes can be configured with <code>jdbc.config.jdbc.driver.class</code> property and are by default:</p>
             <dl>
               <dt>hsqldb</dt><dd>org.hsqldb.jdbc.JDBCDriver</dd>
               <dt>Oracle</dt><dd>oracle.jdbc.OracleDriver</dd>
@@ -3987,6 +3989,7 @@ instead. (see figures 12 and 13).</p>
               <dt>MariaDB</dt><dd>org.mariadb.jdbc.Driver</dd>
               <dt>SQLite</dt><dd>org.sqlite.JDBC</dd>
               <dt>Sybase AES</dt><dd>net.sourceforge.jtds.jdbc.Driver</dd>
+              <dt>Exasol</dt><dd>com.exasol.jdbc.EXADriver</dd>
             </dl>
         </property>
         <property name="Username" required="No">Name of user to connect as.</property>
@@ -4071,6 +4074,15 @@ If the database server is not running or is not accessible, then JMeter will rep
       <dd><code>jdbc:mariadb://host[:port]/dbname[;URLAttributes=value[;&hellip;]]</code></dd>
     </dl>
   </dd>
+  <dt>Exasol (see also <a href="https://docs.exasol.com/connect_exasol/drivers/jdbc.htm" >JDBC driver documentation</a>)</dt>
+  <dd>
+    <dl>
+      <dt>Driver class</dt>
+      <dd><code>com.exasol.jdbc.EXADriver</code></dd>
+      <dt>Database URL</dt>
+      <dd><code>jdbc:exa:host[:port][;schema=SCHEMA_NAME][;prop_x=value_x]</code></dd>
+    </dl>
+  </dd>
 </dl>
 <note>The above may not be correct - please check the relevant JDBC driver documentation.</note>
 </component>
diff --git a/xdocs/usermanual/properties_reference.xml b/xdocs/usermanual/properties_reference.xml
index b0af6f3..87994c8 100644
--- a/xdocs/usermanual/properties_reference.xml
+++ b/xdocs/usermanual/properties_reference.xml
@@ -1026,7 +1026,7 @@ JMETER-SERVER</source>
 </property>
 <property name="jdbc.config.jdbc.driver.class">
     List of JDBC driver class name<br/>
-    Defaults to: <source>com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver</source>
+    Defaults to: <source>com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver|com.exasol.jdbc.EXADriver</source>
 </property>
 </properties>
 </section>