├── README.md ├── warProject ├── .gitignore ├── .settings │ ├── org.eclipse.wst.jsdt.ui.superType.name │ ├── org.eclipse.wst.jsdt.ui.superType.container │ ├── org.eclipse.wst.validation.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ └── org.eclipse.wst.common.component ├── keystore.p12 ├── src │ ├── main │ │ ├── resources │ │ │ ├── keystore.p12 │ │ │ ├── hikari01.properties │ │ │ ├── hikari02.properties │ │ │ ├── application.properties │ │ │ ├── ehcache.xml │ │ │ └── NCORV.xml │ │ └── java │ │ │ └── com │ │ │ └── github │ │ │ └── eostermueller │ │ │ └── perfSandbox │ │ │ ├── model │ │ │ ├── Teller.java │ │ │ ├── Branch.java │ │ │ ├── Accounts.java │ │ │ ├── Transaction.java │ │ │ └── Account.java │ │ │ ├── Logger.java │ │ │ ├── dataaccess │ │ │ ├── BaseManager.java │ │ │ ├── TableNames.java │ │ │ ├── BaseSqlTextMgr.java │ │ │ └── PerfSandboxUtil.java │ │ │ ├── parse │ │ │ ├── CountType.java │ │ │ ├── Ncorv.java │ │ │ ├── NcorvSaxHandler.java │ │ │ ├── SaxParserPool.java │ │ │ ├── UnpooledSaxParserWorker.java │ │ │ ├── ApacheCommonsPooledSaxParserWorker.java │ │ │ └── EclipseEmfPooledSaxParserWorker.java │ │ │ ├── PerfSandboxException.java │ │ │ ├── filesystem │ │ │ └── FileSystemReader.java │ │ │ ├── dataaccess_6 │ │ │ └── AccountMgr6.java │ │ │ ├── BranchInquiry.java │ │ │ ├── cache │ │ │ ├── UncachedBranchInquiryImpl.java │ │ │ └── CachedBranchInquiryImpl.java │ │ │ ├── BusyCpuProcessor.java │ │ │ ├── dataaccess_5 │ │ │ ├── ListInquiry.java │ │ │ ├── AccountMgr5.java │ │ │ ├── SqlTextMgr5.java │ │ │ └── PkInquiry.java │ │ │ ├── dataaccess_4 │ │ │ ├── SqlTextMgr4.java │ │ │ ├── PkInquiry4.java │ │ │ └── AccountMgr4.java │ │ │ ├── dataaccess_3 │ │ │ ├── SqlTextMgr3.java │ │ │ └── AccountMgr3.java │ │ │ ├── dataaccess_1 │ │ │ ├── SqlTextMgr1.java │ │ │ └── AccountMgr1.java │ │ │ ├── dataaccess_2 │ │ │ ├── SqlTextMgr2.java │ │ │ ├── AllAccountMgr2.java │ │ │ └── AccountMgr2.java │ │ │ ├── PerformanceSandboxApp.java │ │ │ ├── AbstractBranchInquiry.java │ │ │ └── HttpServer.java │ └── test │ │ └── java │ │ └── com │ │ └── github │ │ └── eostermueller │ │ └── perfSandbox │ │ ├── Test1MbFileSystemRead.java │ │ ├── SaxEclipseEmfParserTest.java │ │ ├── HttpServerTest.java │ │ ├── SaxParserTest.java │ │ ├── CachedBranchInquiryTest.java │ │ ├── TestBusyCpuProcessor.java │ │ └── UncachedBranchInquiryTest.java ├── .project ├── .classpath └── pom.xml ├── load.cmd ├── load.sh ├── .gitignore ├── startWar.cmd ├── keystore.p12 ├── db ├── helpDb.cmd ├── stopDb.cmd ├── helpDb.sh ├── startDb.cmd ├── countRows.cmd ├── countRows.sh ├── stopDb.sh └── startDb.sh ├── bin ├── genkeystore.cmd ├── genkeystore.sh ├── setenv.cmd └── setenv.sh ├── toolbox ├── hs-notes.txt ├── garbageSpank-new.sh └── garbageSpank-old.sh ├── startWar.sh ├── stopWar.cmd ├── LICENSE.txt ├── init.cmd ├── pom-load.xml ├── init.sh ├── sampleJMeterScripts ├── jpt_ch07_sandbox.jmx └── jpt_ch07_correlationVariables.jmx └── src └── test └── jmeter ├── 08b-shutdown.jmx ├── 11-shutdown.jmx ├── 04a.jmx ├── 04b.jmx ├── 07a.jmx └── 07b.jmx /README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /warProject/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /load.cmd: -------------------------------------------------------------------------------- 1 | mvn -f pom-load.xml -Djmeter.test=%1.jmx 2 | 3 | -------------------------------------------------------------------------------- /load.sh: -------------------------------------------------------------------------------- 1 | mvn -f pom-load.xml -Djmeter.test=$1.jmx 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /db/data/ 3 | db/h2.log 4 | jmeter.log 5 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /startWar.cmd: -------------------------------------------------------------------------------- 1 | call stopWar.cmd 2 | start cmd /c "mvn -f pom-startWar.xml -P%1 clean deploy" 3 | -------------------------------------------------------------------------------- /keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eostermueller/javaPerformanceTroubleshooting/HEAD/keystore.p12 -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /warProject/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eostermueller/javaPerformanceTroubleshooting/HEAD/warProject/keystore.p12 -------------------------------------------------------------------------------- /db/helpDb.cmd: -------------------------------------------------------------------------------- 1 | SET dir=%~dp0 2 | SET dir=%dir:~0,-1% 3 | 4 | call %dir%\..\bin\setenv.cmd 5 | java -cp %dir%\%H2_JAR% org.h2.tools.Server -help 6 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /bin/genkeystore.cmd: -------------------------------------------------------------------------------- 1 | keytool -noprompt -genkey -alias jetty -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 9999 -storepass mypassword 2 | -------------------------------------------------------------------------------- /bin/genkeystore.sh: -------------------------------------------------------------------------------- 1 | keytool -noprompt -genkey -alias jetty -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 9999 -storepass mypassword 2 | -------------------------------------------------------------------------------- /warProject/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eostermueller/javaPerformanceTroubleshooting/HEAD/warProject/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/model/Teller.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.model; 2 | 3 | public class Teller { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /toolbox/hs-notes.txt: -------------------------------------------------------------------------------- 1 | config file. 2 | special class names. 3 | remove 'noise' columns. 4 | add leak indicator problem. 5 | move interval count to the header, 6 | use tag instead of paren 7 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/Logger.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | public interface Logger { 4 | void log(String v); 5 | } 6 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess/BaseManager.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess; 2 | 3 | 4 | public class BaseManager { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /warProject/src/main/resources/hikari01.properties: -------------------------------------------------------------------------------- 1 | idleTimeout=42000 2 | jdbcUrl=jdbc:h2:tcp://localhost/perfSandboxDb;SCHEMA=S01;AUTO_SERVER=TRUE 3 | username= 4 | password= 5 | driverClassName=org.h2.Driver 6 | -------------------------------------------------------------------------------- /warProject/src/main/resources/hikari02.properties: -------------------------------------------------------------------------------- 1 | idleTimeout=42000 2 | jdbcUrl=jdbc:h2:tcp://localhost/perfSandboxDb;SCHEMA=S02;AUTO_SERVER=TRUE 3 | username= 4 | password= 5 | driverClassName=org.h2.Driver 6 | -------------------------------------------------------------------------------- /db/stopDb.cmd: -------------------------------------------------------------------------------- 1 | SET dir_stop=%~dp0 2 | SET dir_stop=%dir_stop:~0,-1% 3 | 4 | 5 | java -cp %dir_stop%\..\warProject\target\performanceGolf\WEB-INF\lib\h2-1.4.191.jar org.h2.tools.Server -tcpShutdown tcp://localhost:9092 6 | -------------------------------------------------------------------------------- /startWar.sh: -------------------------------------------------------------------------------- 1 | #This scripts takes a single parameter, the 3-character id of the test. 2 | #Each id is a profile in pom-startWar.xml 3 | 4 | BASEDIR=$(dirname $0) 5 | mvn -f $BASEDIR/pom-startWar.xml -P$1 clean deploy 6 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding//src/test/resources=UTF-8 6 | encoding/=UTF-8 7 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/CountType.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | public enum CountType { 4 | HR7983, //between 1979 and 1983 5 | HR8587, //between 1985 and 1987 6 | HR8995, //between 1989 and 1995 7 | OTHER 8 | 9 | 10 | } 11 | -------------------------------------------------------------------------------- /db/helpDb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | dir=$(dirname "$0") 3 | 4 | #export BASE_DIR=$dir/data 5 | export BASE_DIR=$dir/data2 6 | #export BASE_DIR=/Volumes/eto-external-drive/h2 7 | 8 | export H2=$dir/../warProject/target/performanceGolf/WEB-INF/lib/h2-1.4.191.jar 9 | 10 | java -cp $H2 org.h2.tools.Server -help 11 | 12 | 13 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /bin/setenv.cmd: -------------------------------------------------------------------------------- 1 | 2 | SET bin_dir=%~dp0 3 | SET bin_dir=%bin_dir:~0,-1% 4 | 5 | set H2_JAR=%bin_dir%\..\warProject\target\performanceGolf\WEB-INF\lib\h2-1.4.191.jar 6 | set JMETER_HOME=C:\Users\winSquee\Desktop\jmeter\apache-jmeter-3.0 7 | 8 | set JAVA_HOME=C:\Progra~1\Java\jdk1.8.0_91 9 | 10 | 11 | 12 | REM JMeter will use this 13 | set JVM_ARGS=-Xmx3g 14 | -------------------------------------------------------------------------------- /toolbox/garbageSpank-new.sh: -------------------------------------------------------------------------------- 1 | dir=$(dirname "$0") 2 | 3 | 4 | export MY_CP=$dir/../target/heapSpank-0.5.jar:$dir/heapSpank-0.5.jar 5 | 6 | export PID_TO_MONITOR=$1 7 | export INTERVAL=1s 8 | 9 | $JAVA_HOME/bin/jstat -gcnew $PID_TO_MONITOR $INTERVAL | java -classpath $MY_CP com.github.eostermueller.heapspank.garbagespank.console.GarbageSpankConsole -i $INTERVAL 10 | -------------------------------------------------------------------------------- /stopWar.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | jcmd | findstr performanceGolf > mypid.txt 5 | set /p mydata= 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/Test1MbFileSystemRead.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | import com.github.eostermueller.perfSandbox.filesystem.FileSystemReader; 8 | 9 | public class Test1MbFileSystemRead { 10 | 11 | @Test 12 | public void test() { 13 | FileSystemReader fsr = new FileSystemReader(); 14 | String results = fsr.readConfig(); 15 | 16 | assertTrue("Unable to read 1mb file", results.length() > 1000000 ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/PerfSandboxException.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | public class PerfSandboxException extends Exception { 4 | Exception cause = null; 5 | public PerfSandboxException(String string) { 6 | super(string); 7 | } 8 | public PerfSandboxException(String string, Exception e) { 9 | super(string); 10 | this.cause = e; 11 | } 12 | @Override 13 | public Exception getCause() { 14 | return this.cause; 15 | } 16 | 17 | public PerfSandboxException(Exception e) { 18 | this.cause = e; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2016 Erik Ostermueller 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /db/stopDb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | dir=$(dirname "$0") 3 | 4 | ## The loadDb.sh script will create 200mb of data in the db/data folder. 5 | ## To change the location, change BASE_DIR environment variable (below) 6 | ## to an existing folder where you want the data to be created. 7 | 8 | export BASE_DIR=$dir/data 9 | #export BASE_DIR=/Volumes/eto-external-drive/h2/wideData 10 | 11 | export H2=$dir/../warProject/target/performanceGolf/WEB-INF/lib/h2-1.4.191.jar 12 | 13 | java -cp $H2 org.h2.tools.Server -tcpShutdown tcp://localhost:9092 2>/dev/null 14 | 15 | 16 | #[-baseDir ] The base directory for H2 databases (all servers) 17 | #[-ifExists] Only existing databases may be opened (all servers) 18 | -------------------------------------------------------------------------------- /db/startDb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | dir=$(dirname "$0") 3 | 4 | ## The loadDb.sh script will create 200mb of data in the db/data folder. 5 | ## To change the location, change BASE_DIR environment variable (below) 6 | ## to an existing folder where you want the data to be created. 7 | 8 | export BASE_DIR=$dir/data 9 | #export BASE_DIR=/Volumes/eto-external-drive/h2/wideData 10 | 11 | export H2=$dir/../warProject/target/performanceGolf/WEB-INF/lib/h2-1.4.191.jar 12 | 13 | 14 | java -Xmx1g -XX:NewSize=768m -cp $H2 org.h2.tools.Server -tcp -web -baseDir $BASE_DIR 15 | 16 | 17 | #[-baseDir ] The base directory for H2 databases (all servers) 18 | #[-ifExists] Only existing databases may be opened (all servers) 19 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.7 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.source=1.7 13 | -------------------------------------------------------------------------------- /warProject/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/filesystem/FileSystemReader.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.filesystem; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.nio.charset.Charset; 8 | import java.nio.file.Files; 9 | import java.util.Scanner; 10 | 11 | public class FileSystemReader { 12 | 13 | private static final String DATA_FILE = "/data_1mb.txt"; 14 | 15 | public String readConfig() { 16 | return readFile(DATA_FILE); 17 | } 18 | 19 | private String readFile(String fileName) { 20 | InputStream in = this.getClass().getResourceAsStream(fileName); 21 | String text = new Scanner( in ).useDelimiter("\\A").next(); 22 | return text; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_6/AccountMgr6.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_6; 2 | 3 | import java.util.List; 4 | 5 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 6 | import com.github.eostermueller.perfSandbox.model.Account; 7 | import com.github.eostermueller.perfSandbox.model.Accounts; 8 | 9 | public class AccountMgr6 { 10 | 11 | public AccountMgr6(PerfSandboxSingleton perfSandbox) { 12 | // TODO Auto-generated constructor stub 13 | } 14 | 15 | public Accounts getAccounts(List accountIds_criteria) { 16 | 17 | Accounts accounts = new Accounts(); 18 | for(Long acctId : accountIds_criteria) { 19 | accounts.addAccount( Account.createFake(acctId) ); 20 | } 21 | return accounts; 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/model/Accounts.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class Accounts { 7 | private List m_list = new ArrayList(); 8 | public void addAccount(Account val) { 9 | m_list.add(val); 10 | } 11 | public List getAccounts() { 12 | return m_list; 13 | } 14 | public Account findAccount(long accountIdCriteria) { 15 | for(Account a : m_list) { 16 | if (a.accountId==accountIdCriteria) 17 | return a; 18 | } 19 | return null; 20 | } 21 | public Accounts() { 22 | 23 | } 24 | public Accounts(Accounts template) { 25 | for(Account a : template.m_list) { 26 | this.m_list.add( new Account(a) ); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/BranchInquiry.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import java.sql.SQLException; 4 | 5 | import javax.sql.DataSource; 6 | 7 | 8 | public interface BranchInquiry { 9 | String randomBranchInquiries() throws SQLException; 10 | void setDataSource(DataSource dataSource); 11 | DataSource getDataSource() throws SQLException; 12 | String randomLogicalBranchInquiry() throws SQLException; 13 | void setMaxBranchId(int maxBranchId); 14 | int getMaxBranchId() throws SQLException; 15 | void setInquiryCount(int val); 16 | int getInquiryCount(); 17 | String getTableName(); 18 | void setTableName(String tableName); 19 | long getTotalPhysicalCount(); 20 | void resetTotalPhysicalCount(); 21 | void incrementTotalPhysicalCount(); 22 | String physicalBranchNameInquiry(long branchId) throws SQLException; 23 | String logicalBranchNameInquiry(long branchId) throws SQLException; 24 | void shutdown(); 25 | } 26 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/cache/UncachedBranchInquiryImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.cache; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | import com.github.eostermueller.perfSandbox.AbstractBranchInquiry; 9 | import com.github.eostermueller.perfSandbox.BranchInquiry; 10 | 11 | public class UncachedBranchInquiryImpl extends AbstractBranchInquiry implements 12 | BranchInquiry { 13 | 14 | /** 15 | * With this uncached implementation, physical lookup is the best we can do for a logical lookup. 16 | * @throws SQLException 17 | */ 18 | @Override 19 | public String logicalBranchNameInquiry(long branchId) throws SQLException { 20 | 21 | return this.physicalBranchNameInquiry(branchId); 22 | } 23 | 24 | @Override 25 | public void shutdown() { 26 | //intentional no-op, no caching manager to shutdown. 27 | } 28 | 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess/TableNames.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess; 2 | 3 | /** 4 | * Used to create "schema.table" text to be embedded in SQL statements. 5 | * Sometimes a schema with performance issues (say, missing a particular index) will be used 6 | * to simulate performance problems. 7 | * 8 | * @author erikostermueller 9 | * 10 | */ 11 | public class TableNames { 12 | public String getAccountTable() { 13 | return getTable("accounts"); 14 | } 15 | public String getBranchTable() { 16 | return getTable("branches"); 17 | } 18 | public String getHistoryTable() { 19 | return getTable("history"); 20 | } 21 | public String getTellerTable() { 22 | return getTable("tellers"); 23 | } 24 | private String m_schema = null; 25 | public void setSchema(String val) { 26 | m_schema = val; 27 | } 28 | 29 | private String getTable(String tableName) { 30 | if (getSchema()==null) 31 | return tableName; 32 | else 33 | return getSchema() + "." + tableName; 34 | } 35 | private String getSchema() { 36 | return m_schema; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /warProject/src/main/resources/ehcache.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 16 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess/BaseSqlTextMgr.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | 5 | import com.github.eostermueller.perfSandbox.Logger; 6 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 7 | 8 | public class BaseSqlTextMgr { 9 | private Logger m_logger; 10 | public void setLogger(Logger logger) { 11 | this.m_logger = logger; 12 | } 13 | public TableNames getTableNames() { 14 | return this.m_tableNames; 15 | } 16 | protected TableNames m_tableNames = new TableNames(); 17 | @Autowired 18 | private PerfSandboxSingleton pgBench = null; 19 | 20 | public String getMaxAccountId() { 21 | return "select max(aid) from " + m_tableNames.getAccountTable(); 22 | } 23 | public String getMaxBranchId() { 24 | return "select max(bid) from " + m_tableNames.getBranchTable(); 25 | } 26 | 27 | 28 | public String getBranchCount() { 29 | return "select count(*) from " + m_tableNames.getBranchTable(); 30 | } 31 | public void logSql(String sql) { 32 | if (this.m_logger!=null) 33 | this.m_logger.log(sql); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /warProject/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | springBootJettyExample 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /warProject/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/SaxEclipseEmfParserTest.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.xml.parsers.ParserConfigurationException; 9 | import javax.xml.parsers.SAXParser; 10 | 11 | import org.eclipse.emf.ecore.xmi.XMLParserPool; 12 | import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.xml.sax.Attributes; 16 | import org.xml.sax.SAXException; 17 | import org.xml.sax.helpers.DefaultHandler; 18 | 19 | public class SaxEclipseEmfParserTest { 20 | private static final String SIMPLE_XML = "4"; 21 | Map features = new HashMap(); 22 | Map properties = new HashMap(); 23 | 24 | private XMLParserPool parserPool = null; 25 | @Before 26 | public void setup() { 27 | parserPool = new XMLParserPoolImpl(); 28 | } 29 | @Test 30 | public void test() throws ParserConfigurationException, SAXException { 31 | SAXParser parser = parserPool.get(features, properties, false); 32 | } 33 | } 34 | class MyHandler extends DefaultHandler { 35 | @Override 36 | public void startElement(String uri, String localName,String qName, 37 | Attributes attributes) throws SAXException { 38 | System.out.println( "localName [" + localName + "]" ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/BusyCpuProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean; 4 | 5 | import com.github.eostermueller.perfSandbox.filesystem.FileSystemReader; 6 | 7 | /** 8 | * Eat up lots of CPU as a troubleshooting exercise 9 | * @author erikostermueller 10 | * 11 | */ 12 | public class BusyCpuProcessor { 13 | 14 | public static final long SLEEP_TIME_MS = 50; 15 | BusyCpuRunner runner = null; 16 | Thread thread = null; 17 | String data = null; 18 | public BusyCpuProcessor() { 19 | 20 | FileSystemReader fsr = new FileSystemReader(); 21 | data = fsr.readConfig(); 22 | runner = new BusyCpuRunner( fsr.readConfig() ); 23 | 24 | } 25 | public boolean isStarted() { 26 | boolean rc = false; 27 | 28 | if (thread !=null) { 29 | Thread.State myState = thread.getState(); 30 | 31 | if (myState.equals(Thread.State.RUNNABLE)) 32 | rc = true; 33 | } 34 | return rc; 35 | } 36 | 37 | public void start() { 38 | 39 | stop(); 40 | thread = new Thread(runner, "PerformanceGolfBusyCpuThread"); 41 | thread.start(); 42 | } 43 | public void stop() { 44 | runner.stop(); 45 | } 46 | } 47 | class BusyCpuRunner implements Runnable { 48 | private volatile boolean _stop = false; 49 | String data = null; 50 | BusyCpuRunner(String val) { 51 | this.data = val; 52 | } 53 | public void run() { 54 | _stop = false; 55 | while(!_stop) { 56 | data.replaceAll("/^(A*)*$/", "bar"); 57 | //data.replaceAll("foo", "bar"); 58 | } 59 | 60 | } 61 | public void stop() { 62 | _stop = true; 63 | } 64 | } -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess/PerfSandboxUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess; 2 | 3 | import java.io.IOException; 4 | import java.net.DatagramSocket; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | import java.sql.Connection; 8 | import java.sql.ResultSet; 9 | import java.sql.SQLException; 10 | import java.sql.Statement; 11 | import java.sql.Timestamp; 12 | import java.util.Calendar; 13 | import java.util.Date; 14 | import java.util.TimeZone; 15 | 16 | public class PerfSandboxUtil { 17 | 18 | public static final int UN_INIT = -1; 19 | public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 20 | private static final int MIN_PORT_NUMBER = 1; 21 | private static final int MAX_PORT_NUMBER = 65535; 22 | 23 | 24 | public static Date getDate(ResultSet rs, int colNum) throws SQLException { 25 | Timestamp ts = rs.getTimestamp(colNum,tzUTC); // column is TIMESTAMPTZ 26 | return ts !=null ? new Date(ts.getTime()) : null; 27 | } 28 | public static void closeQuietly(Connection con) { 29 | try { 30 | if (con!=null) 31 | con.close(); 32 | } catch (SQLException e) { 33 | //ignore 34 | } 35 | } 36 | public static void closeQuietly(ResultSet rs) { 37 | try { 38 | if (rs!=null) 39 | rs.close(); 40 | } catch (SQLException e) { 41 | //ignore 42 | } 43 | } 44 | public static void closeQuietly(Statement stmt) { 45 | try { 46 | if (stmt!=null) 47 | stmt.close(); 48 | } catch (SQLException e) { 49 | //ignore 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_5/ListInquiry.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_5; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 13 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 14 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 15 | import com.github.eostermueller.perfSandbox.model.Transaction; 16 | 17 | public class ListInquiry { 18 | 19 | public ListInquiry(PerfSandboxSingleton val) { 20 | this.pgBench = val; 21 | } 22 | PerfSandboxSingleton pgBench = null; 23 | public List getTransactions(long accountId) throws SQLException, PerfSandboxException { 24 | 25 | Connection con = null; 26 | PreparedStatement ps = null; 27 | ResultSet rs = null; 28 | List list = null; 29 | try { 30 | con = pgBench.getConnection(); 31 | ps = con.prepareStatement( AccountMgr5.m_sqlTextMgr5.getHistoryListSql() ); 32 | ps.setLong(1, accountId); 33 | rs = ps.executeQuery(); 34 | list = new ArrayList(); 35 | while(rs.next()) { 36 | list.add ( rs.getLong(1)); 37 | } 38 | } finally { 39 | PerfSandboxUtil.closeQuietly(rs); 40 | PerfSandboxUtil.closeQuietly(ps); 41 | PerfSandboxUtil.closeQuietly(con); 42 | } 43 | return list; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /init.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | set dir=%~dp0 3 | 4 | echo "@@" 5 | echo "@@" 6 | echo "@@ About to initialize the performanceGolf war & db." 7 | echo "@@ It will take about 5-10 minutes to populate the db." 8 | echo "@@ To change location of this database, quit this script now and edit db/startDb.cmd." 9 | echo "@@" 10 | echo "@@ Before proceeding:" 11 | echo "@@ 1) Make sure you have 1gb of available disk space." 12 | echo "@@ 2) Make sure Java 1.8 or greater is installed and JAVA_HOME/bin is in the path." 13 | echo "@@ 3) Make sure Maven 3 or greater is installed and MAVEN_HOME/bin is in the path." 14 | echo "@@" 15 | echo "@@ "Ctrl+C to exit, or ...." 16 | pause 17 | 18 | set LOG=%dir%\db\h2.log 19 | 20 | 21 | :#Build the WAR file used for all performance testing 22 | call mvn -f %dir%\warProject\pom.xml clean package 23 | 24 | :### 25 | :### Delete any existing database 26 | :### 27 | call %dir%\db\stopDb.cmd > NUL 28 | rmdir /q /s %dir%\db\data 29 | mkdir %dir%\db\data 30 | 31 | 32 | :### 33 | :### Create blank DB and generate data into it. 34 | :### This is the part that takes 5-10 minutes. 35 | :### 36 | :### Start the db window minimized, and close 37 | :### the DOS window once stopDb.cmd is called 38 | :### 39 | start /MIN %dir%\db\startDb.cmd ^& exit 40 | 41 | timeout 10 42 | call %dir%\load.cmd loadDb-01 43 | call %dir%\load.cmd loadDb-02 44 | 45 | echo "@@" 46 | echo "@@ Here are row counts of tables:" 47 | echo "@@" 48 | call %dir%\load.cmd countRows-01 | findstr S0 49 | call %dir%\load.cmd countRows-02 | findstr S0 50 | call %dir\db\stopDb.cmd 51 | 52 | echo "@@" 53 | echo "@@ init.cmd is finished." 54 | echo "@@ The db has been stopped." 55 | echo "@@" 56 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/cache/CachedBranchInquiryImpl.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.cache; 2 | 3 | import java.sql.SQLException; 4 | 5 | import com.github.eostermueller.perfSandbox.AbstractBranchInquiry; 6 | import com.github.eostermueller.perfSandbox.BranchInquiry; 7 | 8 | import net.sf.ehcache.CacheManager; 9 | import net.sf.ehcache.Cache; 10 | import net.sf.ehcache.Element; 11 | 12 | public class CachedBranchInquiryImpl extends AbstractBranchInquiry implements BranchInquiry { 13 | private CacheManager cm = CacheManager.getInstance(); 14 | //private static CacheManager cm = CacheManager.create(); 15 | private static final String BRANCH_CACHE = "BRANCH_CACHE"; 16 | 17 | 18 | String getKey(long branchId) { 19 | return Long.toString(branchId).trim(); 20 | } 21 | @Override 22 | public String logicalBranchNameInquiry(long branchId) throws SQLException { 23 | String branchName = null; 24 | if (!cm.cacheExists(BRANCH_CACHE)) 25 | throw new RuntimeException("Is ehcache in the classpath? Was expecting a BRACHE_CACHE to be defined in ehcache.xml, like this: " + m_historyByAccountSql + ""); 30 | sb.append("" + m_accountPkInquirySql + ""); 31 | return sb.toString(); 32 | } 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /pom-load.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.example 5 | jmeter-demo 6 | jar 7 | 1.0-SNAPSHOT 8 | jmeter-demo 9 | http://maven.apache.org 10 | 11 | 12 | 13 | 14 | test-02.jmx 15 | 16 | 17 | install 18 | 19 | 20 | com.lazerycode.jmeter 21 | jmeter-maven-plugin 22 | 2.1.0 23 | 24 | 3.1 25 | 26 | ${jmeter.test} 27 | 28 | 29 | com.h2database:h2:1.4.191 30 | 31 | 32 | 10 33 | 34 | 35 | 36 | 37 | jmeter-tests 38 | verify 39 | 40 | jmeter 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_5/AccountMgr5.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_5; 2 | 3 | import java.sql.SQLException; 4 | import java.util.List; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 9 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 10 | import com.github.eostermueller.perfSandbox.model.Account; 11 | import com.github.eostermueller.perfSandbox.model.Accounts; 12 | 13 | public class AccountMgr5 { 14 | public AccountMgr5(PerfSandboxSingleton val) { 15 | this.pgBench = val; 16 | this.m_sqlTextMgr5.setLogger(val); 17 | m_pkInquiry = pgBench.getPkInquiry(); 18 | m_listInquiry = pgBench.getListInquiry(); 19 | } 20 | private PerfSandboxSingleton pgBench = null; 21 | private PkInquiry m_pkInquiry; 22 | private ListInquiry m_listInquiry; 23 | public static SqlTextMgr5 m_sqlTextMgr5 = new SqlTextMgr5(); 24 | public Accounts getAccounts(List randomAccountIds) { 25 | Accounts accounts = new Accounts(); 26 | for( long accountId : randomAccountIds) { 27 | try { 28 | Account a = m_pkInquiry.getAccount(accountId); 29 | getAccountHistory(a); 30 | accounts.addAccount( a ); 31 | } catch (SQLException e) { 32 | e.printStackTrace(); 33 | } catch (PerfSandboxException e) { 34 | e.printStackTrace(); 35 | } 36 | } 37 | return accounts; 38 | } 39 | public void getAccountHistory(Account val) throws SQLException, PerfSandboxException { 40 | List historyIds = m_listInquiry.getTransactions(val.accountId); 41 | for( long historyId : historyIds) { 42 | val.transactions.add(m_pkInquiry.getTransaction(historyId)); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/HttpServerTest.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.io.IOException; 6 | 7 | import org.junit.Test; 8 | 9 | import com.github.eostermueller.perfSandbox.HttpServer; 10 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 11 | 12 | 13 | public class HttpServerTest { 14 | 15 | /** 16 | * Validates that code can launch a live HTTP server, configure a simple REST service, invoke it and get the expected response. 17 | */ 18 | @Test 19 | public void test() { 20 | HttpServer myServer = new HttpServer(); 21 | try { 22 | assertTrue("TCP port [" + HttpServer.DEFAULT_HTTP_LISTEN_PORT + "t must be avilable for this test to run...and it is NOT available", 23 | HttpServer.available(HttpServer.WIREMOCK_HOST,HttpServer.DEFAULT_HTTP_LISTEN_PORT)); 24 | 25 | myServer.start(HttpServer.DEFAULT_HTTP_LISTEN_PORT, 26 | 1000, 27 | true /* disable journal, which is a memory leak, per http://wiremock.org/docs/configuration/ */ 28 | ); 29 | 30 | assertTrue("Server did not start on TCP port [" + HttpServer.DEFAULT_HTTP_LISTEN_PORT + " as expected.", 31 | !HttpServer.available(HttpServer.WIREMOCK_HOST,HttpServer.DEFAULT_HTTP_LISTEN_PORT)); 32 | 33 | String actualHttpResponse = myServer.getHttpResponse(); 34 | 35 | assertEquals("HttpServer did not return expected response", HttpServer.HTTP_RESPONSE, actualHttpResponse); 36 | 37 | } catch (Exception e) { 38 | fail("Unexpected exception"); 39 | } finally { 40 | myServer.stop(); 41 | assertTrue("HttpServer was unable to stop TCP port [" + HttpServer.DEFAULT_HTTP_LISTEN_PORT + " as expected.", 42 | HttpServer.available(HttpServer.WIREMOCK_HOST,HttpServer.DEFAULT_HTTP_LISTEN_PORT)); 43 | 44 | } 45 | 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/NcorvSaxHandler.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import org.xml.sax.Attributes; 6 | import org.xml.sax.SAXException; 7 | import org.xml.sax.helpers.DefaultHandler; 8 | 9 | 10 | public class NcorvSaxHandler extends DefaultHandler { 11 | private Ncorv ncorv; 12 | public NcorvSaxHandler(Ncorv val) { 13 | this.ncorv =val; 14 | } 15 | CountType current = null; 16 | @Override 17 | public void startElement (String uri, String localName, 18 | String qName, Attributes attributes) throws SAXException { 19 | 20 | if (qName.equals(CountType.HR7983.toString())) { 21 | this.current = CountType.HR7983; 22 | } else if (qName.equals(CountType.HR8587.toString())) { 23 | this.current = CountType.HR8587; 24 | } else if (qName.equals(CountType.HR8995.toString())) { 25 | this.current = CountType.HR8995; 26 | } else { 27 | this.current = CountType.OTHER; 28 | } 29 | //debug("current [" + this.current + "] uri[" + uri + "] localname[" + localName + "] qName[" + qName + "]"); 30 | } 31 | public void characters(char ch[], int start, int length) throws SAXException { 32 | 33 | String data = new String(ch, start, length); 34 | BigDecimal bd = null; 35 | if (this.current != null) { 36 | switch(this.current) { 37 | case HR7983: 38 | bd = new BigDecimal(data); 39 | ncorv.setHR7983( ncorv.getHR7983().add(bd) ); 40 | break; 41 | case HR8587: 42 | bd = new BigDecimal(data); 43 | ncorv.setHR8587( ncorv.getHR8587().add(bd) ); 44 | break; 45 | case HR8995: 46 | bd = new BigDecimal(data); 47 | ncorv.setHR8995( ncorv.getHR8995().add(bd) ); 48 | break; 49 | case OTHER: 50 | break; 51 | default: 52 | break; 53 | } 54 | } 55 | this.current = CountType.OTHER; 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/model/Transaction.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.model; 2 | 3 | import java.util.Date; 4 | import java.util.concurrent.ThreadLocalRandom; 5 | 6 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 7 | 8 | public class Transaction { 9 | //tid | bid | aid | delta | mtime | filler 10 | public long historyId = PerfSandboxUtil.UN_INIT; 11 | public int tellerId = PerfSandboxUtil.UN_INIT; 12 | public int branchId = PerfSandboxUtil.UN_INIT; 13 | public long accountId = PerfSandboxUtil.UN_INIT; 14 | public long delta = PerfSandboxUtil.UN_INIT; 15 | public Date mtime = null; 16 | public String filler = null; 17 | 18 | public Transaction(Transaction template) { 19 | this.historyId = template.historyId; 20 | this.tellerId = template.tellerId; 21 | this.branchId = template.branchId; 22 | this.accountId = template.accountId; 23 | this.delta = template.delta; 24 | this.mtime = new Date(template.mtime.getTime()); 25 | this.filler = new String(template.filler); 26 | 27 | } 28 | 29 | public Transaction() { 30 | } 31 | 32 | public static Transaction createFake(Long acctId) { 33 | Transaction t = new Transaction(); 34 | 35 | t.tellerId = ThreadLocalRandom.current().nextInt(5000); 36 | t.historyId = ThreadLocalRandom.current().nextInt(2500000); 37 | t.branchId = ThreadLocalRandom.current().nextInt(1000);; 38 | t.accountId = acctId; 39 | t.delta = ThreadLocalRandom.current().nextInt(200000); 40 | t.mtime = new Date(); 41 | t.filler = getRandomNineteenDigitString(); 42 | return t; 43 | } 44 | public static String getRandomNineteenDigitString() { 45 | ///these #'s approach max long, but not quite there. 46 | long myLong = ThreadLocalRandom.current().nextLong(1223372036854775807L,9223372036854775807L ); 47 | return Long.toString(myLong); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/SaxParserPool.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | import org.apache.commons.pool2.BasePooledObjectFactory; 4 | import org.apache.commons.pool2.PooledObject; 5 | import org.apache.commons.pool2.impl.DefaultPooledObject; 6 | import org.apache.commons.pool2.impl.GenericObjectPool; 7 | import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 8 | 9 | import javax.xml.parsers.SAXParser; 10 | import javax.xml.parsers.SAXParserFactory; 11 | 12 | public class SaxParserPool { 13 | private static GenericObjectPool pool = null; 14 | private static class LazyHolder { 15 | private static final SaxParserPool SINGLETON = new SaxParserPool(); 16 | } 17 | 18 | public static SaxParserPool getInstance() { 19 | return LazyHolder.SINGLETON; 20 | } 21 | public SAXParser borrowSAXParser() throws Exception { 22 | return pool.borrowObject(); 23 | } 24 | public void returnSAXParser(SAXParser parser) { 25 | pool.returnObject(parser); 26 | } 27 | public SaxParserPool() { 28 | GenericObjectPoolConfig config = new GenericObjectPoolConfig(); 29 | 30 | /** 31 | * set attributes on the config object before creating the pool 32 | * https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/GenericObjectPoolConfig.html 33 | */ 34 | this.pool = new GenericObjectPool(new Factory(), config); 35 | } 36 | 37 | } 38 | class Factory extends BasePooledObjectFactory { 39 | static final SAXParserFactory factory = SAXParserFactory.newInstance(); 40 | 41 | @Override 42 | public SAXParser create() throws Exception { 43 | return factory.newSAXParser(); 44 | } 45 | 46 | @Override 47 | public PooledObject wrap(SAXParser mySaxParser) { 48 | return new DefaultPooledObject(mySaxParser); 49 | } 50 | @Override 51 | public void passivateObject(PooledObject pooledObject) { 52 | //pooledObject.deallocate(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/UnpooledSaxParserWorker.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.InputStream; 5 | import java.math.BigDecimal; 6 | import java.util.Scanner; 7 | 8 | import javax.xml.parsers.SAXParser; 9 | import javax.xml.parsers.SAXParserFactory; 10 | 11 | 12 | 13 | public class UnpooledSaxParserWorker implements Ncorv { 14 | private static final String XML_INPUT_FILE = "/NCORV.xml"; 15 | private String xml; 16 | public BigDecimal bdHR7983; 17 | public BigDecimal bdHR8587; 18 | public BigDecimal bdHR8995; 19 | 20 | public void setup() { 21 | InputStream xmlStream = UnpooledSaxParserWorker.class.getResourceAsStream(XML_INPUT_FILE); 22 | this.xml = new Scanner(xmlStream,"UTF-8").useDelimiter("\\A").next(); 23 | } 24 | public void parse() { 25 | 26 | this.bdHR7983 = new BigDecimal(0); 27 | this.bdHR8587 = new BigDecimal(0); 28 | this.bdHR8995 = new BigDecimal(0); 29 | 30 | SAXParserFactory factory = SAXParserFactory.newInstance(); 31 | try { 32 | 33 | SAXParser saxParser = factory.newSAXParser(); 34 | NcorvSaxHandler handler = new NcorvSaxHandler(this); 35 | ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes()); 36 | saxParser.parse( bais, handler); 37 | 38 | } catch (Throwable err) { 39 | err.printStackTrace (); 40 | } 41 | } 42 | 43 | @Override 44 | public BigDecimal getHR7983() { 45 | return bdHR7983; 46 | } 47 | @Override 48 | public BigDecimal getHR8587() { 49 | return bdHR8587; 50 | } 51 | @Override 52 | public BigDecimal getHR8995() { 53 | return bdHR8995; 54 | } 55 | @Override 56 | public void setHR7983(BigDecimal val) { 57 | bdHR7983 = val; 58 | 59 | } 60 | @Override 61 | public void setHR8587(BigDecimal val) { 62 | bdHR8587 = val; 63 | 64 | } 65 | @Override 66 | public void setHR8995(BigDecimal val) { 67 | this.bdHR8995 = val; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_3/SqlTextMgr3.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_3; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.github.eostermueller.perfSandbox.dataaccess.BaseSqlTextMgr; 6 | import com.github.eostermueller.perfSandbox.dataaccess.TableNames; 7 | 8 | public class SqlTextMgr3 extends BaseSqlTextMgr { 9 | public Stats m_stats = new Stats(); 10 | 11 | public String getMultipleAccountsSql(int numAccountCriteria) { 12 | this.m_stats.m_accountAndHistorySql.incrementAndGet(); 13 | StringBuilder sb = new StringBuilder(); 14 | sb.append( "SELECT a.aid, a.bid, a.abalance, a.filler, a.filler01, a.filler02, a.filler03, a.filler04, a.filler05, a.filler06, a.filler07, a.filler08, a.filler09, a.filler10, a.filler11, a.filler12, a.filler13, a.filler14, a.filler15, a.filler16, a.filler17, a.filler18, a.filler19, a.filler20 FROM " 15 | + m_tableNames.getAccountTable() 16 | + " a WHERE aid in ("); 17 | 18 | for(int i =0; i< numAccountCriteria; i++) { 19 | if (i > 0) sb.append(","); 20 | sb.append("?"); 21 | } 22 | sb.append(")"); 23 | logSql(sb.toString()); 24 | 25 | return sb.toString(); 26 | } 27 | 28 | public String getHistoryByAccountSql() { 29 | 30 | this.m_stats.m_historyByAccountSql.incrementAndGet(); 31 | String sql = "SELECT tid, hid, bid, aid, delta, mtime, filler from " + m_tableNames.getHistoryTable() + " WHERE aid = ?"; 32 | logSql(sql); 33 | 34 | return sql; 35 | } 36 | 37 | public static class Stats { 38 | public AtomicLong m_accountAndHistorySql = new AtomicLong(0); 39 | public AtomicLong m_historyByAccountSql = new AtomicLong(0); 40 | public String getXmlStats() { 41 | StringBuilder sb = new StringBuilder(); 42 | sb.append("" + m_accountAndHistorySql + ""); 43 | sb.append("" + this.m_historyByAccountSql + ""); 44 | return sb.toString(); 45 | } 46 | 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_1/SqlTextMgr1.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_1; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.github.eostermueller.perfSandbox.dataaccess.BaseSqlTextMgr; 6 | import com.github.eostermueller.perfSandbox.dataaccess.TableNames; 7 | 8 | public class SqlTextMgr1 extends BaseSqlTextMgr { 9 | public Stats m_stats = new Stats(); 10 | 11 | public String getAccountAndHistorySql(int numAccountCriteria) { 12 | this.m_stats.m_accountAndHistorySql.incrementAndGet(); 13 | StringBuilder sb = new StringBuilder(); 14 | // sb.append( "SELECT a.aid, a.bid, a.abalance, a.filler, " 15 | // + "h.tid, h.hid, h.delta, h.mtime, h.filler FROM " 16 | // + m_tableNames.getAccountTable() + " a, " 17 | // + m_tableNames.getHistoryTable() + " h " 18 | // + "WHERE a.aid = h.aid AND a.aid in ("); 19 | 20 | sb.append( "SELECT A.AID, A.BID, A.ABALANCE, A.FILLER, a.FILLER02, A.FILLER02, A.FILLER03,A.FILLER04,A.FILLER05,A.FILLER06,A.FILLER07,A.FILLER08,A.FILLER09,A.FILLER10,A.FILLER11,A.FILLER12,A.FILLER13,A.FILLER14,A.FILLER15,A.FILLER16,A.FILLER17,A.FILLER18,A.FILLER19,A.FILLER20," 21 | + "h.tid, h.hid, h.delta, h.mtime, h.filler FROM " 22 | + m_tableNames.getAccountTable() + " A LEFT OUTER JOIN " 23 | + m_tableNames.getHistoryTable() + " h ON a.aid = h.aid "); 24 | 25 | if (numAccountCriteria > 0 ) { 26 | sb.append("WHERE a.aid in ("); 27 | for(int i =0; i< numAccountCriteria; i++) { 28 | if (i > 0) sb.append(","); 29 | sb.append("?"); 30 | } 31 | sb.append(") "); 32 | } 33 | sb.append("ORDER BY a.aid, h.mtime desc"); 34 | 35 | logSql(sb.toString()); 36 | return sb.toString(); 37 | } 38 | 39 | public static class Stats { 40 | public AtomicLong m_accountAndHistorySql = new AtomicLong(0); 41 | public String getXmlStats() { 42 | StringBuilder sb = new StringBuilder(); 43 | sb.append("" + m_accountAndHistorySql + ""); 44 | return sb.toString(); 45 | } 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/ApacheCommonsPooledSaxParserWorker.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | 4 | import java.io.ByteArrayInputStream; 5 | import java.io.InputStream; 6 | import java.math.BigDecimal; 7 | import java.util.Scanner; 8 | 9 | import javax.xml.parsers.SAXParser; 10 | 11 | import org.xml.sax.Attributes; 12 | import org.xml.sax.SAXException; 13 | import org.xml.sax.helpers.DefaultHandler; 14 | 15 | 16 | 17 | public class ApacheCommonsPooledSaxParserWorker implements Ncorv { 18 | private static SaxParserPool pool = new SaxParserPool(); 19 | private static final String XML_INPUT_FILE = "/NCORV.xml"; 20 | private String xml; 21 | public BigDecimal bdHR7983; 22 | public BigDecimal bdHR8587; 23 | public BigDecimal bdHR8995; 24 | 25 | @SuppressWarnings("resource") 26 | public void setup() { 27 | InputStream xmlStream = ApacheCommonsPooledSaxParserWorker.class.getResourceAsStream(XML_INPUT_FILE); 28 | this.xml = new Scanner(xmlStream,"UTF-8").useDelimiter("\\A").next(); 29 | } 30 | public void parse() { 31 | 32 | this.bdHR7983 = new BigDecimal(0); 33 | this.bdHR8587 = new BigDecimal(0); 34 | this.bdHR8995 = new BigDecimal(0); 35 | 36 | SAXParser saxParser = null; 37 | try { 38 | 39 | saxParser = pool.borrowSAXParser(); 40 | NcorvSaxHandler handler = new NcorvSaxHandler(this); 41 | ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes()); 42 | saxParser.parse( bais, handler); 43 | } catch (Throwable err) { 44 | err.printStackTrace (); 45 | } finally { 46 | pool.returnSAXParser(saxParser); 47 | } 48 | } 49 | 50 | @Override 51 | public BigDecimal getHR7983() { 52 | return bdHR7983; 53 | } 54 | @Override 55 | public BigDecimal getHR8587() { 56 | return bdHR8587; 57 | } 58 | @Override 59 | public BigDecimal getHR8995() { 60 | return bdHR8995; 61 | } 62 | @Override 63 | public void setHR7983(BigDecimal val) { 64 | bdHR7983 = val; 65 | 66 | } 67 | @Override 68 | public void setHR8587(BigDecimal val) { 69 | bdHR8587 = val; 70 | 71 | } 72 | @Override 73 | public void setHR8995(BigDecimal val) { 74 | this.bdHR8995 = val; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | dir=$(dirname "$0") 3 | 4 | export LOG=$dir/init.log 5 | 6 | echo "### init.sh start" >> $LOG 7 | date >> $LOG 8 | # echo "@@" 9 | # echo "@@" 10 | # echo "@@ About to initialize the performanceGolf war & db." 11 | # echo "@@ It will take about 5-10 minutes to populate the db." 12 | # echo "@@ To change location of this database, quit this script now and edit db/startDb.sh." 13 | # echo "@@" 14 | # echo "@@ Before proceeding:" 15 | # echo "@@ 1) Make sure you have 1gb of available disk space." 16 | # echo "@@ 2) Make sure Java 1.8 or greater is installed and JAVA_HOME/bin is in the path." 17 | # echo "@@ 3) Make sure Maven 3 or greater is installed and MAVEN_HOME/bin is in the path." 18 | # echo "@@" 19 | # read -p "@@ Press any key to continue, or Ctrl+C to exit." 20 | 21 | echo . 22 | echo . 23 | echo . 24 | echo "Please wait." 25 | echo "To follow progress of this install:" 26 | echo "1) open a separate terminal window to this folder: $PWD" 27 | echo "2) run this command: tail -f init.log" 28 | echo . 29 | echo . 30 | echo . 31 | 32 | chmod +x load.sh 33 | chmod +x startWar.sh 34 | chmod +x db/startDb.sh 35 | chmod +x db/stopDb.sh 36 | chmod +x db/countRows.sh 37 | chmod +x db/helpDb.sh 38 | 39 | #Build the WAR file used for all performance testing 40 | echo "### WAR file build" >> $LOG 41 | date >> $LOG 42 | mvn -f warProject/pom.xml clean package 1>> $LOG 2>&1 43 | 44 | ### 45 | ### Delete any existing database 46 | ### 47 | $dir/db/stopDb.sh 1>> $LOG 2>&1 48 | rm -rf $dir/db/data 49 | mkdir $dir/db/data 50 | 51 | ### 52 | ### Create blank DB and generate data into it. 53 | ### This is the part that takes 5-10 minutes. 54 | ### 55 | echo "### Starting DB" >> $LOG 56 | date >> $LOG 57 | $dir/db/startDb.sh 1>> $LOG 2>&1 & 58 | sleep 5 59 | echo "### After DB start" >> $LOG 60 | date >> $LOG 61 | 62 | echo "### DB Load 01" >> $LOG 63 | date >> $LOG 64 | $dir/load.sh loadDb-01 1>> $LOG 2>&1 65 | echo "### DB Load 02" >> $LOG 66 | date >> $LOG 67 | $dir/load.sh loadDb-02 1>> $LOG 2>&1 68 | echo "@@" 69 | echo "@@ Here are row counts of tables:" 70 | echo "@@" 71 | $dir/load.sh countRows-01 | grep S0 72 | $dir/load.sh countRows-02 | grep S0 73 | $dir/db/stopDb.sh 74 | 75 | echo "@@" 76 | echo "@@ init.sh is finished." 77 | echo "@@ The db has been stopped." 78 | echo "@@" 79 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_2/SqlTextMgr2.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_2; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.github.eostermueller.perfSandbox.dataaccess.BaseSqlTextMgr; 6 | import com.github.eostermueller.perfSandbox.dataaccess.TableNames; 7 | 8 | public class SqlTextMgr2 extends BaseSqlTextMgr { 9 | public Stats m_stats = new Stats(); 10 | 11 | 12 | public String getMultipleAccountsSql(int numAccountCriteria) { 13 | this.m_stats.m_accountAndHistorySql.incrementAndGet(); 14 | StringBuilder sb = new StringBuilder(); 15 | sb.append( "SELECT a.aid, a.bid, a.abalance, a.filler, a.filler01, a.filler02, a.filler03, a.filler04, a.filler05, a.filler06, a.filler07, a.filler08, a.filler09, a.filler10, a.filler11, a.filler12, a.filler13, a.filler14, a.filler15, a.filler16, a.filler17, a.filler18, a.filler19, a.filler20 FROM "); 16 | sb.append( m_tableNames.getAccountTable() ); 17 | sb.append( " a" );//the table alias 18 | 19 | if (numAccountCriteria >0) { 20 | sb.append(" WHERE aid in ("); 21 | for(int i =0; i< numAccountCriteria; i++) { 22 | if (i > 0) sb.append(","); 23 | sb.append("?"); 24 | } 25 | sb.append(")"); 26 | } 27 | 28 | logSql(sb.toString()); 29 | 30 | return sb.toString(); 31 | } 32 | 33 | public String getHistorySql(int numAccountCriteria) { 34 | this.m_stats.m_accountAndHistorySql.incrementAndGet(); 35 | StringBuilder sb = new StringBuilder(); 36 | sb.append(" SELECT tid , hid, bid , aid , delta , mtime , filler FROM "); 37 | sb.append(m_tableNames.getHistoryTable()); 38 | 39 | if (numAccountCriteria >0) { 40 | sb.append(" WHERE aid in ("); 41 | for(int i =0; i< numAccountCriteria; i++) { 42 | if (i > 0) sb.append(","); 43 | sb.append("?"); 44 | } 45 | sb.append(")"); 46 | 47 | } 48 | 49 | sb.append(" ORDER BY aid, hid"); 50 | logSql(sb.toString()); 51 | 52 | return sb.toString(); 53 | } 54 | 55 | public static class Stats { 56 | public AtomicLong m_accountAndHistorySql = new AtomicLong(0); 57 | public AtomicLong m_historyByAccountSql = new AtomicLong(0); 58 | public String getXmlStats() { 59 | StringBuilder sb = new StringBuilder(); 60 | sb.append("" + m_accountAndHistorySql + ""); 61 | sb.append("" + this.m_historyByAccountSql + ""); 62 | return sb.toString(); 63 | } 64 | 65 | } 66 | 67 | 68 | } 69 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/PerformanceSandboxApp.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import javax.annotation.Resource; 4 | 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.builder.SpringApplicationBuilder; 9 | //import org.springframework.boot.context.web.SpringBootServletInitializer; 10 | import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; 11 | import org.springframework.context.ApplicationContext; 12 | import org.springframework.context.annotation.ComponentScan; 13 | import org.springframework.context.annotation.PropertySource; 14 | import org.springframework.core.env.Environment; 15 | 16 | @SpringBootApplication 17 | @EnableAutoConfiguration 18 | ////@ComponentScan("com.github.eostermueller.perfSandbox.x07") 19 | //@ComponentScan 20 | @PropertySource("classpath:/application.properties") 21 | public class PerformanceSandboxApp extends SpringBootServletInitializer { 22 | 23 | /** 24 | * 25 | * NOT WORKING :-( 26 | * Some popular data available in this env. 27 | * http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html 28 | */ 29 | @Resource 30 | public Environment environment; 31 | public static ApplicationContext applicationContext= null; 32 | public static void main(String[] args) throws Exception { 33 | 34 | applicationContext = SpringApplication.run(PerformanceSandboxApp.class, args); 35 | } 36 | 37 | @Override 38 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 39 | return application.sources(PerformanceSandboxApp.class); 40 | } 41 | /** 42 | * Perhaps try this example to get the context path: 43 | * https://github.com/bijukunjummen/try-spring-boot-config 44 | * @return 45 | */ 46 | private String getContextPath() { 47 | String contextPath = this.environment.getProperty("server.context-path"); 48 | return contextPath; 49 | } 50 | private String getBaseUrl() { 51 | return "http://" + this.getServerAddress() + ":" + this.getPort() + this.getContextPath(); 52 | } 53 | private String getServerAddress() { 54 | String serverAddress = environment.getProperty("server.context-path"); 55 | return serverAddress; 56 | 57 | } 58 | private int getPort() { 59 | String port = environment.getProperty("local.server.port"); 60 | return Integer.valueOf(port); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/SaxParserTest.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.math.BigDecimal; 6 | 7 | import org.junit.Test; 8 | 9 | import com.github.eostermueller.perfSandbox.parse.ApacheCommonsPooledSaxParserWorker; 10 | import com.github.eostermueller.perfSandbox.parse.EclipseEmfPooledSaxParserWorker; 11 | import com.github.eostermueller.perfSandbox.parse.UnpooledSaxParserWorker; 12 | 13 | public class SaxParserTest { 14 | 15 | @Test 16 | public void testUnpooledImplementation() { 17 | UnpooledSaxParserWorker worker = new UnpooledSaxParserWorker(); 18 | worker.setup(); 19 | 20 | for(int i = 0; i < 5; i++) { 21 | worker.parse(); 22 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(278.647434).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR7983); 23 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(229.865371).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8587); 24 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(245.139347).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8995); 25 | } 26 | } 27 | @Test 28 | public void testApachePooledImplementation() { 29 | ApacheCommonsPooledSaxParserWorker worker = new ApacheCommonsPooledSaxParserWorker(); 30 | worker.setup(); 31 | 32 | for(int i = 0; i < 5; i++) { 33 | worker.parse(); 34 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(278.647434).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR7983); 35 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(229.865371).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8587); 36 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(245.139347).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8995); 37 | } 38 | } 39 | @Test 40 | public void testEclipseEmfPooledImplementation() { 41 | EclipseEmfPooledSaxParserWorker worker = new EclipseEmfPooledSaxParserWorker(); 42 | worker.setup(); 43 | 44 | for(int i = 0; i < 5; i++) { 45 | worker.parse(); 46 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(278.647434).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR7983); 47 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(229.865371).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8587); 48 | assertEquals("incorrect calculation from data in NCORV.xml data file", new BigDecimal(245.139347).setScale(6, BigDecimal.ROUND_HALF_UP), worker.bdHR8995); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_4/PkInquiry4.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_4; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.List; 8 | 9 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 10 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 11 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 12 | import com.github.eostermueller.perfSandbox.model.Account; 13 | import com.github.eostermueller.perfSandbox.model.Branch; 14 | import com.github.eostermueller.perfSandbox.model.Transaction; 15 | 16 | 17 | public class PkInquiry4 { 18 | public PkInquiry4(PerfSandboxSingleton val) { 19 | this.pgBench = val; 20 | } 21 | private PerfSandboxSingleton pgBench = null; 22 | public Account getAccount(long accountId) throws SQLException, PerfSandboxException { 23 | Account account = new Account(); 24 | Connection con = null; 25 | PreparedStatement ps = null; 26 | ResultSet rs = null; 27 | try { 28 | con = pgBench.getConnection(); 29 | ps = con.prepareStatement( AccountMgr4.m_sqlTextMgr4.getAccountPkInquirySql() ); 30 | ps.setLong(1, accountId); 31 | 32 | rs = ps.executeQuery(); 33 | short count = 0; 34 | while(rs.next()) { 35 | if (++count >1) 36 | throw new PerfSandboxException("Expecting only a single account record, but found at least 2 for accountId [" + accountId + "]"); 37 | account.accountId = rs.getLong(1); 38 | account.branchId = rs.getInt(2); 39 | account.balance = rs.getLong(3); 40 | account.filler = rs.getString(4); 41 | account.filler01 = rs.getString(5); 42 | account.filler02 = rs.getString(6); 43 | account.filler03 = rs.getString(7); 44 | account.filler04 = rs.getString(8); 45 | account.filler05 = rs.getString(9); 46 | account.filler06 = rs.getString(10); 47 | account.filler07 = rs.getString(11); 48 | account.filler08 = rs.getString(12); 49 | account.filler09 = rs.getString(13); 50 | account.filler10 = rs.getString(14); 51 | account.filler11 = rs.getString(15); 52 | account.filler12 = rs.getString(16); 53 | account.filler13 = rs.getString(17); 54 | account.filler14 = rs.getString(18); 55 | account.filler15 = rs.getString(19); 56 | account.filler16 = rs.getString(20); 57 | account.filler17 = rs.getString(21); 58 | account.filler18 = rs.getString(22); 59 | account.filler19 = rs.getString(23); 60 | account.filler20 = rs.getString(24); 61 | } 62 | } finally { 63 | PerfSandboxUtil.closeQuietly(rs); 64 | PerfSandboxUtil.closeQuietly(ps); 65 | PerfSandboxUtil.closeQuietly(con); 66 | } 67 | return account; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/parse/EclipseEmfPooledSaxParserWorker.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.parse; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.InputStream; 5 | import java.math.BigDecimal; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.Scanner; 9 | 10 | import javax.xml.parsers.SAXParser; 11 | 12 | import org.eclipse.emf.ecore.xmi.XMLParserPool; 13 | import org.xml.sax.Attributes; 14 | import org.xml.sax.SAXException; 15 | import org.xml.sax.helpers.DefaultHandler; 16 | import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl; 17 | 18 | 19 | public class EclipseEmfPooledSaxParserWorker implements Ncorv { 20 | private XMLParserPool parserPool = new XMLParserPoolImpl(); 21 | 22 | private static final String XML_INPUT_FILE = "/NCORV.xml"; 23 | private String xml; 24 | public BigDecimal bdHR7983; 25 | public BigDecimal bdHR8587; 26 | public BigDecimal bdHR8995; 27 | Map parserFeatures = new HashMap(); 28 | Map parserProperties = new HashMap(); 29 | 30 | @SuppressWarnings("resource") 31 | public void setup() { 32 | InputStream xmlStream = EclipseEmfPooledSaxParserWorker.class.getResourceAsStream(XML_INPUT_FILE); 33 | this.xml = new Scanner(xmlStream,"UTF-8").useDelimiter("\\A").next(); 34 | parserFeatures.put("http://xml.org/sax/features/validation", Boolean.FALSE); //$NON-NLS-1$ 35 | parserFeatures.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", Boolean.FALSE); 36 | } 37 | public void parse() { 38 | 39 | this.bdHR7983 = new BigDecimal(0); 40 | this.bdHR8587 = new BigDecimal(0); 41 | this.bdHR8995 = new BigDecimal(0); 42 | 43 | SAXParser saxParser = null; 44 | try { 45 | 46 | saxParser = parserPool.get(parserFeatures, parserProperties, Boolean.FALSE); 47 | NcorvSaxHandler handler = new NcorvSaxHandler(this); 48 | ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes()); 49 | saxParser.parse( bais, handler); 50 | 51 | 52 | } catch (Throwable err) { 53 | err.printStackTrace (); 54 | } finally { 55 | parserPool.release(saxParser, parserFeatures, parserProperties, Boolean.FALSE); 56 | } 57 | } 58 | @Override 59 | public BigDecimal getHR7983() { 60 | return bdHR7983; 61 | } 62 | @Override 63 | public BigDecimal getHR8587() { 64 | return bdHR8587; 65 | } 66 | @Override 67 | public BigDecimal getHR8995() { 68 | return bdHR8995; 69 | } 70 | @Override 71 | public void setHR7983(BigDecimal val) { 72 | bdHR7983 = val; 73 | 74 | } 75 | @Override 76 | public void setHR8587(BigDecimal val) { 77 | bdHR8587 = val; 78 | 79 | } 80 | @Override 81 | public void setHR8995(BigDecimal val) { 82 | this.bdHR8995 = val; 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_4/AccountMgr4.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_4; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 13 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 14 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 15 | import com.github.eostermueller.perfSandbox.model.Account; 16 | import com.github.eostermueller.perfSandbox.model.Accounts; 17 | import com.github.eostermueller.perfSandbox.model.Transaction; 18 | 19 | 20 | public class AccountMgr4 { 21 | public AccountMgr4(PerfSandboxSingleton val) { 22 | this.pgBench = val; 23 | this.m_sqlTextMgr4.setLogger(val); 24 | 25 | this.m_pkInquiry4 = new PkInquiry4(val); 26 | 27 | } 28 | private PerfSandboxSingleton pgBench = null; 29 | private PkInquiry4 m_pkInquiry4 = null; 30 | // private ListInquiry m_listInquiry; 31 | 32 | public static SqlTextMgr4 m_sqlTextMgr4 = new SqlTextMgr4(); 33 | public Accounts getAccounts(List randomAccountIds) { 34 | Accounts accounts = new Accounts(); 35 | for( long accountId : randomAccountIds) { 36 | try { 37 | Account a = m_pkInquiry4.getAccount(accountId); 38 | getAccountHistory(a); 39 | accounts.addAccount( a ); 40 | } catch (SQLException e) { 41 | e.printStackTrace(); 42 | } catch (PerfSandboxException e) { 43 | e.printStackTrace(); 44 | } 45 | } 46 | return accounts; 47 | } 48 | 49 | public void getAccountHistory(Account val) throws SQLException, PerfSandboxException { 50 | val.transactions = getTransactions(val.accountId); 51 | } 52 | private List getTransactions(long accountId) throws SQLException, PerfSandboxException { 53 | 54 | Connection con = null; 55 | PreparedStatement ps = null; 56 | ResultSet rs = null; 57 | List list = null; 58 | try { 59 | con = pgBench.getConnection(); 60 | ps = con.prepareStatement( m_sqlTextMgr4.getHistoryByAccountSql() ); 61 | ps.setLong(1, accountId); 62 | rs = ps.executeQuery(); 63 | list = new ArrayList(); 64 | while(rs.next()) { 65 | Transaction t = new Transaction(); 66 | t.tellerId = rs.getInt(1); 67 | t.historyId = rs.getLong(2); 68 | t.branchId = rs.getInt(3); 69 | t.accountId = rs.getInt(4); 70 | t.delta = rs.getLong(5); 71 | t.mtime = PerfSandboxUtil.getDate(rs, 6); 72 | t.filler = rs.getString(7); 73 | list.add(t); 74 | } 75 | } finally { 76 | PerfSandboxUtil.closeQuietly(rs); 77 | PerfSandboxUtil.closeQuietly(ps); 78 | PerfSandboxUtil.closeQuietly(con); 79 | } 80 | return list; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_5/SqlTextMgr5.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_5; 2 | 3 | import java.util.concurrent.atomic.AtomicLong; 4 | 5 | import com.github.eostermueller.perfSandbox.dataaccess.BaseSqlTextMgr; 6 | import com.github.eostermueller.perfSandbox.dataaccess.TableNames; 7 | 8 | public class SqlTextMgr5 extends BaseSqlTextMgr { 9 | public Stats m_stats = new Stats(); 10 | 11 | public String getAccountPkInquirySql() { 12 | this.m_stats.m_accountPkInquirySql.incrementAndGet(); 13 | //String sql = "SELECT aid, bid, abalance, filler from " + m_tableNames.getAccountTable() + " WHERE aid = ?"; 14 | String sql = "SELECT aid, bid, abalance, filler, filler01, filler02, filler03, filler04, filler05, filler06, filler07, filler08, filler09, filler10, filler11, filler12, filler13, filler14, filler15, filler16, filler17, filler18, filler19, filler20 from " + m_tableNames.getAccountTable() + " WHERE aid = ?"; 15 | logSql(sql); 16 | return sql; 17 | } 18 | public String getHistoryListSql() { 19 | this.m_stats.m_historyListSql.incrementAndGet(); 20 | String sql = "SELECT hid from " + m_tableNames.getHistoryTable() + " WHERE aid = ?"; 21 | logSql(sql); 22 | return sql; 23 | } 24 | public String getHistoryPkInquirySql() { 25 | this.m_stats.m_historyPkInquirySql.incrementAndGet(); 26 | String sql = "SELECT tid, hid, bid, aid, delta, mtime, filler from " + m_tableNames.getHistoryTable() + " WHERE hid = ?"; 27 | logSql(sql); 28 | return sql; 29 | } 30 | public String getBranchPkInquirySql() { 31 | this.m_stats.m_branchPkInquirySql.incrementAndGet(); 32 | String sql = "SELECT bid, bbalance, filler from " + m_tableNames.getBranchTable() + " WHERE bid = ?"; 33 | logSql(sql); 34 | return sql; 35 | } 36 | 37 | public String getTellerPkInquiry() { 38 | this.m_stats.m_tellerPkInquirySql.incrementAndGet(); 39 | String sql = "SELECT tid, bid, tbalance, filler from " + m_tableNames.getTellerTable() + " WHERE tid = ?"; 40 | logSql(sql); 41 | return sql; 42 | } 43 | 44 | public static class Stats { 45 | public AtomicLong m_accountPkInquirySql = new AtomicLong(); 46 | public AtomicLong m_historyListSql = new AtomicLong(); 47 | public AtomicLong m_historyPkInquirySql= new AtomicLong(); 48 | public AtomicLong m_branchPkInquirySql = new AtomicLong(); 49 | public AtomicLong m_tellerPkInquirySql = new AtomicLong(); 50 | public String getXmlStats() { 51 | StringBuilder sb = new StringBuilder(); 52 | sb.append("" + m_accountPkInquirySql + ""); 53 | sb.append("" + m_historyListSql + ""); 54 | sb.append("" + m_historyPkInquirySql + ""); 55 | sb.append("" + m_branchPkInquirySql + ""); 56 | sb.append("" + m_tellerPkInquirySql + ""); 57 | return sb.toString(); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/CachedBranchInquiryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.sql.Connection; 6 | import java.sql.SQLException; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | import javax.sql.DataSource; 10 | 11 | import org.h2.jdbcx.JdbcConnectionPool; 12 | import org.junit.AfterClass; 13 | import org.junit.BeforeClass; 14 | import org.junit.Test; 15 | 16 | import com.github.eostermueller.perfSandbox.cache.CachedBranchInquiryImpl; 17 | 18 | public class CachedBranchInquiryTest { 19 | private static final int INQUIRY_COUNT = 5; 20 | private static final int MAX_BRANCH_COUNT = 100; 21 | static BranchInquiry branchInquiry = null; 22 | private static String JDBC_URL ="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; 23 | private static DataSource dataSource = null; 24 | private AtomicInteger physicalBranchSelectCount = new AtomicInteger(0); 25 | public static DataSource getDataSource() { 26 | return dataSource; 27 | } 28 | 29 | @BeforeClass 30 | public static void setup() throws SQLException { 31 | 32 | dbSetup(); 33 | 34 | branchInquiry = new CachedBranchInquiryImpl(); 35 | branchInquiry.setDataSource( getDataSource() ); 36 | branchInquiry.setInquiryCount(INQUIRY_COUNT); 37 | branchInquiry.setTableName("BRANCHES"); 38 | branchInquiry.setMaxBranchId(MAX_BRANCH_COUNT); 39 | 40 | } 41 | @AfterClass 42 | public static void dbShutdown() throws SQLException { 43 | getDataSource().getConnection().createStatement().executeUpdate("DROP TABLE BRANCHES"); 44 | getDataSource().getConnection().close(); 45 | } 46 | 47 | private static void dbSetup() throws SQLException { 48 | dataSource = JdbcConnectionPool.create(JDBC_URL, "user", "password"); 49 | Connection conn = getDataSource().getConnection(); 50 | 51 | conn.createStatement().executeUpdate("CREATE TABLE BRANCHES (" 52 | + "bid int not null," 53 | + "bbalance int," 54 | + "filler char(88));"); 55 | 56 | for (int i = 1; i <= MAX_BRANCH_COUNT; i++) { 57 | String sql = "INSERT INTO BRANCHES (BID, BBALANCE, FILLER ) values ("+i+", "+i+",'"+i+"x"+i+"x"+i+"x"+i+"')"; 58 | System.out.println(sql); 59 | conn.createStatement().executeUpdate(sql); 60 | } 61 | } 62 | @Test 63 | public void cannotMakePhysicalReadForTwoConsecutiveRequests() throws SQLException { 64 | // 65 | branchInquiry.resetTotalPhysicalCount(); 66 | assertEquals("sanity check failed", 0, branchInquiry.getTotalPhysicalCount()); 67 | 68 | /** 69 | * F I R S T T I M E 70 | */ 71 | String branchName = branchInquiry.logicalBranchNameInquiry(95); 72 | 73 | assertEquals("Lookup to db did not find correct branchName/filler","95x95x95x95", branchName); 74 | assertEquals("Just executed a single SQL, but didn't tally the count correctly", 75 | 1, branchInquiry.getTotalPhysicalCount()); 76 | 77 | /** 78 | * S E C O N D T I M E 79 | */ 80 | branchName = branchInquiry.logicalBranchNameInquiry(95); 81 | 82 | assertEquals("Lookup to db did not find correct branchName/filler","95x95x95x95", branchName); 83 | 84 | // asserting that caching is taking place 85 | assertEquals("Just made a second logical read, and the read unexpectedly went to disk!", 86 | 1, branchInquiry.getTotalPhysicalCount()); 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/TestBusyCpuProcessor.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.lang.management.ManagementFactory; 6 | import java.lang.management.OperatingSystemMXBean; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import javax.management.Attribute; 10 | import javax.management.AttributeList; 11 | import javax.management.InstanceNotFoundException; 12 | import javax.management.MBeanServer; 13 | import javax.management.MalformedObjectNameException; 14 | import javax.management.ObjectName; 15 | import javax.management.ReflectionException; 16 | import org.junit.Test; 17 | 18 | public class TestBusyCpuProcessor { 19 | 20 | /** 21 | * I could not find a reliable JVM way to measure CPU. 22 | * So this is a manual test. Comment in the "@Test", run this method, and watch your CPU montior...make sure about one core is in use for the duration. 23 | * @throws MalformedObjectNameException 24 | * @throws InstanceNotFoundException 25 | * @throws ReflectionException 26 | */ 27 | //@Test 28 | public void cpuTest() throws MalformedObjectNameException, InstanceNotFoundException, ReflectionException { 29 | BusyCpuProcessor bcp = new BusyCpuProcessor(); 30 | 31 | try { 32 | bcp.start(); 33 | TimeUnit.SECONDS.sleep(60); 34 | 35 | } catch (InterruptedException e) { 36 | // TODO Auto-generated catch block 37 | e.printStackTrace(); 38 | } finally { 39 | bcp.stop(); 40 | } 41 | 42 | 43 | } 44 | @Test 45 | public void simpleTest() { 46 | 47 | BusyCpuProcessor bcp = new BusyCpuProcessor(); 48 | 49 | try { 50 | assertFalse("Haven't done anything yet -- should be stopped", bcp.isStarted() ); 51 | 52 | bcp.start(); 53 | 54 | mySleep(); 55 | 56 | assertTrue("this test just invoked start, but status is wrong ", bcp.isStarted() ); 57 | 58 | 59 | } finally { 60 | bcp.stop(); 61 | mySleep(); 62 | assertFalse("Just requested a stop -- so it should be stopped", bcp.isStarted() ); 63 | } 64 | 65 | 66 | } 67 | @Test 68 | public void stopAndStartMultipleTimes() { 69 | BusyCpuProcessor bcp = new BusyCpuProcessor(); 70 | 71 | try { 72 | bcp.start(); 73 | assertTrue("this test just invoked start, but status is wrong ", bcp.isStarted() ); 74 | bcp.start(); 75 | mySleep(); 76 | bcp.start(); 77 | mySleep(); 78 | bcp.start(); 79 | mySleep(); 80 | bcp.start(); 81 | mySleep(); 82 | bcp.start(); 83 | mySleep(); 84 | bcp.stop(); 85 | mySleep(); 86 | bcp.start(); 87 | mySleep(); 88 | bcp.stop(); 89 | mySleep(); 90 | bcp.stop(); 91 | mySleep(); 92 | bcp.start(); 93 | mySleep(); 94 | bcp.stop(); 95 | mySleep(); 96 | bcp.start(); 97 | mySleep(); 98 | bcp.stop(); 99 | mySleep(); 100 | bcp.start(); 101 | mySleep(); 102 | bcp.stop(); 103 | mySleep(); 104 | bcp.start(); 105 | mySleep(); 106 | bcp.stop(); 107 | mySleep(); 108 | bcp.start(); 109 | mySleep(); 110 | bcp.stop(); 111 | mySleep(); 112 | bcp.start(); 113 | 114 | } finally { 115 | mySleep(); 116 | bcp.stop(); 117 | mySleep(); 118 | assertFalse("Just requested a stop -- so it should be stopped", bcp.isStarted() ); 119 | 120 | } 121 | 122 | 123 | } 124 | private void mySleep() { 125 | try { 126 | Thread.sleep(BusyCpuProcessor.SLEEP_TIME_MS);//value of 10 caused exceptions. 127 | } catch (InterruptedException e) { 128 | // TODO Auto-generated catch block 129 | e.printStackTrace(); 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/AbstractBranchInquiry.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.concurrent.ThreadLocalRandom; 8 | import java.util.concurrent.atomic.AtomicLong; 9 | 10 | import javax.sql.DataSource; 11 | 12 | public abstract class AbstractBranchInquiry implements BranchInquiry { 13 | 14 | private String tableName = null; 15 | 16 | public String getTableName() { 17 | return tableName; 18 | } 19 | 20 | public void setTableName(String tableName) { 21 | this.tableName = tableName; 22 | } 23 | private DataSource dataSource; 24 | private int inquiryCount; 25 | private int maxBranchId; 26 | private AtomicLong totalPhysicalCount = new AtomicLong(0); 27 | 28 | @Override 29 | public void resetTotalPhysicalCount() { 30 | this.totalPhysicalCount.set(0); 31 | } 32 | 33 | @Override 34 | public String randomBranchInquiries() throws SQLException { 35 | 36 | long randomBranchId = -1; 37 | String filler = null; 38 | StringBuilder sb = new StringBuilder(); 39 | for(int i = 0; i < this.getInquiryCount(); i++) { 40 | String branchName = this.randomLogicalBranchInquiry(); 41 | sb.append(branchName).append("\n"); 42 | } 43 | return sb.toString(); 44 | } 45 | 46 | @Override 47 | abstract public String logicalBranchNameInquiry(long branchId) throws SQLException; 48 | 49 | @Override 50 | public 51 | abstract void shutdown(); 52 | 53 | @Override 54 | public void setDataSource(DataSource dataSource) { 55 | this.dataSource = dataSource; 56 | } 57 | @Override 58 | public DataSource getDataSource() throws SQLException { 59 | return this.dataSource; 60 | } 61 | 62 | @Override 63 | public void setInquiryCount(int val) { 64 | this.inquiryCount = val; 65 | } 66 | 67 | @Override 68 | public void setMaxBranchId(int maxBranchId) { 69 | this.maxBranchId = maxBranchId; 70 | } 71 | @Override 72 | public int getMaxBranchId() throws SQLException { 73 | return this.maxBranchId; 74 | } 75 | @Override 76 | public int getInquiryCount() { 77 | return this.inquiryCount; 78 | } 79 | @Override 80 | public 81 | long getTotalPhysicalCount() { 82 | return this.totalPhysicalCount.get(); 83 | } 84 | @Override 85 | public 86 | void incrementTotalPhysicalCount() { 87 | totalPhysicalCount.incrementAndGet(); 88 | } 89 | 90 | public long getRandomBranchId() throws SQLException { 91 | 92 | /** 93 | * The two data bases will likely have different max branch ids. 94 | * If a table has only 1000 branch ids (1-1000 is how the load script is designed) 95 | * then querying for branch 1001 would produce and error we want to avoid. 96 | */ 97 | 98 | return (long)ThreadLocalRandom.current().nextDouble(1, getMaxBranchId() ); 99 | } 100 | 101 | 102 | @Override 103 | public String randomLogicalBranchInquiry() throws SQLException { 104 | long randomBranchId = this.getRandomBranchId(); 105 | return logicalBranchNameInquiry(randomBranchId); 106 | } 107 | @Override 108 | public String physicalBranchNameInquiry(long branchId) throws SQLException { 109 | 110 | Connection conn = getDataSource().getConnection(); 111 | String rc = ""; 112 | ResultSet rs = null; 113 | PreparedStatement stmt = null; 114 | try { 115 | stmt = conn.prepareStatement("SELECT FILLER from " + this.getTableName() + " where bid=?" ); 116 | stmt.setLong(1, branchId); 117 | rs = stmt.executeQuery(); 118 | rs.next(); 119 | rc = rs.getString(1); 120 | this.incrementTotalPhysicalCount(); 121 | } finally { 122 | if (rs!=null) rs.close(); 123 | if (stmt!=null) stmt.close(); 124 | if (conn!=null) conn.close(); 125 | } 126 | return rc; 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /warProject/src/test/java/com/github/eostermueller/perfSandbox/UncachedBranchInquiryTest.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.sql.Connection; 6 | import java.sql.SQLException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | import javax.sql.DataSource; 12 | import javax.xml.parsers.ParserConfigurationException; 13 | import javax.xml.parsers.SAXParser; 14 | 15 | import org.eclipse.emf.ecore.xmi.XMLParserPool; 16 | import org.eclipse.emf.ecore.xmi.impl.XMLParserPoolImpl; 17 | import org.h2.jdbcx.JdbcConnectionPool; 18 | import org.junit.AfterClass; 19 | import org.junit.Before; 20 | import org.junit.BeforeClass; 21 | import org.junit.Test; 22 | import org.xml.sax.Attributes; 23 | import org.xml.sax.SAXException; 24 | import org.xml.sax.helpers.DefaultHandler; 25 | 26 | import com.github.eostermueller.perfSandbox.cache.UncachedBranchInquiryImpl; 27 | 28 | public class UncachedBranchInquiryTest { 29 | private static final int INQUIRY_COUNT = 5; 30 | private static final int MAX_BRANCH_COUNT = 100; 31 | static BranchInquiry branchInquiry = null; 32 | private static String JDBC_URL ="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"; 33 | private static DataSource dataSource = null; 34 | private AtomicInteger physicalBranchSelectCount = new AtomicInteger(0); 35 | public static DataSource getDataSource() { 36 | return dataSource; 37 | } 38 | 39 | @BeforeClass 40 | public static void setup() throws SQLException { 41 | 42 | dbSetup(); 43 | 44 | branchInquiry = new UncachedBranchInquiryImpl(); 45 | branchInquiry.setDataSource( getDataSource() ); 46 | branchInquiry.setInquiryCount(INQUIRY_COUNT); 47 | branchInquiry.setTableName("BRANCHES"); 48 | branchInquiry.setMaxBranchId(MAX_BRANCH_COUNT); 49 | 50 | } 51 | @AfterClass 52 | public static void dbShutdown() throws SQLException { 53 | getDataSource().getConnection().createStatement().executeUpdate("DROP TABLE BRANCHES"); 54 | getDataSource().getConnection().close(); 55 | } 56 | 57 | private static void dbSetup() throws SQLException { 58 | dataSource = JdbcConnectionPool.create(JDBC_URL, "user", "password"); 59 | Connection conn = getDataSource().getConnection(); 60 | 61 | conn.createStatement().executeUpdate("CREATE TABLE BRANCHES (" 62 | + "bid int not null," 63 | + "bbalance int," 64 | + "filler char(88));"); 65 | 66 | for (int i = 1; i <= MAX_BRANCH_COUNT; i++) { 67 | String sql = "INSERT INTO BRANCHES (BID, BBALANCE, FILLER ) values ("+i+", "+i+",'"+i+"x"+i+"x"+i+"x"+i+"')"; 68 | System.out.println(sql); 69 | conn.createStatement().executeUpdate(sql); 70 | } 71 | } 72 | @Test 73 | public void canMakePhysicalReadForTwoConsecutiveRequests() throws SQLException { 74 | // 75 | branchInquiry.resetTotalPhysicalCount(); 76 | assertEquals("sanity check failed", 0, branchInquiry.getTotalPhysicalCount()); 77 | 78 | /** 79 | * F I R S T T I M E 80 | */ 81 | String branchName = branchInquiry.logicalBranchNameInquiry(95); 82 | 83 | assertEquals("Lookup to db did not find correct branchName/filler","95x95x95x95", branchName); 84 | assertEquals("Just executed a single SQL, but didn't tally the count correctly", 85 | 1, branchInquiry.getTotalPhysicalCount()); 86 | 87 | /** 88 | * S E C O N D T I M E 89 | */ 90 | branchName = branchInquiry.logicalBranchNameInquiry(95); 91 | 92 | assertEquals("Lookup to db did not find correct branchName/filler","95x95x95x95", branchName); 93 | // asserting that no caching is taking place here. 94 | assertEquals("Just executed a second SQL, but didn't tally the count correctly", 95 | 2, branchInquiry.getTotalPhysicalCount()); 96 | 97 | } 98 | 99 | @Test 100 | public void canSelectData() throws SQLException { 101 | 102 | branchInquiry.resetTotalPhysicalCount(); 103 | branchInquiry.randomBranchInquiries(); 104 | 105 | assertEquals("Did not make physical call to DB the expected number of times", 106 | INQUIRY_COUNT, 107 | branchInquiry.getTotalPhysicalCount()); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_2/AllAccountMgr2.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_2; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.List; 8 | 9 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 10 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 11 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 12 | import com.github.eostermueller.perfSandbox.model.Account; 13 | import com.github.eostermueller.perfSandbox.model.Accounts; 14 | import com.github.eostermueller.perfSandbox.model.Transaction; 15 | 16 | public class AllAccountMgr2 { 17 | public AllAccountMgr2(PerfSandboxSingleton val) { 18 | this.pgBench = val; 19 | m_sqlTextMgr2.setLogger(val); 20 | } 21 | private PerfSandboxSingleton pgBench = null; 22 | 23 | public static SqlTextMgr2 m_sqlTextMgr2 = new SqlTextMgr2(); 24 | public Accounts getAllAccountsAndCrashJvm() throws PerfSandboxException { 25 | Accounts accounts = getAccountsInternal(); 26 | 27 | getTransactions(accounts); 28 | 29 | return accounts; 30 | } 31 | 32 | private Accounts getAccountsInternal() throws PerfSandboxException { 33 | final int ALL_ACCTS = 0; 34 | Connection con = null; 35 | PreparedStatement ps = null; 36 | ResultSet rs = null; 37 | Accounts accounts = new Accounts(); 38 | try { 39 | con = pgBench.getConnection(); 40 | ps = con.prepareStatement( m_sqlTextMgr2.getMultipleAccountsSql(ALL_ACCTS)); 41 | rs = ps.executeQuery(); 42 | short count = 0; 43 | 44 | while(rs.next()) { 45 | Account a = createAccount(rs); 46 | accounts.addAccount(a); 47 | } 48 | } catch (SQLException e) { 49 | throw new PerfSandboxException(e); 50 | } finally { 51 | PerfSandboxUtil.closeQuietly(rs); 52 | PerfSandboxUtil.closeQuietly(ps); 53 | PerfSandboxUtil.closeQuietly(con); 54 | } 55 | return accounts; 56 | } 57 | 58 | private Account createAccount(ResultSet rs) throws SQLException { 59 | Account a = new Account(); 60 | a.accountId = rs.getLong(1); 61 | a.branchId = rs.getInt(2); 62 | a.balance = rs.getLong(3); 63 | a.filler = rs.getString(4); 64 | a.filler01 = rs.getString(5); 65 | a.filler02 = rs.getString(6); 66 | a.filler03 = rs.getString(7); 67 | a.filler04 = rs.getString(8); 68 | a.filler05 = rs.getString(9); 69 | a.filler06 = rs.getString(10); 70 | a.filler07 = rs.getString(11); 71 | a.filler08 = rs.getString(12); 72 | a.filler09 = rs.getString(13); 73 | a.filler10 = rs.getString(14); 74 | a.filler11 = rs.getString(15); 75 | a.filler12 = rs.getString(16); 76 | a.filler13 = rs.getString(17); 77 | a.filler14 = rs.getString(18); 78 | a.filler15 = rs.getString(19); 79 | a.filler16 = rs.getString(20); 80 | a.filler17 = rs.getString(21); 81 | a.filler18 = rs.getString(22); 82 | a.filler19 = rs.getString(23); 83 | a.filler20 = rs.getString(24); 84 | return a; 85 | } 86 | private void getTransactions(Accounts accounts) throws PerfSandboxException { 87 | 88 | Connection con = null; 89 | PreparedStatement ps = null; 90 | ResultSet rs = null; 91 | try { 92 | con = pgBench.getConnection(); 93 | ps = con.prepareStatement( m_sqlTextMgr2.getHistorySql(0) ); 94 | 95 | rs = ps.executeQuery(); 96 | while(rs.next()) { 97 | Transaction t = new Transaction(); 98 | t.tellerId = rs.getInt(1); 99 | t.historyId = rs.getLong(2); 100 | t.branchId = rs.getInt(3); 101 | t.accountId = rs.getInt(4); 102 | t.delta = rs.getLong(5); 103 | t.mtime = PerfSandboxUtil.getDate(rs, 6); 104 | t.filler = rs.getString(7); 105 | Account a = accounts.findAccount(t.accountId); 106 | if (a!=null) 107 | a.transactions.add(t); 108 | else 109 | throw new PerfSandboxException("Found transaction with account id = [" + t.accountId + "], but it didn't have a matching account. Full transactions [" + t.toString() + "]"); 110 | } 111 | } catch (SQLException e) { 112 | throw new PerfSandboxException(e); 113 | } finally { 114 | PerfSandboxUtil.closeQuietly(rs); 115 | PerfSandboxUtil.closeQuietly(ps); 116 | PerfSandboxUtil.closeQuietly(con); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /warProject/src/main/resources/NCORV.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Oconee 4 | Georgia 5 | 7.768076 6 | 2.210482 7 | 5.287129 8 | 9 | 10 | De Kalb 11 | Georgia 12 | 11.655774 13 | 12.144973 14 | 15.537506 15 | 16 | 17 | Cleburne 18 | Alabama 19 | 18.881878 20 | 10.553811 21 | 16.558485 22 | 23 | 24 | Walton 25 | Georgia 26 | 12.090129 27 | 8.585492 28 | 8.217715 29 | 30 | 31 | Haralson 32 | Georgia 33 | 10.641921 34 | 8.011793 35 | 6.360271 36 | 37 | 38 | Carroll 39 | Georgia 40 | 12.027491 41 | 10.694697 42 | 8.870924 43 | 44 | 45 | Morgan 46 | Georgia 47 | 15.323583 48 | 10.743735 49 | 9.630200 50 | 51 | 52 | Douglas 53 | Georgia 54 | 9.302292 55 | 6.193037 56 | 5.854757 57 | 58 | 59 | Rockdale 60 | Georgia 61 | 4.789986 62 | 8.838802 63 | 3.912564 64 | 65 | 66 | Greene 67 | Georgia 68 | 17.314218 69 | 14.404241 70 | 16.330911 71 | 72 | 73 | Newton 74 | Georgia 75 | 13.992903 76 | 20.508263 77 | 9.458859 78 | 79 | 80 | Taliaferro 81 | Georgia 82 | 19.349845 83 | 16.103060 84 | 23.228804 85 | 86 | 87 | Talladega 88 | Alabama 89 | 9.945969 90 | 9.316357 91 | 12.955071 92 | 93 | 94 | Clayton 95 | Georgia 96 | 7.822084 97 | 9.950467 98 | 10.144222 99 | 100 | 101 | Henry 102 | Georgia 103 | 13.447729 104 | 8.726194 105 | 5.803169 106 | 107 | 108 | Fayette 109 | Georgia 110 | 5.731316 111 | 3.494964 112 | 3.305901 113 | 114 | 115 | Jasper 116 | Georgia 117 | 2.607018 118 | 21.394035 119 | 9.830747 120 | 121 | 122 | Coweta 123 | Georgia 124 | 11.480540 125 | 15.939834 126 | 7.017117 127 | 128 | 129 | Randolph 130 | Alabama 131 | 19.921509 132 | 8.468835 133 | 14.900592 134 | 135 | 136 | Clay 137 | Alabama 138 | 7.244907 139 | 2.468039 140 | 7.488073 141 | 142 | 143 | Putnam 144 | Georgia 145 | 22.511115 146 | 0.000000 147 | 14.382281 148 | 149 | 150 | Hancock 151 | Georgia 152 | 14.822657 153 | 14.381764 154 | 12.701034 155 | 156 | 157 | Butts 158 | Georgia 159 | 9.974494 160 | 6.732496 161 | 17.363015 162 | 163 | 164 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_2/AccountMgr2.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_2; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.List; 8 | 9 | import javax.servlet.ServletException; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | 13 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 14 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 15 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 16 | import com.github.eostermueller.perfSandbox.model.Account; 17 | import com.github.eostermueller.perfSandbox.model.Accounts; 18 | import com.github.eostermueller.perfSandbox.model.Transaction; 19 | 20 | public class AccountMgr2 { 21 | public AccountMgr2(PerfSandboxSingleton val) { 22 | this.pgBench = val; 23 | m_sqlTextMgr2.setLogger(val); 24 | } 25 | private PerfSandboxSingleton pgBench = null; 26 | 27 | public static SqlTextMgr2 m_sqlTextMgr2 = new SqlTextMgr2(); 28 | public Accounts getAccounts(List randomAccountIds) throws PerfSandboxException { 29 | Accounts accounts = getAccountsInternal(randomAccountIds); 30 | 31 | getTransactions(accounts); 32 | 33 | return accounts; 34 | } 35 | 36 | private Accounts getAccountsInternal(List accountIds) throws PerfSandboxException { 37 | Connection con = null; 38 | PreparedStatement ps = null; 39 | ResultSet rs = null; 40 | Accounts accounts = new Accounts(); 41 | try { 42 | con = pgBench.getConnection(); 43 | ps = con.prepareStatement( m_sqlTextMgr2.getMultipleAccountsSql(accountIds.size()) ); 44 | for (int i = 1; i <= accountIds.size(); i++) { 45 | ps.setLong(i, accountIds.get(i-1).longValue()); 46 | } 47 | rs = ps.executeQuery(); 48 | short count = 0; 49 | 50 | while(rs.next()) { 51 | Account a = createAccount(rs); 52 | accounts.addAccount(a); 53 | } 54 | } catch (SQLException e) { 55 | throw new PerfSandboxException(e); 56 | } finally { 57 | PerfSandboxUtil.closeQuietly(rs); 58 | PerfSandboxUtil.closeQuietly(ps); 59 | PerfSandboxUtil.closeQuietly(con); 60 | } 61 | return accounts; 62 | } 63 | 64 | private Account createAccount(ResultSet rs) throws SQLException { 65 | Account a = new Account(); 66 | a.accountId = rs.getLong(1); 67 | a.branchId = rs.getInt(2); 68 | a.balance = rs.getLong(3); 69 | a.filler = rs.getString(4); 70 | a.filler01 = rs.getString(5); 71 | a.filler02 = rs.getString(6); 72 | a.filler03 = rs.getString(7); 73 | a.filler04 = rs.getString(8); 74 | a.filler05 = rs.getString(9); 75 | a.filler06 = rs.getString(10); 76 | a.filler07 = rs.getString(11); 77 | a.filler08 = rs.getString(12); 78 | a.filler09 = rs.getString(13); 79 | a.filler10 = rs.getString(14); 80 | a.filler11 = rs.getString(15); 81 | a.filler12 = rs.getString(16); 82 | a.filler13 = rs.getString(17); 83 | a.filler14 = rs.getString(18); 84 | a.filler15 = rs.getString(19); 85 | a.filler16 = rs.getString(20); 86 | a.filler17 = rs.getString(21); 87 | a.filler18 = rs.getString(22); 88 | a.filler19 = rs.getString(23); 89 | a.filler20 = rs.getString(24); 90 | return a; 91 | } 92 | private void getTransactions(Accounts accounts) throws PerfSandboxException { 93 | 94 | Connection con = null; 95 | PreparedStatement ps = null; 96 | ResultSet rs = null; 97 | try { 98 | con = pgBench.getConnection(); 99 | ps = con.prepareStatement( m_sqlTextMgr2.getHistorySql(accounts.getAccounts().size()) ); 100 | 101 | for (int i = 1; i <= accounts.getAccounts().size();i++) { 102 | ps.setLong(i, accounts.getAccounts().get(i-1).accountId ); 103 | } 104 | rs = ps.executeQuery(); 105 | while(rs.next()) { 106 | Transaction t = new Transaction(); 107 | t.tellerId = rs.getInt(1); 108 | t.historyId = rs.getLong(2); 109 | t.branchId = rs.getInt(3); 110 | t.accountId = rs.getInt(4); 111 | t.delta = rs.getLong(5); 112 | t.mtime = PerfSandboxUtil.getDate(rs, 6); 113 | t.filler = rs.getString(7); 114 | Account a = accounts.findAccount(t.accountId); 115 | if (a!=null) 116 | a.transactions.add(t); 117 | else 118 | throw new PerfSandboxException("Found transaction with account id = [" + t.accountId + "], but it didn't have a matching account. Full transactions [" + t.toString() + "]"); 119 | } 120 | } catch (SQLException e) { 121 | throw new PerfSandboxException(e); 122 | } finally { 123 | PerfSandboxUtil.closeQuietly(rs); 124 | PerfSandboxUtil.closeQuietly(ps); 125 | PerfSandboxUtil.closeQuietly(con); 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_3/AccountMgr3.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_3; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 13 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 14 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 15 | import com.github.eostermueller.perfSandbox.model.Account; 16 | import com.github.eostermueller.perfSandbox.model.Accounts; 17 | import com.github.eostermueller.perfSandbox.model.Transaction; 18 | 19 | public class AccountMgr3 { 20 | 21 | public AccountMgr3(PerfSandboxSingleton val) { 22 | this.pgBench = val; 23 | this.m_sqlTextMgr3.setLogger(val); 24 | } 25 | private PerfSandboxSingleton pgBench = null; 26 | 27 | public static SqlTextMgr3 m_sqlTextMgr3 = new SqlTextMgr3(); 28 | public Accounts getAccounts(List randomAccountIds) throws PerfSandboxException { 29 | Accounts accounts = getAccountsInternal(randomAccountIds); 30 | 31 | for( Account a : accounts.getAccounts() ) 32 | try { 33 | a.transactions = this.getTransactions(a.accountId); 34 | } catch (SQLException e) { 35 | throw new PerfSandboxException(e); 36 | } catch (PerfSandboxException e) { 37 | throw new PerfSandboxException(e); 38 | } 39 | return accounts; 40 | } 41 | 42 | private Accounts getAccountsInternal(List accountIds) throws PerfSandboxException { 43 | Connection con = null; 44 | PreparedStatement ps = null; 45 | ResultSet rs = null; 46 | Accounts accounts = new Accounts(); 47 | try { 48 | con = pgBench.getConnection(); 49 | ps = con.prepareStatement( m_sqlTextMgr3.getMultipleAccountsSql(accountIds.size()) ); 50 | for (int i = 1; i <= accountIds.size(); i++) { 51 | ps.setLong(i, accountIds.get(i-1).longValue()); 52 | } 53 | rs = ps.executeQuery(); 54 | short count = 0; 55 | 56 | while(rs.next()) { 57 | Account a = createAccount(rs); 58 | accounts.addAccount(a); 59 | } 60 | } catch (SQLException e) { 61 | throw new PerfSandboxException(e); 62 | } finally { 63 | PerfSandboxUtil.closeQuietly(rs); 64 | PerfSandboxUtil.closeQuietly(ps); 65 | PerfSandboxUtil.closeQuietly(con); 66 | } 67 | return accounts; 68 | } 69 | 70 | private Account createAccount(ResultSet rs) throws SQLException { 71 | Account a = new Account(); 72 | a.accountId = rs.getLong(1); 73 | a.branchId = rs.getInt(2); 74 | a.balance = rs.getLong(3); 75 | a.filler = rs.getString(4); 76 | a.filler01 = rs.getString(5); 77 | a.filler02 = rs.getString(6); 78 | a.filler03 = rs.getString(7); 79 | a.filler04 = rs.getString(8); 80 | a.filler05 = rs.getString(9); 81 | a.filler06 = rs.getString(10); 82 | a.filler07 = rs.getString(11); 83 | a.filler08 = rs.getString(12); 84 | a.filler09 = rs.getString(13); 85 | a.filler10 = rs.getString(14); 86 | a.filler11 = rs.getString(15); 87 | a.filler12 = rs.getString(16); 88 | a.filler13 = rs.getString(17); 89 | a.filler14 = rs.getString(18); 90 | a.filler15 = rs.getString(19); 91 | a.filler16 = rs.getString(20); 92 | a.filler17 = rs.getString(21); 93 | a.filler18 = rs.getString(22); 94 | a.filler19 = rs.getString(23); 95 | a.filler20 = rs.getString(24); 96 | return a; 97 | } 98 | public void getAccountHistory(Account val) throws SQLException, PerfSandboxException { 99 | val.transactions = getTransactions(val.accountId); 100 | } 101 | private List getTransactions(long accountId) throws SQLException, PerfSandboxException { 102 | 103 | Connection con = null; 104 | PreparedStatement ps = null; 105 | ResultSet rs = null; 106 | List list = null; 107 | try { 108 | con = pgBench.getConnection(); 109 | ps = con.prepareStatement( m_sqlTextMgr3.getHistoryByAccountSql() ); 110 | ps.setLong(1, accountId); 111 | rs = ps.executeQuery(); 112 | list = new ArrayList(); 113 | while(rs.next()) { 114 | Transaction t = new Transaction(); 115 | t.tellerId = rs.getInt(1); 116 | t.historyId = rs.getLong(2); 117 | t.branchId = rs.getInt(3); 118 | t.accountId = rs.getInt(4); 119 | t.delta = rs.getLong(5); 120 | t.mtime = PerfSandboxUtil.getDate(rs, 6); 121 | t.filler = rs.getString(7); 122 | list.add(t); 123 | } 124 | } finally { 125 | PerfSandboxUtil.closeQuietly(rs); 126 | PerfSandboxUtil.closeQuietly(ps); 127 | PerfSandboxUtil.closeQuietly(con); 128 | } 129 | return list; 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_1/AccountMgr1.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_1; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.List; 8 | 9 | import javax.servlet.ServletException; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.stereotype.Service; 13 | 14 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 15 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 16 | import com.github.eostermueller.perfSandbox.dataaccess.BaseManager; 17 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 18 | import com.github.eostermueller.perfSandbox.model.Account; 19 | import com.github.eostermueller.perfSandbox.model.Accounts; 20 | import com.github.eostermueller.perfSandbox.model.Transaction; 21 | 22 | @Service 23 | public class AccountMgr1 extends BaseManager { 24 | @Autowired 25 | public AccountMgr1(PerfSandboxSingleton val) { 26 | this.pgBench = val; 27 | this.m_sqlTextMgr1.setLogger(val); 28 | } 29 | public static SqlTextMgr1 m_sqlTextMgr1 = new SqlTextMgr1(); 30 | private final PerfSandboxSingleton pgBench; 31 | public PerfSandboxSingleton getPgBench() { 32 | return pgBench; 33 | } 34 | 35 | public Accounts getAllAccountsAndCrashJvm() throws PerfSandboxException { 36 | int NUM_CRITERIA = 0; // means do not add WHERE clauses, select all rows in table, crash JVM. 37 | Connection con = null; 38 | PreparedStatement ps = null; 39 | ResultSet rs = null; 40 | Accounts accounts = new Accounts(); 41 | try { 42 | con = getPgBench().getConnection(); 43 | ps = con.prepareStatement( m_sqlTextMgr1.getAccountAndHistorySql(NUM_CRITERIA) ); 44 | ps.setFetchSize(1000);//2.5million rows total, get 1k rows at a time. 45 | rs = ps.executeQuery(); 46 | 47 | while(rs.next()) { 48 | getAccountAndTxData( rs, accounts ); 49 | } 50 | } catch (SQLException e) { 51 | throw new PerfSandboxException(e); 52 | } finally { 53 | PerfSandboxUtil.closeQuietly(rs); 54 | PerfSandboxUtil.closeQuietly(ps); 55 | PerfSandboxUtil.closeQuietly(con); 56 | } 57 | return accounts; 58 | } 59 | 60 | public Accounts getAccounts(List accountIdsCriteria) throws PerfSandboxException { 61 | 62 | Connection con = null; 63 | PreparedStatement ps = null; 64 | ResultSet rs = null; 65 | Accounts accounts = new Accounts(); 66 | try { 67 | con = getPgBench().getConnection(); 68 | ps = con.prepareStatement( m_sqlTextMgr1.getAccountAndHistorySql(accountIdsCriteria.size()) ); 69 | ps.setFetchSize(200); 70 | for (int i = 1; i <= accountIdsCriteria.size(); i++) { 71 | ps.setLong(i, accountIdsCriteria.get(i-1).longValue()); 72 | } 73 | rs = ps.executeQuery(); 74 | short count = 0; 75 | 76 | while(rs.next()) { 77 | getAccountAndTxData( rs, accounts ); 78 | } 79 | } catch (SQLException e) { 80 | throw new PerfSandboxException(e); 81 | } finally { 82 | PerfSandboxUtil.closeQuietly(rs); 83 | PerfSandboxUtil.closeQuietly(ps); 84 | PerfSandboxUtil.closeQuietly(con); 85 | } 86 | return accounts; 87 | } 88 | 89 | private void getAccountAndTxData(ResultSet rs, Accounts accounts) throws SQLException { 90 | long accountId = rs.getLong(1); 91 | Account account = accounts.findAccount(accountId); 92 | if (account==null) { 93 | account = createAccount(rs); 94 | accounts.addAccount(account); 95 | } 96 | Transaction t = createTransactions(rs); 97 | account.transactions.add(t); 98 | } 99 | 100 | private Transaction createTransactions(ResultSet rs) throws SQLException { 101 | Transaction t = new Transaction(); 102 | t.accountId = rs.getLong(1); 103 | t.branchId = rs.getInt(2); 104 | t.tellerId = rs.getInt(5+20); 105 | t.historyId = rs.getLong(6+20); 106 | t.delta = rs.getLong(7+20); 107 | t.mtime = PerfSandboxUtil.getDate(rs, 8+20); 108 | t.filler = rs.getString(9+20); 109 | return t; 110 | } 111 | 112 | private Account createAccount(ResultSet rs) throws SQLException { 113 | Account a = new Account(); 114 | a.accountId = rs.getLong(1); 115 | a.branchId = rs.getInt(2); 116 | a.balance = rs.getLong(3); 117 | a.filler = rs.getString(4); 118 | a.filler01 = rs.getString(5); 119 | a.filler02= rs.getString(6); 120 | a.filler03 = rs.getString(7); 121 | a.filler04 = rs.getString(8); 122 | a.filler05 = rs.getString(9); 123 | a.filler06 = rs.getString(10); 124 | a.filler07 = rs.getString(11); 125 | a.filler08 = rs.getString(12); 126 | a.filler09 = rs.getString(13); 127 | a.filler10 = rs.getString(14); 128 | a.filler11 = rs.getString(15); 129 | a.filler12 = rs.getString(16); 130 | a.filler13 = rs.getString(17); 131 | a.filler14 = rs.getString(18); 132 | a.filler15 = rs.getString(19); 133 | a.filler16 = rs.getString(20); 134 | a.filler17 = rs.getString(21); 135 | a.filler18 = rs.getString(22); 136 | a.filler19 = rs.getString(23); 137 | a.filler20 = rs.getString(24); 138 | return a; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/dataaccess_5/PkInquiry.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.dataaccess_5; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.sql.Statement; 8 | import java.util.List; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import com.github.eostermueller.perfSandbox.PerfSandboxSingleton; 13 | import com.github.eostermueller.perfSandbox.PerfSandboxException; 14 | import com.github.eostermueller.perfSandbox.dataaccess.PerfSandboxUtil; 15 | import com.github.eostermueller.perfSandbox.model.Account; 16 | import com.github.eostermueller.perfSandbox.model.Accounts; 17 | import com.github.eostermueller.perfSandbox.model.Branch; 18 | import com.github.eostermueller.perfSandbox.model.Transaction; 19 | 20 | public class PkInquiry { 21 | public PkInquiry(PerfSandboxSingleton val) { 22 | this.pgBench = val; 23 | } 24 | private PerfSandboxSingleton pgBench; 25 | public Account getAccount(long accountId) throws SQLException, PerfSandboxException { 26 | Account account = new Account(); 27 | Connection con = null; 28 | PreparedStatement ps = null; 29 | ResultSet rs = null; 30 | try { 31 | con = pgBench.getConnection(); 32 | ps = con.prepareStatement( AccountMgr5.m_sqlTextMgr5.getAccountPkInquirySql() ); 33 | ps.setLong(1, accountId); 34 | 35 | rs = ps.executeQuery(); 36 | short count = 0; 37 | while(rs.next()) { 38 | if (++count >1) 39 | throw new PerfSandboxException("Expecting only a single account record, but found at least 2 for accountId [" + accountId + "]"); 40 | account.accountId = rs.getLong(1); 41 | account.branchId = rs.getInt(2); 42 | account.balance = rs.getLong(3); 43 | account.filler = rs.getString(4); 44 | account.filler01 = rs.getString(5); 45 | account.filler02 = rs.getString(6); 46 | account.filler03 = rs.getString(7); 47 | account.filler04 = rs.getString(8); 48 | account.filler05 = rs.getString(9); 49 | account.filler06 = rs.getString(10); 50 | account.filler07 = rs.getString(11); 51 | account.filler08 = rs.getString(12); 52 | account.filler09 = rs.getString(13); 53 | account.filler10 = rs.getString(14); 54 | account.filler11 = rs.getString(15); 55 | account.filler12 = rs.getString(16); 56 | account.filler13 = rs.getString(17); 57 | account.filler14 = rs.getString(18); 58 | account.filler15 = rs.getString(19); 59 | account.filler16 = rs.getString(20); 60 | account.filler17 = rs.getString(21); 61 | account.filler18 = rs.getString(22); 62 | account.filler19 = rs.getString(23); 63 | account.filler20 = rs.getString(24); 64 | } 65 | } finally { 66 | PerfSandboxUtil.closeQuietly(rs); 67 | PerfSandboxUtil.closeQuietly(ps); 68 | PerfSandboxUtil.closeQuietly(con); 69 | } 70 | return account; 71 | } 72 | public Branch getBranch(int branchId) throws SQLException, PerfSandboxException { 73 | Branch branch = new Branch(); 74 | Connection con = null; 75 | PreparedStatement ps = null; 76 | ResultSet rs = null; 77 | try { 78 | con = pgBench.getConnection(); 79 | ps = con.prepareStatement( AccountMgr5.m_sqlTextMgr5.getBranchPkInquirySql() ); 80 | ps.setInt(1, branchId); 81 | rs = ps.executeQuery(); 82 | short count = 0; 83 | while(rs.next()) { 84 | if (++count >1) 85 | throw new PerfSandboxException("Expecting only a single account record, but found at least 2 for accountId [" + branchId + "]"); 86 | branch.bid = rs.getInt(1); 87 | branch.bbalance = rs.getLong(2); 88 | branch.filler = rs.getString(3); 89 | } 90 | } finally { 91 | PerfSandboxUtil.closeQuietly(rs); 92 | PerfSandboxUtil.closeQuietly(ps); 93 | PerfSandboxUtil.closeQuietly(con); 94 | } 95 | return branch; 96 | } 97 | public Transaction getTransaction(long transactionId) throws SQLException, PerfSandboxException { 98 | Transaction transaction = new Transaction(); 99 | Connection con = null; 100 | PreparedStatement ps = null; 101 | ResultSet rs = null; 102 | try { 103 | con = pgBench.getConnection(); 104 | ps = con.prepareStatement( AccountMgr5.m_sqlTextMgr5.getHistoryPkInquirySql() ); 105 | ps.setLong(1, transactionId); 106 | rs = ps.executeQuery(); 107 | short count = 0; 108 | while(rs.next()) { 109 | if (++count >1) 110 | throw new PerfSandboxException("Expecting only a single account record, but found at least 2 for accountId [" + transactionId + "]"); 111 | // return "SELECT tid, hid, bid, aid, delta, mtime, filler from " + m_tableNames.getHistoryTable() + " WHERE tid = ?"; 112 | transaction.tellerId = rs.getInt(1); 113 | transaction.historyId = rs.getLong(2); 114 | transaction.branchId = rs.getInt(3); 115 | transaction.accountId = rs.getLong(4); 116 | transaction.delta = rs.getLong(5); 117 | transaction.mtime = PerfSandboxUtil.getDate(rs, 6); 118 | transaction.filler = rs.getString(7); 119 | } 120 | } finally { 121 | PerfSandboxUtil.closeQuietly(rs); 122 | PerfSandboxUtil.closeQuietly(ps); 123 | PerfSandboxUtil.closeQuietly(con); 124 | } 125 | return transaction; 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /warProject/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 4.0.0 7 | com.github.eostermueller 8 | performanceGolf 9 | 0.0.1-SNAPSHOT 10 | Performance Golf Sample Application 11 | war 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 2.0.5.RELEASE 16 | 17 | 18 | 19 | org.apache.commons 20 | commons-pool2 21 | 2.6.0 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-web 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-tomcat 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-jetty 36 | provided 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-jdbc 41 | 42 | 43 | org.apache.tomcat 44 | tomcat-jdbc 45 | 46 | 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-data-jpa 51 | 52 | 53 | org.springframework.boot 54 | spring-boot-starter-actuator 55 | 56 | 57 | 58 | 59 | com.github.tomakehurst 60 | wiremock-standalone 61 | 2.0.2-beta 62 | 63 | 64 | com.h2database 65 | h2 66 | 1.4.191 67 | 68 | 74 | 75 | com.zaxxer 76 | HikariCP 77 | 3.2.0 78 | 79 | 80 | 81 | junit 82 | junit 83 | 4.12 84 | 85 | 86 | 87 | org.eclipse.emf 88 | org.eclipse.emf.ecore.xmi 89 | 2.11.1-v20150805-0538 90 | 91 | 92 | 93 | sax 94 | sax 95 | 2.0.1 96 | 97 | 98 | net.sf.ehcache 99 | ehcache 100 | 2.9.0 101 | 102 | 103 | 104 | javax.xml.bind 105 | jaxb-api 106 | 2.3.0 107 | 108 | 109 | 110 | 111 | performanceGolf 112 | 113 | 114 | org.springframework.boot 115 | spring-boot-maven-plugin 116 | 117 | 118 | org.apache.maven.plugins 119 | maven-war-plugin 120 | 121 | 122 | org.apache.maven.plugins 123 | maven-compiler-plugin 124 | 3.5.1 125 | 126 | 1.7 127 | 1.7 128 | 129 | 130 | 131 | 132 | 133 | 134 | spring-snapshots 135 | http://repo.spring.io/snapshot 136 | 137 | true 138 | 139 | 140 | 141 | spring-milestones 142 | http://repo.spring.io/milestone 143 | 144 | 145 | 146 | 147 | spring-snapshots 148 | http://repo.spring.io/snapshot 149 | 150 | 151 | spring-milestones 152 | http://repo.spring.io/milestone 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/model/Account.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.concurrent.ThreadLocalRandom; 6 | 7 | public class Account { 8 | public long accountId = 0; 9 | public int branchId = 0; 10 | public long balance = 0; 11 | public String filler = null; 12 | public String filler01 = null; 13 | public String filler02 = null; 14 | public String filler03 = null; 15 | public String filler04 = null; 16 | public String filler05 = null; 17 | public String filler06 = null; 18 | public String filler07 = null; 19 | public String filler08 = null; 20 | public String filler09 = null; 21 | public String filler10 = null; 22 | public String filler11 = null; 23 | public String filler12 = null; 24 | public String filler13 = null; 25 | public String filler14 = null; 26 | public String filler15 = null; 27 | public String filler16 = null; 28 | public String filler17 = null; 29 | public String filler18 = null; 30 | public String filler19 = null; 31 | public String filler20 = null; 32 | public List transactions = new ArrayList(); 33 | 34 | public Account(Account template) { 35 | this.accountId = template.accountId; 36 | this.branchId = template.branchId; 37 | this.balance = template.balance; 38 | this.filler = new String(template.filler); 39 | this.filler01 = new String(template.filler01); 40 | this.filler02 = new String(template.filler02); 41 | this.filler03 = new String(template.filler03); 42 | this.filler04 = new String(template.filler04); 43 | this.filler05 = new String(template.filler05); 44 | this.filler06 = new String(template.filler06); 45 | this.filler07 = new String(template.filler07); 46 | this.filler08 = new String(template.filler08); 47 | this.filler09 = new String(template.filler09); 48 | this.filler10 = new String(template.filler10); 49 | this.filler11 = new String(template.filler11); 50 | this.filler12 = new String(template.filler12); 51 | this.filler13 = new String(template.filler13); 52 | this.filler14 = new String(template.filler14); 53 | this.filler15 = new String(template.filler15); 54 | this.filler16 = new String(template.filler16); 55 | this.filler17 = new String(template.filler17); 56 | this.filler18 = new String(template.filler18); 57 | this.filler19 = new String(template.filler19); 58 | this.filler20 = new String(template.filler20); 59 | 60 | for(Transaction t : template.transactions) { 61 | this.transactions.add( new Transaction(t) ); 62 | } 63 | 64 | } 65 | 66 | public Account() { 67 | // TODO Auto-generated constructor stub 68 | } 69 | 70 | public static Account createFake(Long acctId) { 71 | Account a = new Account(); 72 | a.accountId = acctId; 73 | a.branchId = 1; 74 | a.balance = ThreadLocalRandom.current().nextInt(8675309); 75 | a.filler = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 76 | a.filler01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 77 | a.filler02 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 78 | a.filler03 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 79 | a.filler04 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 80 | a.filler05 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 81 | a.filler06 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 82 | a.filler07 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 83 | a.filler08 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 84 | a.filler09 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 85 | a.filler10 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 86 | a.filler11 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 87 | a.filler12 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 88 | a.filler13 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 89 | a.filler14 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 90 | a.filler15 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 91 | a.filler16 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 92 | a.filler17 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 93 | a.filler18 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 94 | a.filler19 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901"; 95 | a.filler20 = Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString()+Transaction.getRandomNineteenDigitString(); 96 | for(int i = 0; i < 50; i++) 97 | a.transactions.add( Transaction.createFake( acctId ) ); 98 | 99 | return a; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /sampleJMeterScripts/jpt_ch07_sandbox.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This test plan demonstrates simple usage of Dummy Sampler 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | false 16 | 17 | saveConfig 18 | 19 | 20 | true 21 | true 22 | true 23 | 24 | true 25 | true 26 | true 27 | true 28 | false 29 | true 30 | true 31 | false 32 | false 33 | false 34 | false 35 | false 36 | false 37 | false 38 | false 39 | 0 40 | true 41 | true 42 | 43 | 44 | 45 | 500 46 | false 47 | 48 | 49 | 50 | 51 | false 52 | false 53 | 54 | 55 | 56 | continue 57 | 58 | false 59 | -1 60 | 61 | 1 62 | 1 63 | 1300542586000 64 | 1300542586000 65 | false 66 | 67 | 68 | 69 | 70 | 71 | true 72 | true 73 | 200 74 | OK 75 | Dummy Sampler used to simulate requests and responses 76 | without actual network activity. This helps debugging tests. 77 | Dummy Sampler used to simulate requests and responses 78 | without actual network activity. This helps debugging tests. 79 | ${__Random(100,1000)} 80 | ${__Random(1,100)} 81 | 82 | 83 | 84 | true 85 | true 86 | 200 87 | OK 88 | Dummy Sampler used to simulate requests and responses 89 | without actual network activity. This helps debugging tests. 90 | Dummy Sampler used to simulate requests and responses 91 | without actual network activity. This helps debugging tests. 92 | ${__Random(100,1000)} 93 | ${__Random(1,100)} 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /sampleJMeterScripts/jpt_ch07_correlationVariables.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | This test plan demonstrates simple usage of Dummy Sampler 6 | false 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | false 16 | 17 | saveConfig 18 | 19 | 20 | true 21 | true 22 | true 23 | 24 | true 25 | true 26 | true 27 | true 28 | false 29 | true 30 | true 31 | false 32 | false 33 | true 34 | false 35 | false 36 | false 37 | false 38 | false 39 | 0 40 | true 41 | true 42 | 43 | 44 | 45 | 46 | 47 | 48 | continue 49 | 50 | false 51 | 1 52 | 53 | 1 54 | 1 55 | 1300542586000 56 | 1300542586000 57 | false 58 | 59 | 60 | 61 | 62 | 63 | true 64 | true 65 | 200 66 | OK 67 | <QUERY> 68 | <TITLE>Empire Burlesque</TITLE> 69 | </QUERY> 70 | <CATALOG> 71 | <CD name="file" value="bobDylan-01.txt"> 72 | <TITLE>Empire Burlesque</TITLE> 73 | <ARTIST>Bob Dylan</ARTIST> 74 | <COUNTRY>USA</COUNTRY> 75 | <COMPANY>Columbia</COMPANY> 76 | <PRICE>10.90</PRICE> 77 | <YEAR>1985</YEAR> 78 | </CD> 79 | <CATALOG> 80 | 81 | 82 | 83 | 84 | 85 | false 86 | MY_FILE 87 | name="file" value="(.+?)"> 88 | 89 | MY_FILE_ERROR 90 | 91 | 92 | 93 | 94 | 95 | false 96 | true 97 | false 98 | 99 | 100 | 101 | true 102 | true 103 | 200 104 | OK 105 | Submit this to the next request: ${MY_FILE_g1} 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /warProject/src/main/java/com/github/eostermueller/perfSandbox/HttpServer.java: -------------------------------------------------------------------------------- 1 | package com.github.eostermueller.perfSandbox; 2 | 3 | import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; 4 | import static com.github.tomakehurst.wiremock.client.WireMock.get; 5 | import static com.github.tomakehurst.wiremock.client.WireMock.stubFor; 6 | import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; 7 | import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; 8 | 9 | import java.io.BufferedReader; 10 | import java.io.IOException; 11 | import java.io.InputStreamReader; 12 | import java.net.HttpURLConnection; 13 | import java.net.Socket; 14 | import java.net.URL; 15 | 16 | import wiremock.com.google.common.base.Optional; 17 | 18 | import com.github.tomakehurst.wiremock.WireMockServer; 19 | import com.github.tomakehurst.wiremock.client.WireMock; 20 | 21 | /** 22 | * Provides a live HTTP server that provides 23 | *
    24 | *
  • a single HTTP GET to /perfSandboxBackend
  • 25 | *
  • that will wait x milliseconds before returning the HTTP response.
  • 26 | *
  • To specify x, see the start() method.
  • 27 | *
  • default hostname is localhost
  • 28 | *
  • The http server listens on TCP port specified on the start() method.
  • 29 | *
  • The connect of the response is fixed -- see the constant HTTP_RESPONSE
  • 30 | *
  • the start() method implements both "start" and "restart" functionality
  • 31 | *
32 | * @author erikostermueller 33 | * 34 | */ 35 | public class HttpServer { 36 | public static final String PERF_SANDBOX_BACKEND_URL = "/perfSandboxBackend"; 37 | public static final String WIREMOCK_HOST = "localhost"; 38 | public static final String HTTP_RESPONSE = "HelloWorldFromPerformanceSandBoxBackendServer HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO HELLO DONE "; 39 | private static int DELAY_BEFORE_CONFIGURE = 2000; 40 | private String host = WIREMOCK_HOST; 41 | public static int DEFAULT_HTTP_LISTEN_PORT = 8674; 42 | 43 | int intPort = 0; 44 | int intDelayMs = 0; 45 | WireMockServer wireMockServer = null; 46 | 47 | public static void main_(String args[]) throws PerfSandboxException, IOException { 48 | HttpServer myServer = new HttpServer(); 49 | 50 | if (!available(WIREMOCK_HOST,DEFAULT_HTTP_LISTEN_PORT)) 51 | log("Can't run test unless [" + DEFAULT_HTTP_LISTEN_PORT + " is available"); 52 | 53 | myServer.start(DEFAULT_HTTP_LISTEN_PORT, 1000, true); 54 | if (available(WIREMOCK_HOST,DEFAULT_HTTP_LISTEN_PORT)) 55 | log("Server did not start on TCP port [" + DEFAULT_HTTP_LISTEN_PORT + " as expected."); 56 | 57 | String actualHttpResponse = myServer.getHttpResponse(); 58 | if (!actualHttpResponse.equals(HTTP_RESPONSE)) 59 | log("Found [" + actualHttpResponse + "] instead of [" + HTTP_RESPONSE + "]" ); 60 | 61 | myServer.stop(); 62 | if (!available(WIREMOCK_HOST,DEFAULT_HTTP_LISTEN_PORT)) 63 | log("Server did not stop on TCP port [" + DEFAULT_HTTP_LISTEN_PORT + " as expected."); 64 | } 65 | public int getDelayInMs() { 66 | return this.intDelayMs; 67 | } 68 | public boolean isRunning() { 69 | boolean ynRC = false; 70 | if (this.wireMockServer!=null) { 71 | ynRC = this.wireMockServer.isRunning(); 72 | } 73 | return ynRC; 74 | } 75 | public boolean stop() { 76 | boolean ynRC = true; 77 | if (this.wireMockServer!=null) { 78 | this.wireMockServer.stop(); 79 | ynRC = !this.wireMockServer.isRunning(); 80 | } 81 | return ynRC; 82 | } 83 | public String getHttpResponse() throws IOException { 84 | return getHttpResponse(getUrl()); 85 | } 86 | public String getUrl() { 87 | return "http://localhost:" + this.intPort + PERF_SANDBOX_BACKEND_URL; 88 | } 89 | 90 | /** A convenience method that executes an HTTP GET to the given URL. 91 | * 92 | * @param url 93 | * @return 94 | * @throws IOException 95 | */ 96 | public String getHttpResponse(String url) throws IOException { 97 | 98 | URL obj = new URL(url); 99 | HttpURLConnection con = (HttpURLConnection) obj.openConnection(); 100 | 101 | // optional default is GET 102 | con.setRequestMethod("GET"); 103 | 104 | int responseCode = con.getResponseCode(); 105 | //System.out.println("\nSending 'GET' request to URL : " + url); 106 | //System.out.println("Response Code : " + responseCode); 107 | 108 | BufferedReader in = new BufferedReader( 109 | new InputStreamReader(con.getInputStream())); 110 | String inputLine; 111 | StringBuffer response = new StringBuffer(); 112 | 113 | while ((inputLine = in.readLine()) != null) { 114 | response.append(inputLine); 115 | } 116 | in.close(); 117 | 118 | return response.toString(); 119 | } 120 | /** 121 | * If the server is down, it will be started. 122 | * If the server is up, it will be restarted. 123 | * @param intPort 124 | * @param intDelayMs 125 | * @return 126 | * @throws PerfSandboxException 127 | */ 128 | public boolean start(int intPort, int intDelayMs, boolean disableRequestJournal) throws PerfSandboxException { 129 | if (intPort <1 || intPort > 65535) { 130 | throw new PerfSandboxException("The /startBackend 'port' query parameter is out of bounds. Must be a valid TCP port number, aka b/t 1 and 65535"); 131 | } else { 132 | this.intPort = intPort; 133 | } 134 | 135 | if (this.wireMockServer != null && this.wireMockServer.isRunning()) 136 | this.wireMockServer.stop(); 137 | 138 | if (available(host,intPort)) { 139 | 140 | if (disableRequestJournal) 141 | this.wireMockServer = new WireMockServer(wireMockConfig().port(intPort).disableRequestJournal() ); 142 | else 143 | this.wireMockServer = new WireMockServer(wireMockConfig().port(intPort).maxRequestJournalEntries(Optional.of(Integer.MAX_VALUE)) ); 144 | 145 | wireMockServer.start(); 146 | 147 | try { Thread.sleep(DELAY_BEFORE_CONFIGURE); } catch (Exception e) {} 148 | 149 | if (!wireMockServer.isRunning()) { 150 | throw new PerfSandboxException("Backend http system is unable to start. Is some other process listening on port [" + intPort + "]?"); 151 | } 152 | 153 | this.intDelayMs = intDelayMs; 154 | configure(intDelayMs); 155 | return true; 156 | } else { 157 | throw new PerfSandboxException("Unable to start backend http server because some process listening on port [" + intPort + "]."); 158 | } 159 | 160 | } 161 | private void configure(int intDelayMs) { 162 | 163 | WireMock wireMock = new WireMock(host, this.intPort); 164 | wireMock.register(get(urlEqualTo(PERF_SANDBOX_BACKEND_URL)).willReturn( 165 | aResponse() 166 | .withStatus(200) 167 | .withBody(HTTP_RESPONSE) 168 | .withFixedDelay(intDelayMs))); 169 | 170 | } 171 | private static void log(String msg) { 172 | System.out.println("~@: " + msg); 173 | } 174 | /** 175 | * Test to see if port is available. 176 | * @param port 177 | * @return 178 | */ 179 | public static boolean available(String hst, int port) { 180 | try (Socket ignored = new Socket(hst, port)) { 181 | return false; 182 | } catch (IOException ignored) { 183 | return true; 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/test/jmeter/08b-shutdown.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 0 23 | = 24 | 25 | 26 | BACKEND_PORT 27 | 8676 28 | = 29 | 30 | 31 | BACKEND_DELAY_MS 32 | 500 33 | = 34 | 35 | 36 | 37 | 38 | true 39 | 40 | 41 | 42 | true 43 | 44 | saveConfig 45 | 46 | 47 | true 48 | true 49 | true 50 | 51 | true 52 | true 53 | true 54 | true 55 | false 56 | true 57 | true 58 | false 59 | false 60 | false 61 | false 62 | false 63 | false 64 | false 65 | false 66 | 0 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | continue 76 | 77 | false 78 | 1 79 | 80 | 1 81 | 1 82 | 1473768597000 83 | 1473768597000 84 | false 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ${HOST} 94 | ${PORT} 95 | 96 | 97 | https 98 | 99 | /stopCpuBusy?id=1 100 | GET 101 | true 102 | false 103 | true 104 | false 105 | false 106 | 107 | 108 | 109 | 110 | 111 | <Config> 112 | Busy CPU thread stopped 113 | true</stopped> 114 | 1 115 | 116 | Assertion.response_data 117 | false 118 | 16 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | ${HOST} 127 | ${PORT} 128 | 129 | 130 | https 131 | 132 | /stopCpuBusy?id=2 133 | GET 134 | true 135 | false 136 | true 137 | false 138 | false 139 | 140 | 141 | 142 | 143 | 144 | <Config> 145 | Busy CPU thread stopped 146 | true</stopped> 147 | 2 148 | 149 | Assertion.response_data 150 | false 151 | 16 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/test/jmeter/11-shutdown.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 0 23 | = 24 | 25 | 26 | BACKEND_PORT 27 | 8676 28 | = 29 | 30 | 31 | BACKEND_DELAY_MS 32 | 500 33 | = 34 | 35 | 36 | 37 | 38 | true 39 | 40 | 41 | 42 | true 43 | 44 | saveConfig 45 | 46 | 47 | true 48 | true 49 | true 50 | 51 | true 52 | true 53 | true 54 | true 55 | false 56 | true 57 | true 58 | false 59 | false 60 | false 61 | false 62 | false 63 | false 64 | false 65 | false 66 | 0 67 | true 68 | true 69 | 70 | 71 | 72 | 73 | 74 | 75 | continue 76 | 77 | false 78 | 1 79 | 80 | 1 81 | 1 82 | 1473768597000 83 | 1473768597000 84 | false 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | ${HOST} 94 | ${PORT} 95 | 96 | 97 | https 98 | 99 | /stopCpuBusy?id=1 100 | GET 101 | true 102 | false 103 | true 104 | false 105 | false 106 | 107 | 108 | 109 | 110 | 111 | <Config> 112 | Busy CPU thread stopped 113 | true</stopped> 114 | 1 115 | 116 | Assertion.response_data 117 | false 118 | 16 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | ${HOST} 127 | ${PORT} 128 | 129 | 130 | https 131 | 132 | /stopCpuBusy?id=2 133 | GET 134 | true 135 | false 136 | true 137 | false 138 | false 139 | 140 | 141 | 142 | 143 | 144 | <Config> 145 | Busy CPU thread stopped 146 | true</stopped> 147 | 2 148 | 149 | Assertion.response_data 150 | false 151 | 16 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/test/jmeter/04a.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 1 23 | = 24 | 25 | 26 | DB 27 | 2 28 | = 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | continue 37 | 38 | false 39 | 1 40 | 41 | 1 42 | 1 43 | 1465183654000 44 | 1465183654000 45 | false 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ${HOST} 55 | ${PORT} 56 | 57 | 58 | https 59 | 60 | /config?scenarioNum=${SCENARIO_NUM}&db=${DB} 61 | GET 62 | true 63 | false 64 | true 65 | false 66 | false 67 | 68 | 69 | 70 | 71 | 72 | continue 73 | 74 | false 75 | -1 76 | 77 | 3 78 | 1 79 | 1463941680000 80 | 1463941680000 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ${HOST} 91 | ${PORT} 92 | 93 | 94 | https 95 | 96 | /randomInquiry?numAccounts=20 97 | GET 98 | true 99 | false 100 | true 101 | false 102 | false 103 | 104 | 105 | 106 | 107 | 108 | 0123456789012345678901234567890123456789012345678901234567890123456789012345678901</Filler> 109 | </Root> 110 | <Root> 111 | <Account> 112 | <Aid> 113 | <Bid> 114 | <Tid>1</Tid> 115 | <Filler>0123456789012345678912</Filler> 116 | 117 | Assertion.response_data 118 | false 119 | 16 120 | 121 | 122 | 123 | 124 | error 125 | exception 126 | throw 127 | 128 | Assertion.response_data 129 | false 130 | 6 131 | 132 | 133 | 134 | 135 | 136 | true 137 | 138 | saveConfig 139 | 140 | 141 | true 142 | true 143 | true 144 | 145 | true 146 | true 147 | true 148 | true 149 | false 150 | true 151 | true 152 | false 153 | false 154 | false 155 | false 156 | false 157 | false 158 | false 159 | false 160 | 0 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /src/test/jmeter/04b.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 2 23 | = 24 | 25 | 26 | DB 27 | 2 28 | = 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | continue 37 | 38 | false 39 | 1 40 | 41 | 1 42 | 1 43 | 1465183654000 44 | 1465183654000 45 | false 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ${HOST} 55 | ${PORT} 56 | 57 | 58 | https 59 | 60 | /config?scenarioNum=${SCENARIO_NUM}&db=${DB} 61 | GET 62 | true 63 | false 64 | true 65 | false 66 | false 67 | 68 | 69 | 70 | 71 | 72 | continue 73 | 74 | false 75 | -1 76 | 77 | 3 78 | 1 79 | 1463941680000 80 | 1463941680000 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ${HOST} 91 | ${PORT} 92 | 93 | 94 | https 95 | 96 | /randomInquiry?numAccounts=20 97 | GET 98 | true 99 | false 100 | true 101 | false 102 | false 103 | 104 | 105 | 106 | 107 | 108 | 0123456789012345678901234567890123456789012345678901234567890123456789012345678901</Filler> 109 | </Root> 110 | <Root> 111 | <Account> 112 | <Aid> 113 | <Bid> 114 | <Tid>1</Tid> 115 | <Filler>0123456789012345678912</Filler> 116 | 117 | Assertion.response_data 118 | false 119 | 16 120 | 121 | 122 | 123 | 124 | error 125 | exception 126 | throw 127 | 128 | Assertion.response_data 129 | false 130 | 6 131 | 132 | 133 | 134 | 135 | 136 | true 137 | 138 | saveConfig 139 | 140 | 141 | true 142 | true 143 | true 144 | 145 | true 146 | true 147 | true 148 | true 149 | false 150 | true 151 | true 152 | false 153 | false 154 | false 155 | false 156 | false 157 | false 158 | false 159 | false 160 | 0 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /src/test/jmeter/07a.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 4 23 | = 24 | 25 | 26 | DB 27 | 2 28 | = 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | continue 37 | 38 | false 39 | 1 40 | 41 | 1 42 | 1 43 | 1465183654000 44 | 1465183654000 45 | false 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ${HOST} 55 | ${PORT} 56 | 57 | 58 | https 59 | 60 | /config?scenarioNum=${SCENARIO_NUM}&db=${DB} 61 | GET 62 | true 63 | false 64 | true 65 | false 66 | false 67 | 68 | 69 | 70 | 71 | 72 | continue 73 | 74 | false 75 | -1 76 | 77 | 3 78 | 1 79 | 1463941680000 80 | 1463941680000 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ${HOST} 91 | ${PORT} 92 | 93 | 94 | https 95 | 96 | /randomInquiry?numAccounts=10 97 | GET 98 | true 99 | false 100 | true 101 | false 102 | false 103 | 104 | 105 | 106 | 107 | 108 | 0123456789012345678901234567890123456789012345678901234567890123456789012345678901</Filler> 109 | </Root> 110 | <Root> 111 | <Account> 112 | <Aid> 113 | <Bid> 114 | <Tid>1</Tid> 115 | <Filler>0123456789012345678912</Filler> 116 | 117 | Assertion.response_data 118 | false 119 | 16 120 | 121 | 122 | 123 | 124 | error 125 | exception 126 | throw 127 | 128 | Assertion.response_data 129 | false 130 | 6 131 | 132 | 133 | 134 | 135 | 136 | true 137 | 138 | saveConfig 139 | 140 | 141 | true 142 | true 143 | true 144 | 145 | true 146 | true 147 | true 148 | true 149 | false 150 | true 151 | true 152 | false 153 | false 154 | false 155 | false 156 | false 157 | false 158 | false 159 | false 160 | 0 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /src/test/jmeter/07b.jmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | false 8 | 9 | 10 | 11 | HOST 12 | localhost 13 | = 14 | 15 | 16 | PORT 17 | 8675 18 | = 19 | 20 | 21 | SCENARIO_NUM 22 | 2 23 | = 24 | 25 | 26 | DB 27 | 2 28 | = 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | continue 37 | 38 | false 39 | 1 40 | 41 | 1 42 | 1 43 | 1465183654000 44 | 1465183654000 45 | false 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ${HOST} 55 | ${PORT} 56 | 57 | 58 | https 59 | 60 | /config?scenarioNum=${SCENARIO_NUM}&db=${DB} 61 | GET 62 | true 63 | false 64 | true 65 | false 66 | false 67 | 68 | 69 | 70 | 71 | 72 | continue 73 | 74 | false 75 | -1 76 | 77 | 3 78 | 1 79 | 1463941680000 80 | 1463941680000 81 | false 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | ${HOST} 91 | ${PORT} 92 | 93 | 94 | https 95 | 96 | /randomInquiry?numAccounts=10 97 | GET 98 | true 99 | false 100 | true 101 | false 102 | false 103 | 104 | 105 | 106 | 107 | 108 | 0123456789012345678901234567890123456789012345678901234567890123456789012345678901</Filler> 109 | </Root> 110 | <Root> 111 | <Account> 112 | <Aid> 113 | <Bid> 114 | <Tid>1</Tid> 115 | <Filler>0123456789012345678912</Filler> 116 | 117 | Assertion.response_data 118 | false 119 | 16 120 | 121 | 122 | 123 | 124 | error 125 | exception 126 | throw 127 | 128 | Assertion.response_data 129 | false 130 | 6 131 | 132 | 133 | 134 | 135 | 136 | true 137 | 138 | saveConfig 139 | 140 | 141 | true 142 | true 143 | true 144 | 145 | true 146 | true 147 | true 148 | true 149 | false 150 | true 151 | true 152 | false 153 | false 154 | false 155 | false 156 | false 157 | false 158 | false 159 | false 160 | 0 161 | true 162 | true 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | --------------------------------------------------------------------------------