1 24 25 package org.objectweb.cjdbc.requestplayer; 26 27 import java.io.BufferedReader ; 28 import java.io.FileReader ; 29 import java.io.IOException ; 30 import java.sql.Connection ; 31 import java.sql.DriverManager ; 32 import java.sql.SQLException ; 33 import java.util.ArrayList ; 34 import java.util.EmptyStackException ; 35 import java.util.HashSet ; 36 import java.util.Hashtable ; 37 import java.util.Stack ; 38 import java.util.StringTokenizer ; 39 40 import org.apache.commons.cli.CommandLine; 41 import org.apache.commons.cli.CommandLineParser; 42 import org.apache.commons.cli.GnuParser; 43 import org.apache.commons.cli.HelpFormatter; 44 import org.apache.commons.cli.Option; 45 import org.apache.commons.cli.OptionGroup; 46 import org.apache.commons.cli.Options; 47 import org.apache.commons.cli.ParseException; 48 import org.objectweb.cjdbc.common.util.Stats; 49 50 59 public class ClientEmulator 60 { 61 62 public static final int MAJOR_VERSION = 1; 63 64 65 public static final int MINOR_VERSION = 0; 66 67 68 private static final Integer ZERO = new Integer (0); 69 70 71 private String propUrl; 72 73 74 private String propUsername; 75 76 77 private String propPassword; 78 79 80 private RequestPlayerProperties requestPlayerProp = null; 81 82 83 protected BufferedReader sqlTrace = null; 84 85 86 protected Stats selectStats = new Stats("Select"); 87 88 89 protected Stats unknownStats = new Stats("Unknown"); 90 91 92 protected Stats updateStats = new Stats("Update"); 93 94 95 protected Stats insertStats = new Stats("Insert"); 96 97 98 protected Stats deleteStats = new Stats("Delete"); 99 100 101 protected Stats beginStats = new Stats("Begin"); 102 103 104 protected Stats commitStats = new Stats("Commit"); 105 106 107 protected Stats rollbackStats = new Stats("Rollback"); 108 109 110 protected Stats getConnectionStats = new Stats( 111 "Get connection from driver"); 112 113 114 protected Stats closeStats = new Stats( 115 "Close connection"); 116 117 118 protected Stats getRequestStats = new Stats( 119 "Get requests from log file"); 120 121 122 private int nbRequests = 0; 123 124 125 private int maxRequests = 0; 126 127 128 private Hashtable tidList = new Hashtable (); 129 130 private HashSet ignoredTids = new HashSet (); 131 132 133 private int timeout; 134 135 136 private int connectionType; 137 138 139 private Stack freeConnections = null; 140 141 142 private int poolSize; 143 144 145 private Integer transactionId; 146 147 153 public ClientEmulator(String configFile) 154 { 155 requestPlayerProp = new RequestPlayerProperties(configFile); 157 if (!requestPlayerProp.checkPropertiesFile()) 158 Runtime.getRuntime().exit(1); 159 160 propUrl = requestPlayerProp.getDatabaseURL(); 161 propUsername = requestPlayerProp.getDatabaseUsername(); 162 propPassword = requestPlayerProp.getDatabasePassword(); 163 164 try 166 { 167 Class.forName(requestPlayerProp.getDatabaseDriver()); 168 } 169 catch (Exception e) 170 { 171 System.out.println("Unable to load database driver '" 172 + requestPlayerProp.getDatabaseDriver() + "' (" + e + ")"); 173 Runtime.getRuntime().exit(1); 174 } 175 176 connectionType = requestPlayerProp.getConnectionType(); 177 if (connectionType == RequestPlayerProperties.POOLING_CONNECTION) 178 { 179 poolSize = requestPlayerProp.getPoolSize(); 180 if (poolSize <= 0) 181 { 182 System.out.println("Connections pool size must be greater than 0."); 183 Runtime.getRuntime().exit(1); 184 } 185 freeConnections = new Stack (); 186 initializeConnections(); 187 } 188 189 int nbClients = requestPlayerProp.getNbClients(); 190 if (nbClients <= 0) 191 { 192 System.out.println("Number of clients must be greater than 0."); 193 Runtime.getRuntime().exit(1); 194 } 195 196 timeout = requestPlayerProp.getTimeout(); 197 198 try 199 { 200 String fileName = requestPlayerProp.getTraceFile(); 201 sqlTrace = new BufferedReader (new FileReader (fileName)); 202 } 203 catch (Exception e) 204 { 205 System.out.println("An error occured while opening trace file (" 206 + e.getMessage() + ")"); 207 Runtime.getRuntime().exit(1); 208 } 209 210 maxRequests = requestPlayerProp.getNbRequests(); 211 212 System.out.println("Creating " + nbClients + " threads."); 213 ClientThread[] threads = new ClientThread[nbClients]; 214 for (int i = 0; i < nbClients; i++) 215 threads[i] = new ClientThread(i, this, connectionType); 216 217 MonitoringThread monitor = new MonitoringThread(this, 60000); 218 monitor.start(); 220 221 System.out.println("Starting threads."); 222 long start = System.currentTimeMillis(); 223 for (int i = 0; i < nbClients; i++) 224 threads[i].start(); 225 System.out.println("Done."); 226 227 for (int i = 0; i < nbClients; i++) 228 { 229 try 230 { 231 threads[i].join(); 232 } 233 catch (java.lang.InterruptedException ie) 234 { 235 System.err.println("ClientEmulator: Thread " + i 236 + " has been interrupted."); 237 } 238 } 239 long end = System.currentTimeMillis(); 240 monitor.setKilled(true); 241 monitor.interrupt(); 242 System.out.println("Done\n"); 243 244 try 245 { 246 sqlTrace.close(); 247 } 248 catch (Exception ignore) 249 { 250 } 251 252 if (connectionType == RequestPlayerProperties.POOLING_CONNECTION) 253 { 254 try 255 { 256 finalizeConnections(); 257 } 258 catch (SQLException e) 259 { 260 System.out.println("Failed to release connections from the pool."); 261 } 262 } 263 264 Stats globalStats = new Stats("Global"); 266 try 267 { 268 globalStats.merge(selectStats); 269 globalStats.merge(insertStats); 270 globalStats.merge(updateStats); 271 globalStats.merge(deleteStats); 272 globalStats.merge(getConnectionStats); 273 globalStats.merge(beginStats); 274 globalStats.merge(commitStats); 275 globalStats.merge(rollbackStats); 276 } 277 catch (Exception e) 278 { 279 e.printStackTrace(); 280 } 281 282 getRequestStats.displayOnStdout(); 286 getConnectionStats.displayOnStdout(); 287 closeStats.displayOnStdout(); 288 beginStats.displayOnStdout(); 289 commitStats.displayOnStdout(); 290 rollbackStats.displayOnStdout(); 291 selectStats.displayOnStdout(); 292 insertStats.displayOnStdout(); 293 updateStats.displayOnStdout(); 294 deleteStats.displayOnStdout(); 295 globalStats.displayOnStdout(); 296 System.out.println("\nTotal execution time: " + (end - start) + " ms"); 297 if (end - start != 0) 298 { 299 System.out.println("Average requests/second: " 300 + (globalStats.getCount() * 1000.0 / (end - start))); 301 System.out.println("Average requests/minute: " 302 + (globalStats.getCount() * 60000.0 / (end - start))); 303 } 304 } 305 306 311 public Connection getConnection() 312 { 313 try 315 { 316 return DriverManager.getConnection(propUrl, propUsername, propPassword); 317 } 318 catch (Exception e) 319 { 320 System.out.println("Unable to connect to database '" 321 + requestPlayerProp.getDatabaseURL() + "' (" + e + ")"); 322 } 323 return null; 324 } 325 326 330 public synchronized void initializeConnections() 331 { 332 for (int i = 0; i < poolSize; i++) 333 { 334 freeConnections.push(getConnection()); 336 } 337 } 338 339 344 public void closeConnection(Connection connection) 345 { 346 try 347 { 348 if (connection != null) 349 connection.close(); 350 } 351 catch (Exception e) 352 { 353 System.out.println("Failed to close the connection (" + e + ")"); 354 } 355 } 356 357 363 public synchronized Connection getConnectionFromPool() 364 { 365 try 366 { 367 while (freeConnections.isEmpty()) 369 { 370 try 371 { 372 wait(); 373 } 374 catch (InterruptedException e) 375 { 376 System.out.println("Connection pool wait interrupted."); 377 } 378 } 379 380 Connection c = (Connection ) freeConnections.pop(); 381 return c; 382 } 383 catch (EmptyStackException e) 384 { 385 System.out.println("Out of connections."); 386 return null; 387 } 388 } 389 390 395 public synchronized void releaseConnectionToPool(Connection connection) 396 { 397 boolean mustNotify = freeConnections.isEmpty(); 398 399 freeConnections.push(connection); 400 401 if (mustNotify) 403 notify(); 404 } 405 406 411 public synchronized void finalizeConnections() throws SQLException 412 { 413 Connection c = null; 414 while (!freeConnections.isEmpty()) 415 { 416 c = (Connection ) freeConnections.pop(); 417 c.close(); 418 } 419 } 420 421 430 public synchronized String parallelGetNextSQLRequest(int tid) 431 { 432 ArrayList req = (ArrayList ) tidList.get(new Integer (tid)); 434 if (req != null) 435 { 436 String request = (String ) req.remove(0); 437 if (req.isEmpty()) 438 tidList.remove(new Integer (tid)); 439 440 nbRequests++; 441 return request; 442 } 443 444 while ((nbRequests <= maxRequests) || (maxRequests == 0)) 446 { 447 String request = readRequest(); 448 449 if ((request == null) || (transactionId == null)) return null; 452 453 if (transactionId.intValue() == tid) 455 { 456 nbRequests++; 457 return request; } 459 else 460 { ArrayList requests = (ArrayList ) tidList.get(transactionId); 462 if (requests == null) 463 { 464 requests = new ArrayList (); 465 tidList.put(transactionId, requests); 466 } 467 requests.add(request); 468 } 469 } 470 return null; 471 } 472 473 479 public void ignoreTid(int tid) 480 { 481 ignoredTids.add(new Integer (tid)); 482 } 483 484 494 public synchronized String sequentialGetNextSQLRequest(int tid) 495 { 496 String request; 497 do 498 { 499 request = readRequest(); 500 501 if (request == null) { 503 notifyAll(); 504 return null; 505 } 506 } 507 while (ignoredTids.contains(transactionId)); 508 509 if (transactionId.intValue() == tid) 511 return request; else 513 { 514 notifyAll(); while (request != null) 516 { 517 try 518 { 519 wait(1000); 520 } 521 catch (InterruptedException e) 522 { 523 System.err.println("sequentialGetNextSQLRequest wait interrupted"); 524 } 525 if (transactionId != null) 527 if (transactionId.intValue() != tid) 528 { 529 String myRequest = request; 530 request = readRequest(); notifyAll(); 532 return myRequest; 533 } 534 } 535 notifyAll(); 536 return null; 537 } 538 } 539 540 543 private String readRequest() 544 { 545 String request = null; 546 transactionId = null; 547 548 try 549 { 550 if ((nbRequests <= maxRequests) || (maxRequests == 0)) 551 if ((request = sqlTrace.readLine()) != null) 552 { 553 nbRequests++; 555 556 StringTokenizer requestTokenizer = new StringTokenizer (request, " "); 557 requestTokenizer.nextToken(); 559 requestTokenizer.nextToken(); 561 String type = requestTokenizer.nextToken().trim(); 562 transactionId = new Integer (requestTokenizer.nextToken().trim()); 563 564 String sql; 565 switch (type.charAt(0)) 566 { 567 case 'B' : 568 sql = "B " + transactionId; 570 transactionId = ZERO; 571 break; 572 case 'C' : 573 case 'R' : 575 sql = type; 577 break; 578 default : 579 sql = type 581 + " " 582 + request.substring( 583 request.indexOf(" " + transactionId.toString() + " ") 584 + transactionId.toString().length() + 1).trim(); 585 break; 586 } 587 return sql.toString(); 588 } 589 } 590 catch (IOException e) 591 { 592 } 593 return null; 594 } 595 596 601 public Stats getDeleteStats() 602 { 603 return deleteStats; 604 } 605 606 611 public Stats getInsertStats() 612 { 613 return insertStats; 614 } 615 616 621 public Stats getSelectStats() 622 { 623 return selectStats; 624 } 625 626 631 public Stats getUnknownStats() 632 { 633 return unknownStats; 634 } 635 636 641 public Stats getUpdateStats() 642 { 643 return updateStats; 644 } 645 646 651 public Stats getBeginStats() 652 { 653 return beginStats; 654 } 655 656 661 public Stats getCloseStats() 662 { 663 return closeStats; 664 } 665 666 671 public Stats getCommitStats() 672 { 673 return commitStats; 674 } 675 676 681 public Stack getFreeConnections() 682 { 683 return freeConnections; 684 } 685 686 691 public Stats getGetConnectionStats() 692 { 693 return getConnectionStats; 694 } 695 696 701 public Stats getGetRequestStats() 702 { 703 return getRequestStats; 704 } 705 706 711 public Stats getRollbackStats() 712 { 713 return rollbackStats; 714 } 715 716 721 public int getTimeout() 722 { 723 return timeout; 724 } 725 726 739 public static void main(String [] args) 740 { 741 Options options = createOptions(); 743 744 CommandLineParser parser = new GnuParser(); 746 CommandLine commandLine = null; 747 try 748 { 749 commandLine = parser.parse(options, args); 750 } 751 catch (ParseException e) 752 { 753 System.err.println("Syntax error (" + e + ")"); 754 printUsage(options); 755 Runtime.getRuntime().exit(1); 756 } 757 758 int n = commandLine.getArgs().length; 760 for (int i = 0; i < n; i++) 761 { 762 System.err.println("Syntax error (unrecognized option: " 763 + commandLine.getArgs()[i] + ")"); 764 printUsage(options); 765 Runtime.getRuntime().exit(1); 766 } 767 768 if (commandLine.hasOption('h')) 770 { 771 if (commandLine.getOptions().length > 1) 772 System.err.println("Syntax error"); 773 774 printUsage(options); 775 Runtime.getRuntime().exit(1); 776 } 777 778 if (commandLine.hasOption('v')) 780 { 781 if (commandLine.getOptions().length > 1) 782 { 783 System.err.println("Syntax error"); 784 printUsage(options); 785 } 786 else 787 System.out.println("C-JDBC request player version " + MAJOR_VERSION 788 + "." + MINOR_VERSION); 789 790 Runtime.getRuntime().exit(1); 791 } 792 793 if (commandLine.hasOption('f')) 795 { 796 if (commandLine.getOptions().length > 1) 797 { 798 System.err.println("Syntax error"); 799 printUsage(options); 800 } 801 new ClientEmulator(commandLine.getOptionValue("f")); 802 } 803 else 804 { 805 new ClientEmulator(null); 806 } 807 } 808 809 815 private static Options createOptions() 816 { 817 Options options = new Options(); 818 OptionGroup group = new OptionGroup(); 819 820 group.addOption(new Option("h", "help", false, 822 "Displays usage information.")); 823 group.addOption(new Option("v", "version", false, 824 "Displays version information.")); 825 options.addOptionGroup(group); 826 827 options 829 .addOption(new Option("f", "file", true, 830 "Allows to use a given configuration file instead of the default file.")); 831 return options; 832 } 833 834 839 private static void printUsage(Options options) 840 { 841 String header = "Launchs the C-JDBC request player: this tool reads SQL requests in a file and forwards them to the C-JDBC controller(s)." 842 + System.getProperty("line.separator") + "Options:"; 843 String footer = "Statistics are displayed after the execution has finished. For more information, see the default configuration file contained in the <C_JDBC_HOME>/config/ directory."; 844 845 (new HelpFormatter()).printHelp(80, "requestplayer(.sh|.bat) [options]", 846 header, options, footer); 847 } 848 } | Popular Tags |