KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > slamd > example > SQLModRateJobClass


1 /*
2  * Sun Public License
3  *
4  * The contents of this file are subject to the Sun Public License Version
5  * 1.0 (the "License"). You may not use this file except in compliance with
6  * the License. A copy of the License is available at http://www.sun.com/
7  *
8  * The Original Code is the SLAMD Distributed Load Generation Engine.
9  * The Initial Developer of the Original Code is Neil A. Wilson.
10  * Portions created by Neil A. Wilson are Copyright (C) 2004.
11  * Some preexisting portions Copyright (C) 2002-2004 Sun Microsystems, Inc.
12  * All Rights Reserved.
13  *
14  * Contributor(s): Neil A. Wilson
15  */

16 package com.sun.slamd.example;
17
18
19
20 import java.sql.*;
21 import java.util.*;
22 import com.sun.slamd.job.*;
23 import com.sun.slamd.parameter.*;
24 import com.sun.slamd.stat.*;
25
26
27
28
29 /**
30  * This class implements a SLAMD job that can be used to measure the update
31  * performance of an SQL database. It should work with any database for which a
32  * JDBC driver exists.
33  *
34  *
35  * @author Neil A. Wilson
36  */

37 public class SQLModRateJobClass
38        extends JobClass
39 {
40   /**
41    * The display name of the stat tracker that counts exceptions caught while
42    * processing queries.
43    */

44   public static final String JavaDoc STAT_TRACKER_EXCEPTIONS_CAUGHT =
45        "Exceptions Caught";
46
47
48
49   /**
50    * The display name of the stat tracker that tracks the rate at which updates
51    * are able to be processed.
52    */

53   public static final String JavaDoc STAT_TRACKER_UPDATES_COMPLETED =
54        "Updates Completed";
55
56
57
58   /**
59    * The display name of the stat tracker that tracks the average length of time
60    * required to process an update.
61    */

62   public static final String JavaDoc STAT_TRACKER_UPDATE_DURATION =
63        "Update Duration (ms)";
64
65
66
67   /**
68    * The characters that are available for use in the randomly-generated values.
69    */

70   public static final char[] ALPHABET =
71        "abcdefghijklmnopqrstuvwxyz".toCharArray();
72
73
74
75   // The parameter that indicates whether to always disconnect from the DB.
76
BooleanParameter disconnectParameter =
77        new BooleanParameter("disconnect", "Always Disconnect",
78                             "Indicates whether the connection to the " +
79                             "database should be dropped after each update.",
80                             false);
81
82   // The parameter that specifies the cool down time.
83
IntegerParameter coolDownParameter =
84        new IntegerParameter("cool_down", "Cool Down Time (s)",
85                             "Specifies the length of time in seconds before " +
86                             "the job ends that it should stop collecting " +
87                             "statistics.", true, 0, true, 0, false, 0);
88
89   // The parameter that specifies the number of iterations to perform.
90
IntegerParameter iterationsParameter =
91        new IntegerParameter("iterations", "Number of Iterations",
92                             "The number of updates to perform before ending " +
93                             "the job.", false, -1, true, -1, false, 0);
94
95   // The parameter that specifies the time between updates.
96
IntegerParameter timeBetweenUpdatesParameter =
97        new IntegerParameter("time_between_updates", "Time Between Updates (ms)",
98                             "Specifies the length of time in milliseconds " +
99                             "that should be allowed between updates. Note " +
100                             "that this time is measured between the " +
101                             "beginning of one update and the beginning of " +
102                             "the next rather than the end of one and the " +
103                             "beginning of the next.", true, 0, true, 0, false,
104                             0);
105
106   // The parameter that specifies the length to use for the generated value.
107
IntegerParameter valueLengthParameter =
108        new IntegerParameter("value_length", "Generated Value Length",
109                             "Specifies the number of characters to include " +
110                             "in the randomly-generated value to use in the " +
111                             "update.", true, 20, true, 1, false, 0);
112
113   // The parameter that specifies the warm up time.
114
IntegerParameter warmUpParameter =
115        new IntegerParameter("warm_up", "Warm Up Time (s)",
116                             "Specifies the length of time in seconds after " +
117                             "the job starts that it should begin collecting " +
118                             "statistics.", true, 0, true, 0, false, 0);
119
120   // The parameter that specifies the password to use to connect to the DB.
121
PasswordParameter passwordParameter =
122        new PasswordParameter("password", "User Password",
123                              "The password for the user account to use to " +
124                              "connect to the database.", false, "");
125
126   // A placeholder used for spacing in the admin interface.
127
PlaceholderParameter placeholder = new PlaceholderParameter();
128
129   // The parameter that specifies the Java class that provides the JDBC driver.
130
StringParameter driverClassParameter =
131        new StringParameter("driver_class", "JDBC Driver Class",
132                            "The fully-qualified Java class that provides " +
133                            "the JDBC interface to the SQL database.", true, "");
134
135   // The parameter that specifies the JDBC URL to connect to the database.
136
StringParameter jdbcURLParameter =
137        new StringParameter("jdbc_url", "JDBC URL",
138                            "The URL that specifies the information to use to " +
139                            "connect to the SQL database.", true, "");
140
141   // The parameter that specifies the database column to match.
142
StringParameter matchColumnParameter =
143        new StringParameter("match_column", "Column to Match",
144                            "The name of the database column to query in " +
145                            "order to find the records to update.", true, "");
146
147   // The parameter that specifies the text to use to peform the match.
148
StringParameter matchValueParameter =
149        new StringParameter("match_value", "Match Value",
150                            "The value or value pattern to use to find the " +
151                            "records to update. It may optionally include a " +
152                            "bracketed pair of integers separated by a dash " +
153                            "(for random access) or a colon (for sequential " +
154                            "access) to alter the query each time it is " +
155                            "issued.", true, "");
156
157   // The parameter that specifies the name of the table to use.
158
StringParameter tableNameParameter =
159        new StringParameter("table_name", "Table Name",
160                            "The of the table in the database in which the " +
161                            "updates should be performed.", true, "");
162
163   // The parameter that specifies the database column to update.
164
StringParameter updateColumnParameter =
165        new StringParameter("update_column", "Column to Update",
166                            "The name of the database column to replace with " +
167                            "a randomly generated string in matching records.",
168                            true, "");
169
170   // The parameter that specifies the username to use to connect to the DB.
171
StringParameter userNameParameter =
172        new StringParameter("username", "User Name",
173                            "The username for the account to use to connect " +
174                            "to the database.", false, "");
175
176
177
178   // Variables that correspond to parameter values.
179
static boolean alwaysDisconnect;
180   static boolean useRange;
181   static boolean useSequential;
182   static int coolDownTime;
183   static int iterations;
184   static int rangeMin;
185   static int rangeMax;
186   static int rangeSpan;
187   static int sequentialCounter;
188   static int timeBetweenUpdates;
189   static int valueLength;
190   static int warmUpTime;
191   static String JavaDoc driverClass;
192   static String JavaDoc jdbcURL;
193   static String JavaDoc matchColumn;
194   static String JavaDoc tableName;
195   static String JavaDoc updateColumn;
196   static String JavaDoc userName;
197   static String JavaDoc userPassword;
198   static String JavaDoc valueInitial;
199   static String JavaDoc valueFinal;
200
201
202   // Variables used in generating random numbers.
203
static Random parentRandom;
204   Random random;
205
206
207   // A variable representing the connection to the database.
208
Connection connection;
209
210
211   // Variables used for tracking statistics.
212
IncrementalTracker exceptionsCaught;
213   IncrementalTracker updatesCompleted;
214   TimeTracker updateTimer;
215
216
217
218   /**
219    * Creates a new instance of this SQL SearchRate job.
220    */

221   public SQLModRateJobClass()
222   {
223     super();
224   }
225
226
227
228   /**
229    * Retrieves the display name for this job.
230    *
231    * @return The display name for this job.
232    */

233   public String JavaDoc getJobName()
234   {
235     return "SQL ModRate";
236   }
237
238
239
240   /**
241    * Retrieves a description for this job.
242    *
243    * @return A description for this job.
244    */

245   public String JavaDoc getJobDescription()
246   {
247     return "This job can be used to repeatedly perform updates in an SQL " +
248            "database to generate load and measure performance.";
249   }
250
251
252
253   /**
254    * Retrieves the name of the category in which this job class should be
255    * classified. This is used to arrange the job classes in the administrative
256    * interface.
257    *
258    * @return The name of the category in which this job class should be
259    * classified.
260    */

261   public String JavaDoc getJobCategoryName()
262   {
263     return "SQL";
264   }
265
266
267
268   /**
269    * Retrieves a parameter list that can be used to determine all the
270    * customizeable options that are available for this job.
271    *
272    * @return A parameter list that can be used to determine all the
273    * customizable options that are available for this job.
274    */

275   public ParameterList getParameterStubs()
276   {
277     Parameter[] parameters = new Parameter[]
278     {
279       placeholder,
280       driverClassParameter,
281       jdbcURLParameter,
282       userNameParameter,
283       passwordParameter,
284       placeholder,
285       tableNameParameter,
286       updateColumnParameter,
287       valueLengthParameter,
288       matchColumnParameter,
289       matchValueParameter,
290       placeholder,
291       warmUpParameter,
292       coolDownParameter,
293       timeBetweenUpdatesParameter,
294       iterationsParameter,
295       disconnectParameter
296     };
297
298     return new ParameterList(parameters);
299   }
300
301
302
303   /**
304    * Retrieves the set of stat trackers that will be maintained by this job
305    * class.
306    *
307    * @param clientID The client ID that should be used for the
308    * returned stat trackers.
309    * @param threadID The thread ID that should be used for the
310    * returned stat trackers.
311    * @param collectionInterval The collection interval that should be used for
312    * the returned stat trackers.
313    *
314    * @return The set of stat trackers that will be maintained by this job
315    * class.
316    */

317   public StatTracker[] getStatTrackerStubs(String JavaDoc clientID, String JavaDoc threadID,
318                                            int collectionInterval)
319   {
320     return new StatTracker[]
321     {
322       new IncrementalTracker(clientID, threadID, STAT_TRACKER_UPDATES_COMPLETED,
323                              collectionInterval),
324       new TimeTracker(clientID, threadID, STAT_TRACKER_UPDATE_DURATION,
325                       collectionInterval),
326       new IncrementalTracker(clientID, threadID, STAT_TRACKER_EXCEPTIONS_CAUGHT,
327                              collectionInterval)
328     };
329   }
330
331
332
333   /**
334    * Retrieves the set of stat trackers that have been maintained by this job.
335    *
336    * @return The set of stat trackers that have been maintained by this job.
337    */

338   public StatTracker[] getStatTrackers()
339   {
340     return new StatTracker[]
341     {
342       updatesCompleted,
343       updateTimer,
344       exceptionsCaught
345     };
346   }
347
348
349
350   /**
351    * Indicates whether this job class implements logic that makes it possible to
352    * test the validity of job parameters before scheduling the job for execution
353    * (e.g., to see if the server is reachable using the information provided).
354    *
355    * @return <CODE>true</CODE> if this job provides a means of testing the job
356    * parameters, or <CODE>false</CODE> if not.
357    */

358   public boolean providesParameterTest()
359   {
360     return true;
361   }
362
363
364
365   /**
366    * Provides a means of testing the provided job parameters to determine
367    * whether they are valid (e.g., to see if the server is reachable) before
368    * scheduling the job for execution. This method will be executed by the
369    * SLAMD server system itself and not by any of the clients.
370    *
371    * @param parameters The job parameters to be tested.
372    * @param outputMessages The lines of output that were generated as part of
373    * the testing process. Each line of output should
374    * be added to this list as a separate string, and
375    * empty strings (but not <CODE>null</CODE> values)
376    * are allowed to provide separation between
377    * different messages. No formatting should be
378    * provided for these messages, however, since they
379    * may be displayed in either an HTML or plain text
380    * interface.
381    *
382    * @return <CODE>true</CODE> if the test completed successfully, or
383    * <CODE>false</CODE> if not. Note that even if the test did not
384    * complete successfully, the user will be presented with a warning
385    * but will still be allowed to schedule the job using the provided
386    * parameters. This is necessary because the parameters may still be
387    * valid even if the server couldn't validate them at the time the
388    * job was scheduled (e.g., if the server wasn't running or could not
389    * be reached by the SLAMD server even though it could be by the
390    * clients).
391    */

392   public boolean testJobParameters(ParameterList parameters,
393                                    ArrayList outputMessages)
394   {
395     // Get the necessary parameter values.
396
StringParameter driverParam =
397          parameters.getStringParameter(driverClassParameter.getName());
398     if ((driverParam == null) || (! driverParam.hasValue()))
399     {
400       outputMessages.add("ERROR: No JDBC driver class provided.");
401       return false;
402     }
403     String JavaDoc driverClass = driverParam.getStringValue();
404
405
406     StringParameter urlParam =
407          parameters.getStringParameter(jdbcURLParameter.getName());
408     if ((urlParam == null) || (! urlParam.hasValue()))
409     {
410       outputMessages.add("ERROR: No JDBC URL provided.");
411       return false;
412     }
413     String JavaDoc jdbcURL = urlParam.getStringValue();
414
415
416     String JavaDoc userName = "";
417     StringParameter usernameParam =
418          parameters.getStringParameter(userNameParameter.getName());
419     if ((usernameParam != null) && usernameParam.hasValue())
420     {
421       userName = usernameParam.getStringValue();
422     }
423
424
425     String JavaDoc userPW = "";
426     PasswordParameter pwParam =
427          parameters.getPasswordParameter(passwordParameter.getName());
428     if ((pwParam != null) && pwParam.hasValue())
429     {
430       userPW = pwParam.getStringValue();
431     }
432
433
434     // Try to load the JDBC driver.
435
try
436     {
437       outputMessages.add("Trying to load JDBC driver class '" + driverClass +
438                          "'....");
439       Class.forName(driverClass);
440       outputMessages.add("Driver class loaded successfully.");
441       outputMessages.add("");
442     }
443     catch (Exception JavaDoc e)
444     {
445       outputMessages.add("ERROR: Unable to load driver class: " +
446                          stackTraceToString(e));
447       return false;
448     }
449
450
451     // Try to establish a connection to the database using the JDBC URL,
452
// username, and password.
453
try
454     {
455       outputMessages.add("Trying to connect to database using JDBC URL '" +
456                          jdbcURL + "' as user '" + userName + "'....");
457
458       Connection connection = DriverManager.getConnection(jdbcURL, userName,
459                                                           userPW);
460
461       outputMessages.add("Connected successfully.");
462       outputMessages.add("");
463
464       try
465       {
466         connection.close();
467       } catch (Exception JavaDoc e) {}
468
469       outputMessages.add("Connection closed.");
470       outputMessages.add("");
471     }
472     catch (Exception JavaDoc e)
473     {
474       outputMessages.add("ERROR: Unable to connect: " +
475                          stackTraceToString(e));
476       return false;
477     }
478
479     outputMessages.add("All tests completed.");
480     return true;
481   }
482
483
484
485   /**
486    * Performs one-time client initialization for this job, including assinging
487    * the values of the parameters to instance variables.
488    *
489    * @param clientID The client ID for the current client.
490    * @param parameters The set of parameters that have been defined for this
491    * job.
492    */

493   public void initializeClient(String JavaDoc clientID, ParameterList parameters)
494   {
495     // Get the database driver class.
496
driverClass = null;
497     driverClassParameter =
498          parameters.getStringParameter(driverClassParameter.getName());
499     if (driverClassParameter != null)
500     {
501       driverClass = driverClassParameter.getStringValue();
502     }
503
504     // Get the JDBC URL to use to connect to the database.
505
jdbcURL = null;
506     jdbcURLParameter =
507          parameters.getStringParameter(jdbcURLParameter.getName());
508     if (jdbcURLParameter != null)
509     {
510       jdbcURL = jdbcURLParameter.getStringValue();
511     }
512
513     // Get the username to use to connect to the database.
514
userName = "";
515     userNameParameter =
516          parameters.getStringParameter(userNameParameter.getName());
517     if ((userNameParameter != null) && userNameParameter.hasValue())
518     {
519       userName = userNameParameter.getStringValue();
520     }
521
522     // Get the password to use to connect to the database.
523
userPassword = "";
524     passwordParameter =
525          parameters.getPasswordParameter(passwordParameter.getName());
526     if ((passwordParameter != null) && passwordParameter.hasValue())
527     {
528       userPassword = passwordParameter.getStringValue();
529     }
530
531     // Get the name of the table in which to make the update.
532
tableName = null;
533     tableNameParameter =
534          parameters.getStringParameter(tableNameParameter.getName());
535     if (tableNameParameter != null)
536     {
537       tableName = tableNameParameter.getStringValue();
538     }
539
540     // Get the name of the column to update.
541
updateColumn = null;
542     updateColumnParameter =
543          parameters.getStringParameter(updateColumnParameter.getName());
544     if (updateColumnParameter != null)
545     {
546       updateColumn = updateColumnParameter.getStringValue();
547     }
548
549     // Get the length to use for the randomly-generated value.
550
valueLength = 20;
551     valueLengthParameter =
552          parameters.getIntegerParameter(valueLengthParameter.getName());
553     if (valueLengthParameter != null)
554     {
555       valueLength = valueLengthParameter.getIntValue();
556     }
557
558     // Get the name of the column to match.
559
matchColumn = null;
560     matchColumnParameter =
561          parameters.getStringParameter(matchColumnParameter.getName());
562     if (matchColumnParameter != null)
563     {
564       matchColumn = matchColumnParameter.getStringValue();
565     }
566
567     // Get the match value to use.
568
matchValueParameter =
569          parameters.getStringParameter(matchValueParameter.getName());
570     if (matchValueParameter != null)
571     {
572       String JavaDoc valueStr = matchValueParameter.getStringValue();
573       useRange = false;
574       useSequential = false;
575
576       int openBracketPos = valueStr.indexOf('[');
577       int dashPos = valueStr.indexOf('-', openBracketPos);
578       if (dashPos < 0)
579       {
580         dashPos = valueStr.indexOf(':', openBracketPos);
581         useSequential = true;
582       }
583
584       int closeBracketPos;
585       if ((openBracketPos >= 0) && (dashPos > 0) &&
586           ((closeBracketPos = valueStr.indexOf(']', dashPos)) > 0))
587       {
588         try
589         {
590           rangeMin = Integer.parseInt(valueStr.substring(openBracketPos+1,
591                                                          dashPos));
592           rangeMax = Integer.parseInt(valueStr.substring(dashPos+1,
593                                                          closeBracketPos));
594           rangeSpan = rangeMax - rangeMin + 1;
595
596           valueInitial = valueStr.substring(0, openBracketPos);
597           valueFinal = valueStr.substring(closeBracketPos+1);
598           useRange = true;
599           sequentialCounter = rangeMin;
600         }
601         catch (Exception JavaDoc e)
602         {
603           useRange = false;
604         }
605       }
606       else
607       {
608         useRange = false;
609       }
610     }
611
612     // Get the warm up time.
613
warmUpTime = 0;
614     warmUpParameter = parameters.getIntegerParameter(warmUpParameter.getName());
615     if (warmUpParameter != null)
616     {
617       warmUpTime = warmUpParameter.getIntValue();
618     }
619
620     // Get the cool down time.
621
coolDownTime = 0;
622     coolDownParameter =
623          parameters.getIntegerParameter(coolDownParameter.getName());
624     if (coolDownParameter != null)
625     {
626       coolDownTime = coolDownParameter.getIntValue();
627     }
628
629     // Get the time between updates.
630
timeBetweenUpdates = 0;
631     timeBetweenUpdatesParameter =
632          parameters.getIntegerParameter(timeBetweenUpdatesParameter.getName());
633     if (timeBetweenUpdatesParameter != null)
634     {
635       timeBetweenUpdates = timeBetweenUpdatesParameter.getIntValue();
636     }
637
638     // Get the number of iterations to perform.
639
iterations = -1;
640     iterationsParameter =
641          parameters.getIntegerParameter(iterationsParameter.getName());
642     if ((iterationsParameter != null) && iterationsParameter.hasValue())
643     {
644       iterations = iterationsParameter.getIntValue();
645     }
646
647     // Determine whether to disconnect after each query.
648
alwaysDisconnect = false;
649     disconnectParameter =
650          parameters.getBooleanParameter(disconnectParameter.getName());
651     if (disconnectParameter != null)
652     {
653       alwaysDisconnect = disconnectParameter.getBooleanValue();
654     }
655
656
657     // Initialize the parent random number generator.
658
parentRandom = new Random();
659   }
660
661
662
663   /**
664    * Performs one-time client initialization for this job, including assinging
665    * the values of the parameters to instance variables.
666    *
667    * @param clientID The client ID for the current client.
668    * @param threadID The thread ID for the current thread.
669    * @param collectionInterval The length of time in seconds to use as the
670    * statistics collection interval.
671    * @param parameters The set of parameters that have been defined
672    * for this job.
673    */

674   public void initializeThread(String JavaDoc clientID, String JavaDoc threadID,
675                                int collectionInterval, ParameterList parameters)
676   {
677     // Initialize the stat trackers.
678
updatesCompleted = new IncrementalTracker(clientID, threadID,
679                                               STAT_TRACKER_UPDATES_COMPLETED,
680                                               collectionInterval);
681     updateTimer = new TimeTracker(clientID, threadID,
682                                   STAT_TRACKER_UPDATE_DURATION,
683                                   collectionInterval);
684     exceptionsCaught = new IncrementalTracker(clientID, threadID,
685                                               STAT_TRACKER_EXCEPTIONS_CAUGHT,
686                                               collectionInterval);
687
688
689     // Enable real-time reporting of the data for these stat trackers.
690
RealTimeStatReporter statReporter = getStatReporter();
691     if (statReporter != null)
692     {
693       String JavaDoc jobID = getJobID();
694       updatesCompleted.enableRealTimeStats(statReporter, jobID);
695       updateTimer.enableRealTimeStats(statReporter, jobID);
696       exceptionsCaught.enableRealTimeStats(statReporter, jobID);
697     }
698
699
700     // Initialize the thread-specific random number generator.
701
random = new Random(parentRandom.nextLong());
702   }
703
704
705
706   /**
707    * Perform the work of actually querying the database.
708    */

709   public void runJob()
710   {
711     // First, load the driver class. It will automatically be registered with
712
// the JDBC driver manager.
713
try
714     {
715       Class.forName(driverClass);
716     }
717     catch (Exception JavaDoc e)
718     {
719       logMessage("Unable to load the driver class \"" + driverClass + "\" -- " +
720                  e);
721       indicateStoppedDueToError();
722       return;
723     }
724
725
726     // Determine the range of time for which we should collect statistics.
727
long currentTime = System.currentTimeMillis();
728     boolean collectingStats = false;
729     long startCollectingTime = currentTime + (1000 * warmUpTime);
730     long stopCollectingTime = Long.MAX_VALUE;
731     if ((coolDownTime > 0) && (getShouldStopTime() > 0))
732     {
733       stopCollectingTime = getShouldStopTime() - (1000 * coolDownTime);
734     }
735
736
737     // Set up variables that will be used throughout the job.
738
boolean connected = false;
739     boolean infinite = (iterations <= 0);
740     long updateStartTime = 0;
741     PreparedStatement statement = null;
742     connection = null;
743
744
745     // Loop until it is determined we should stop.
746
for (int i=0; ((! shouldStop()) && ((infinite || (i < iterations)))); i++)
747     {
748       currentTime = System.currentTimeMillis();
749       if ((! collectingStats) && (currentTime >= startCollectingTime) &&
750           (currentTime < stopCollectingTime))
751       {
752         // Tell the stat trackers that they should start tracking now.
753
updatesCompleted.startTracker();
754         updateTimer.startTracker();
755         exceptionsCaught.startTracker();
756         collectingStats = true;
757       }
758       else if (collectingStats && (currentTime >= stopCollectingTime))
759       {
760         // Tell the stat trackers that tehy should stop tracking now.
761
updatesCompleted.stopTracker();
762         updateTimer.stopTracker();
763         exceptionsCaught.stopTracker();
764         collectingStats = false;
765       }
766
767
768       // If the connection is not currently established, then connect it.
769
if (! connected)
770       {
771         try
772         {
773           connection = DriverManager.getConnection(jdbcURL, userName,
774                                                    userPassword);
775           connected = true;
776         }
777         catch (SQLException se)
778         {
779           logMessage("Unable to connect to the database: " + se);
780           indicateStoppedDueToError();
781           break;
782         }
783
784         String JavaDoc sql = "UPDATE " + tableName + " SET " + updateColumn +
785                      " = ? WHERE " + matchColumn + " = ?;";
786         try
787         {
788           statement = connection.prepareStatement(sql);
789         }
790         catch (SQLException se)
791         {
792           logMessage("Unable to parse SQL statement \"" + sql + "\".");
793           indicateStoppedDueToError();
794           break;
795         }
796       }
797
798
799       // Execute the query and process through the results.
800
if (timeBetweenUpdates > 0)
801       {
802         updateStartTime = System.currentTimeMillis();
803       }
804       if (collectingStats)
805       {
806         updateTimer.startTimer();
807       }
808       try
809       {
810         if (useRange)
811         {
812           statement.setString(1, getRandomValue(valueLength));
813           statement.setString(2, getMatchValue());
814         }
815         statement.execute();
816         if (collectingStats)
817         {
818           updateTimer.stopTimer();
819           updatesCompleted.increment();
820         }
821       }
822       catch (SQLException se)
823       {
824         writeVerbose("Caught SQL Exception: " + se);
825         if (collectingStats)
826         {
827           exceptionsCaught.increment();
828         }
829       }
830
831
832       // If we should disconnect from the database, then do so.
833
if (alwaysDisconnect)
834       {
835         try
836         {
837           statement.close();
838         } catch (Exception JavaDoc e) {}
839
840         try
841         {
842           connection.close();
843         } catch (Exception JavaDoc e) {}
844         connected = false;
845       }
846
847
848       // If we should sleep before the next query, then do so.
849
if (timeBetweenUpdates > 0)
850       {
851         if (! shouldStop())
852         {
853           long now = System.currentTimeMillis();
854           long sleepTime = timeBetweenUpdates - (now - updateStartTime);
855           if (sleepTime > 0)
856           {
857             try
858             {
859               Thread.sleep(sleepTime);
860             } catch (InterruptedException JavaDoc ie) {}
861           }
862         }
863       }
864     }
865
866
867     // If the connection is still established, then close it.
868
if (connected)
869     {
870       try
871       {
872         statement.close();
873       } catch (Exception JavaDoc e) {}
874
875       try
876       {
877         connection.close();
878       } catch (Exception JavaDoc e) {}
879     }
880
881     if (collectingStats)
882     {
883       updatesCompleted.stopTracker();
884       updateTimer.stopTracker();
885       exceptionsCaught.stopTracker();
886     }
887   }
888
889
890
891   /**
892    * Try to force the thread to exit by closing the connection to the database
893    * and setting it to <CODE>null</CODE>.
894    */

895   public void destroy()
896   {
897     if (connection != null)
898     {
899       try
900       {
901         connection.close();
902       } catch (Exception JavaDoc e) {}
903
904       connection = null;
905     }
906   }
907
908
909
910   /**
911    * Generates a string of randomly chosen alphabetic characters.
912    *
913    * @param valueLength The number of characters to include in the value.
914    *
915    * @return The string of randomly chosen alphabetic characters.
916    */

917   public String JavaDoc getRandomValue(int valueLength)
918   {
919     char[] returnChars = new char[valueLength];
920
921     for (int i=0; i < valueLength; i++)
922     {
923       returnChars[i] = ALPHABET[Math.abs((random.nextInt()) & 0x7FFFFFFF) %
924                                 ALPHABET.length];
925     }
926
927     return new String JavaDoc(returnChars);
928   }
929
930
931
932   /**
933    * Retrieves a value to use to match the row(s) to update.
934    *
935    * @return A value to use to match the row(s) to update.
936    */

937   public String JavaDoc getMatchValue()
938   {
939     if (useRange)
940     {
941       int value;
942       if (useSequential)
943       {
944         value = sequentialCounter++;
945         if (sequentialCounter > rangeMax)
946         {
947           sequentialCounter = rangeMin;
948         }
949       }
950       else
951       {
952         value = ((random.nextInt() & 0x7FFFFFFF) % rangeSpan) + rangeMin;
953       }
954
955       return valueInitial + value + valueFinal;
956     }
957     else
958     {
959       return valueInitial;
960     }
961   }
962 }
963
964
Popular Tags