Por: JBuilder R&D Team
Resumo: WebBench is a multi-threaded application that shows how to establish concurrent connections to a transactional datastore. It demonstrates JDataStore's ability to support large amounts of data and many concurrent transactions.
by the JBuilder Team
Abstract: WebBench is
a multi-threaded application that shows how to establish concurrent connections
to a transactional datastore. It demonstrates JDataStore's ability to support
large amounts of data and many concurrent transactions. You choose the
number of concurrent users and other configuration options, set WebBench
running, and see how many transactions were executed. In this way, you
can use WebBench as a benchmarking tool.
can run WebBench?
To run WebBench, you must have JBuilder
3.5 Pro (with JDataStore installed), JBuilder 3.5 Enterprise, or the standalone
JDataStore 3.5. You can download JDataStore 3.5, with a license for
development use only, from JDataStore
3.5 Downloads. All these products include WebBench as a sample,
but you can get a slightly newer version from [link]. Then follow
the instructions for running WebBench.
WebBench generates sample data for an
order-entry application and runs sample transactions. Through the application's
UI or code you can set parameters such as table size, number of connections,
type of transactions (read-write, read-only or both), and the duration
of the test. When you select Run, the requested connections to the datastore
are established and begin running transactions. After it has run for the
requested time, WebBench shuts down the connections and reports the number
of transactions executed.
Unlike most sample applications, WebBench
features industrial-strength - and industrial-sized - tables. Generating
the datastore takes five to ten minutes, and the store and its log files
together occupy about 150 megabytes. The data itself isn't very interesting
- sometimes just strings of random characters. However, the data is realistic
where it counts: in the mix of datatypes used, the relationships between
tables, the index defined, and the values in key columns. As a result,
this data can be used to simulate realistic production transactions and
to investigate how throughput varies with table size, number of concurrent
users, transaction type, and other variables.
WebBench's UI isn't dramatic - just the
necessary menus and status reporting. You may want to use the DataStore
Explorer along with WebBench to see what's happening inside the datastore.
If you do, remember that WebBench and DataStore Explorer can't open a datastore
at the same time. Only open the store in the DataStore Explorer between
WebBench operations, and close it again before the next WebBench run. If
you run read/write transactions, you'll see that new records are added
at the end of the ORDERS and ORDER_LINE tables (check the values in the
timestamp column to see when they were added). Several other tables are
updated. Study the SQL statements in ReadWriteTx.java for details.
Follow these steps to create the database
and populate it with data
Keep in mind when comparing benchmark results
that there is a element of randomness in the tests. Random numbers are
used to determine which customer's record is selected, how many line items
are inserted, whether or not a transaction is rolled back, and so on. As
a result, one benchmark run might have to do more work than a second run
with the same parameters. Also note that read/write transactions add records
to several table, which might perturb the situation slightly.
of WebBench's code
Application structure and UI: WebBenchApp
and WebBenchFrame are the default JBuilder
application files. WebBenchApp is the main executable file and WebBenchFrame
is the UI. WebBenchFrame is designable, but because the UI is one big jTextArea,
there's not much to see in the UI designer. However, you can open the menu
designer and examine the menu's organization, properties, and event handlers.
is opened from Bench | Options and RunDialog
is opened from Bench | Run.
class is responsible for storing and managing settings from the options
dialogs. AppProperties knows how to save its data to disk (as WebBench.properties,
in the java user directory) and reload it. At startup, WebBenchFrame calls
AppProperties' static getAppProperties() method. This reloads previous
settings, if any, and provides WebBenchFrame with any information about
options that it needs. Other classes use AppProperties in the same way.
Event handlers and backup: WebBenchFrame's
event handlers are where the application's UI and its database manipulation
meet. The major menu commands are File | Backup, Bench | Load Data, and
Bench | Run. The code in all three is organized in the same way. As an
example, let's look at BackupDataItem_actionPerformed, the event handler
for File | Backup. Associated with it is the class BackupThread, defined
in WebBenchFrame.java. The event handler creates an instance of BackupThread
and sets it running. BackupThread in turn creates a BackupData
object which does the necessary work with datastores while BackupThread
handles the status reporting in the WebBench UI.
The BackupData class is fairly simple.
It gets the current datastore name from AppProperties, prepends "backup"
to it to name the backup datastore, creates the backup datastore in the
same directory (deleting the existing datastore of that name, if there
is one), and uses DataStore's copyStreams() method to copy everything in
the original datastore to the backup.
One other small class comes into play here.
A transactional datastore consists of a single file for data, one or more
log files, and two status files.
is a utility class that simplifies working with this set of files. BackupData
and JDataStoreDriver use FileList.
work: WebBench does most of its database work through SQL statements
that should run on any database server. However, some operations, such
as establishing the connection to the server and creating and dropping
databases, are done differently by each server. Driver
is an abstract class that encapsulates the server-specific work that WebBench
needs to do. JDataStoreDriver is a
concrete extension of Driver for JDataStore. Almost everything in WebBench
that is specific to JDataStore is in JDataStoreDriver. With extensions
of Driver for other database servers, WebBench could be used to compare
their performance to JDataStore's.
In a few cases code outside of Driver and
its subclasses is not generic:
Loading tables: We've seen how WebBenchFrame's
event handler for the File | Backup menu command works. Bench | Load Data
is similar. The event handler creates and runs an instance of DataLoadThread,
defined in WebBenchFrame.java, and sets it running. DataLoadThread handles
the UI updating and creates a LoadData
object to do the database work. The novelty here is that LoadData in turn
instantiates another class of interest, Tx.
Tx and LoadData both execute SQL statements. Tx's statements, which create
tables and indexes, are hard-coded. LoadData generates data and inserts
it into the tables using prepared statements and parameterized queries.
LoadData intermixes calls to Tx with its own work. It stops running when
it's done and thus returns control to the UI.
Running transactions: Bench | Run
present the Run Options dialog. Assuming you close the dialog by clicking
the Run button, the menu command's event handler starts a TxRunnerThread
(as usual, this class is defined in WebBenchFrame.java), which creates
and runs a TxRunner. Parameters to
TxRunner's constructor tell it the number of connections to create for
each type of transaction. It creates the appropriate ReadOnlyTx
and/or ReadWriteTx objects, sets each
as the target of a new thread, and starts the threads. When every transaction
objects is ready to run transactions, TxRunner signals them all to start,
waits for the specified time, stops the threads, closes the transaction
objects, and reports the results.
ReadOnlyTx and ReadWriteTx extend Tx, which
contains the methods for synchronizing transaction runners that they both
need. Their work is in two parts: first, they create prepared statements
for all the SQL statements they will run; then, when TxRunner tells them
to start, they run transactions until told to stop. Like Tx and LoadData,
ReadOnlyTx and ReadWriteTx do all their work using classes from the java.sql
package such as Connection, PreparedStatement, and ResultSet. Because the
focus here is on database operations rather than data manipulation in the
application, the DataExpress component set is not used, except for isolated
use of a few classes such as DataSetException.
ReadWriteTx inserts a new order record
and a random number of line items for a randomly-chosen customer. The transaction
runs a total of nine different SQL statements, including queries against
customer, stock, and item tables among others and updates to stock and
next-ID information. Not all transactions succeed; on a random basis, some
are rolled back. ReadOnlyTx executes the same queries but omits the inserts
Download the WebBench source code (zip file format).
To uncompress this file properly, make sure you preserve folder names.
Server Response from: ETNASC03