00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 package db;
00011
00012 import com.sleepycat.db.*;
00013
00014 import java.io.File;
00015 import java.io.FileNotFoundException;
00016 import java.math.BigDecimal;
00017 import java.util.Calendar;
00018 import java.util.Date;
00019 import java.util.Random;
00020 import java.util.GregorianCalendar;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 class TpcbExample {
00031 public static final int TELLERS_PER_BRANCH = 10;
00032 public static final int ACCOUNTS_PER_TELLER = 10000;
00033 public static final int HISTORY_PER_BRANCH = 2592000;
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 public static final int ACCOUNTS = 100000;
00060 public static final int BRANCHES = 10;
00061 public static final int TELLERS = 100;
00062 public static final int HISTORY = 259200;
00063
00064 public static final int HISTORY_LEN = 100;
00065 public static final int RECLEN = 100;
00066 public static final int BEGID = 1000000;
00067
00068
00069 public static final int ACCOUNT = 0;
00070 public static final int BRANCH = 1;
00071 public static final int TELLER = 2;
00072
00073 public static boolean verbose = false;
00074 public static final String progname = "TpcbExample";
00075
00076 Environment dbenv;
00077 int accounts, branches, tellers, history;
00078
00079 public TpcbExample(File home,
00080 int accounts, int branches, int tellers, int history,
00081 int cachesize, boolean noSync)
00082 throws DatabaseException, FileNotFoundException {
00083
00084 this.accounts = accounts;
00085 this.branches = branches;
00086 this.tellers = tellers;
00087 this.history = history;
00088
00089 EnvironmentConfig config = new EnvironmentConfig();
00090 config.setErrorStream(System.err);
00091 config.setErrorPrefix(progname);
00092 config.setCacheSize(cachesize == 0 ? 4 * 1024 * 1024 : cachesize);
00093 config.setTxnNoSync(noSync);
00094 config.setLockDetectMode(LockDetectMode.DEFAULT);
00095 config.setAllowCreate(true);
00096
00097 config.setInitializeCache(true);
00098 config.setTransactional(true);
00099 config.setInitializeLocking(true);
00100 config.setInitializeLogging(true);
00101
00102 dbenv = new Environment(home, config);
00103 }
00104
00105 public void close()
00106 throws DatabaseException {
00107
00108 try {
00109 if (dbenv != null)
00110 dbenv.close();
00111 } finally {
00112 dbenv = null;
00113 }
00114 }
00115
00116
00117
00118
00119
00120 public void populate() {
00121 Database dbp = null;
00122
00123 int err;
00124 int balance, idnum;
00125 int end_anum, end_bnum, end_tnum;
00126 int start_anum, start_bnum, start_tnum;
00127 int h_nelem;
00128
00129 idnum = BEGID;
00130 balance = 500000;
00131
00132 h_nelem = accounts;
00133
00134 try {
00135 DatabaseConfig config = new DatabaseConfig();
00136 config.setType(DatabaseType.HASH);
00137 config.setHashNumElements(h_nelem);
00138 config.setAllowCreate(true);
00139 dbp = dbenv.openDatabase(null, "account", null, config);
00140 } catch (Exception e1) {
00141
00142 errExit(e1, "Open of account file failed");
00143 }
00144
00145 start_anum = idnum;
00146 populateTable(dbp, idnum, balance, h_nelem, "account");
00147 idnum += h_nelem;
00148 end_anum = idnum - 1;
00149 try {
00150 dbp.close();
00151 } catch (DatabaseException e2) {
00152 errExit(e2, "Account file close failed");
00153 }
00154
00155 if (verbose)
00156 System.out.println("Populated accounts: " +
00157 String.valueOf(start_anum) + " - " +
00158 String.valueOf(end_anum));
00159
00160
00161
00162
00163
00164
00165 h_nelem = (int)branches;
00166
00167 try {
00168 DatabaseConfig config = new DatabaseConfig();
00169 config.setType(DatabaseType.HASH);
00170 config.setHashNumElements(h_nelem);
00171 config.setHashFillFactor(1);
00172 config.setPageSize(512);
00173 config.setAllowCreate(true);
00174 dbp = dbenv.openDatabase(null, "branch", null, config);
00175 } catch (Exception e3) {
00176
00177 errExit(e3, "Branch file create failed");
00178 }
00179
00180 start_bnum = idnum;
00181 populateTable(dbp, idnum, balance, h_nelem, "branch");
00182 idnum += h_nelem;
00183 end_bnum = idnum - 1;
00184
00185 try {
00186 dbp.close();
00187 } catch (DatabaseException dbe4) {
00188 errExit(dbe4, "Close of branch file failed");
00189 }
00190
00191 if (verbose)
00192 System.out.println("Populated branches: " +
00193 String.valueOf(start_bnum) + " - " +
00194 String.valueOf(end_bnum));
00195
00196
00197
00198
00199
00200 h_nelem = (int)tellers;
00201
00202 try {
00203 DatabaseConfig config = new DatabaseConfig();
00204 config.setType(DatabaseType.HASH);
00205 config.setHashNumElements(h_nelem);
00206 config.setHashFillFactor(0);
00207 config.setPageSize(512);
00208 config.setAllowCreate(true);
00209 dbp = dbenv.openDatabase(null, "teller", null, config);
00210 } catch (Exception e5) {
00211
00212 errExit(e5, "Teller file create failed");
00213 }
00214
00215 start_tnum = idnum;
00216 populateTable(dbp, idnum, balance, h_nelem, "teller");
00217 idnum += h_nelem;
00218 end_tnum = idnum - 1;
00219
00220 try {
00221 dbp.close();
00222 } catch (DatabaseException e6) {
00223 errExit(e6, "Close of teller file failed");
00224 }
00225
00226 if (verbose)
00227 System.out.println("Populated tellers: " +
00228 String.valueOf(start_tnum) + " - " +
00229 String.valueOf(end_tnum));
00230
00231 try {
00232 DatabaseConfig config = new DatabaseConfig();
00233 config.setType(DatabaseType.RECNO);
00234 config.setRecordLength(HISTORY_LEN);
00235 config.setAllowCreate(true);
00236 dbp = dbenv.openDatabase(null, "history", null, config);
00237 } catch (Exception e7) {
00238
00239 errExit(e7, "Create of history file failed");
00240 }
00241
00242 populateHistory(dbp);
00243
00244 try {
00245 dbp.close();
00246 } catch (DatabaseException e8) {
00247 errExit(e8, "Close of history file failed");
00248 }
00249 }
00250
00251 public void populateTable(Database dbp,
00252 int start_id, int balance, int nrecs, String msg) {
00253 Defrec drec = new Defrec();
00254
00255 DatabaseEntry kdbt = new DatabaseEntry(drec.data);
00256 kdbt.setSize(4);
00257 DatabaseEntry ddbt = new DatabaseEntry(drec.data);
00258 ddbt.setSize(drec.data.length);
00259
00260 try {
00261 for (int i = 0; i < nrecs; i++) {
00262 kdbt.setRecordNumber(start_id + (int)i);
00263 drec.set_balance(balance);
00264 dbp.putNoOverwrite(null, kdbt, ddbt);
00265 }
00266 } catch (DatabaseException dbe) {
00267 System.err.println("Failure initializing " + msg + " file: " +
00268 dbe.toString());
00269 System.exit(1);
00270 }
00271 }
00272
00273 public void populateHistory(Database dbp) {
00274 Histrec hrec = new Histrec();
00275 hrec.set_amount(10);
00276
00277 byte[] arr = new byte[4];
00278 int i;
00279 DatabaseEntry kdbt = new DatabaseEntry(arr);
00280 kdbt.setSize(arr.length);
00281 DatabaseEntry ddbt = new DatabaseEntry(hrec.data);
00282 ddbt.setSize(hrec.data.length);
00283
00284 try {
00285 for (i = 1; i <= history; i++) {
00286 kdbt.setRecordNumber(i);
00287
00288 hrec.set_aid(random_id(ACCOUNT));
00289 hrec.set_bid(random_id(BRANCH));
00290 hrec.set_tid(random_id(TELLER));
00291
00292 dbp.append(null, kdbt, ddbt);
00293 }
00294 } catch (DatabaseException dbe) {
00295 errExit(dbe, "Failure initializing history file");
00296 }
00297 }
00298
00299 static Random rand = new Random();
00300 public static int random_int(int lo, int hi) {
00301 int t = rand.nextInt();
00302 if (t < 0)
00303 t = -t;
00304 int ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) *
00305 (hi - lo + 1));
00306 ret += lo;
00307 return (ret);
00308 }
00309
00310 public int random_id(int type) {
00311 int min, max, num;
00312
00313 max = min = BEGID;
00314 num = accounts;
00315 switch(type) {
00316 case TELLER:
00317 min += branches;
00318 num = tellers;
00319
00320 case BRANCH:
00321 if (type == BRANCH)
00322 num = branches;
00323 min += accounts;
00324
00325 case ACCOUNT:
00326 max = min + num - 1;
00327 }
00328 return (random_int(min, max));
00329 }
00330
00331
00332
00333 static long get_int_in_array(byte[] array, int offset) {
00334 return
00335 ((0xff & array[offset + 0]) << 0) |
00336 ((0xff & array[offset + 1]) << 8) |
00337 ((0xff & array[offset + 2]) << 16) |
00338 ((0xff & array[offset + 3]) << 24);
00339 }
00340
00341
00342 static void set_int_in_array(byte[] array, int offset, long value) {
00343 array[offset + 0] = (byte)((value >> 0) & 0xff);
00344 array[offset + 1] = (byte)((value >> 8) & 0xff);
00345 array[offset + 2] = (byte)((value >> 16) & 0xff);
00346 array[offset + 3] = (byte)((value >> 24) & 0xff);
00347 }
00348
00349
00350 static String showRounded(double d, int scale) {
00351 return new BigDecimal(d).
00352 setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString();
00353 }
00354
00355 public void run(int ntxns, int threads) {
00356 double gtps;
00357 int txns, failed;
00358 long curtime, starttime;
00359 TxnThread[] txnList = new TxnThread[threads];
00360 for (int i = 0; i < threads; i++)
00361 txnList[i] = new TxnThread("Thread " + String.valueOf(i), ntxns);
00362
00363 starttime = (new Date()).getTime();
00364 for (int i = 0; i < threads; i++)
00365 txnList[i].start();
00366 for (int i = 0; i < threads; i++)
00367 try {
00368 txnList[i].join();
00369 } catch (Exception e1) {
00370 errExit(e1, "join failed");
00371 }
00372
00373 curtime = (new Date()).getTime();
00374 txns = failed = 0;
00375 for (int i = 0; i < threads; i++) {
00376 txns += txnList[i].txns;
00377 failed += txnList[i].failed;
00378 }
00379 gtps = (double)(txns - failed) /
00380 ((curtime - starttime) / 1000.0);
00381 System.out.print("\nTotal: " +
00382 String.valueOf(txns) + " txns " +
00383 String.valueOf(failed) + " failed ");
00384 System.out.println(showRounded(gtps, 2) + " TPS");
00385 }
00386
00387 class TxnThread extends Thread {
00388 private int ntxns;
00389 public int txns, failed;
00390 private Database adb, bdb, hdb, tdb;
00391
00392 public TxnThread(String name, int ntxns) {
00393 super(name);
00394 this.ntxns = ntxns;
00395 }
00396
00397 public void run() {
00398 double gtps, itps;
00399 int n, ret;
00400 long start_time, end_time;
00401
00402
00403
00404
00405 int err;
00406 try {
00407 DatabaseConfig config = new DatabaseConfig();
00408 config.setTransactional(true);
00409 adb = dbenv.openDatabase(null, "account", null, config);
00410 bdb = dbenv.openDatabase(null, "branch", null, config);
00411 tdb = dbenv.openDatabase(null, "teller", null, config);
00412 hdb = dbenv.openDatabase(null, "history", null, config);
00413 } catch (DatabaseException dbe) {
00414 TpcbExample.errExit(dbe, "Open of db files failed");
00415 } catch (FileNotFoundException fnfe) {
00416 TpcbExample.errExit(fnfe, "Open of db files failed, missing file");
00417 }
00418
00419 start_time = (new Date()).getTime();
00420 for (txns = n = ntxns, failed = 0; n-- > 0;)
00421 if ((ret = txn()) != 0)
00422 failed++;
00423 end_time = (new Date()).getTime();
00424 if (end_time == start_time)
00425 end_time++;
00426
00427 System.out.println(getName() + ": " + (long)txns + " txns: " +
00428 failed + " failed, " + TpcbExample.showRounded(
00429 (txns - failed) / (double)(end_time - start_time), 2) + " TPS");
00430
00431 try {
00432 adb.close();
00433 bdb.close();
00434 tdb.close();
00435 hdb.close();
00436 } catch (DatabaseException dbe2) {
00437 TpcbExample.errExit(dbe2, "Close of db files failed");
00438 }
00439 }
00440
00441
00442
00443
00444 int txn() {
00445 Cursor acurs = null;
00446 Cursor bcurs = null;
00447 Cursor hcurs = null;
00448 Cursor tcurs = null;
00449 Transaction t = null;
00450
00451 Defrec rec = new Defrec();
00452 Histrec hrec = new Histrec();
00453 int account, branch, teller;
00454
00455 DatabaseEntry d_dbt = new DatabaseEntry();
00456 DatabaseEntry d_histdbt = new DatabaseEntry();
00457 DatabaseEntry k_dbt = new DatabaseEntry();
00458 DatabaseEntry k_histdbt = new DatabaseEntry();
00459
00460 account = TpcbExample.this.random_id(TpcbExample.ACCOUNT);
00461 branch = TpcbExample.this.random_id(TpcbExample.BRANCH);
00462 teller = TpcbExample.this.random_id(TpcbExample.TELLER);
00463
00464
00465
00466 byte[] hist_key = new byte[4];
00467 k_histdbt.setData(hist_key);
00468 k_histdbt.setSize(4 );
00469
00470 byte[] key_bytes = new byte[4];
00471 k_dbt.setData(key_bytes);
00472 k_dbt.setSize(4 );
00473
00474 d_dbt.setData(rec.data);
00475 d_dbt.setUserBuffer(rec.length(), true);
00476
00477 hrec.set_aid(account);
00478 hrec.set_bid(branch);
00479 hrec.set_tid(teller);
00480 hrec.set_amount(10);
00481
00482 d_histdbt.setPartial(0, 0, true);
00483
00484
00485
00486
00487
00488
00489
00490 try {
00491 t = dbenv.beginTransaction(null, null);
00492
00493 acurs = adb.openCursor(t, null);
00494 bcurs = bdb.openCursor(t, null);
00495 tcurs = tdb.openCursor(t, null);
00496 hcurs = hdb.openCursor(t, null);
00497
00498
00499 k_dbt.setRecordNumber(account);
00500 if (acurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
00501 throw new Exception("acurs get failed");
00502 rec.set_balance(rec.get_balance() + 10);
00503 acurs.putCurrent(d_dbt);
00504
00505
00506 k_dbt.setRecordNumber(branch);
00507 if (bcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
00508 throw new Exception("bcurs get failed");
00509 rec.set_balance(rec.get_balance() + 10);
00510 bcurs.putCurrent(d_dbt);
00511
00512
00513 k_dbt.setRecordNumber(teller);
00514 if (tcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS)
00515 throw new Exception("ccurs get failed");
00516 rec.set_balance(rec.get_balance() + 10);
00517 tcurs.putCurrent(d_dbt);
00518
00519
00520 d_histdbt.setPartial(0, 0, false);
00521 d_histdbt.setData(hrec.data);
00522 d_histdbt.setUserBuffer(hrec.length(), true);
00523 if (hdb.append(t, k_histdbt, d_histdbt) != OperationStatus.SUCCESS)
00524 throw new DatabaseException("put failed");
00525
00526 acurs.close();
00527 acurs = null;
00528 bcurs.close();
00529 bcurs = null;
00530 tcurs.close();
00531 tcurs = null;
00532 hcurs.close();
00533 hcurs = null;
00534
00535
00536
00537 Transaction tmptxn = t;
00538 t = null;
00539 tmptxn.commit();
00540
00541
00542 return (0);
00543 } catch (Exception e) {
00544 try {
00545 if (acurs != null)
00546 acurs.close();
00547 if (bcurs != null)
00548 bcurs.close();
00549 if (tcurs != null)
00550 tcurs.close();
00551 if (hcurs != null)
00552 hcurs.close();
00553 if (t != null)
00554 t.abort();
00555 } catch (DatabaseException dbe) {
00556
00557 }
00558
00559 if (TpcbExample.this.verbose) {
00560 System.out.println("Transaction A=" + String.valueOf(account) +
00561 " B=" + String.valueOf(branch) +
00562 " T=" + String.valueOf(teller) +
00563 " failed");
00564 System.out.println("Reason: " + e.toString());
00565 }
00566 return (-1);
00567 }
00568 }
00569 }
00570
00571 private static void usage() {
00572 System.err.println(
00573 "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" +
00574 " [-c cachesize] [-h home] [-n transactions]\n" +
00575 " [-T threads] [-S seed] [-s history] [-t tellers]");
00576 System.exit(1);
00577 }
00578
00579 private static void invarg(String str) {
00580 System.err.println("TpcbExample: invalid argument: " + str);
00581 System.exit(1);
00582 }
00583
00584 public static void errExit(Exception err, String s) {
00585 System.err.print(progname + ": ");
00586 if (s != null) {
00587 System.err.print(s + ": ");
00588 }
00589 System.err.println(err.toString());
00590 System.exit(1);
00591 }
00592
00593 public static void main(String[] argv) throws java.io.IOException {
00594 File home = new File("TESTDIR");
00595 int accounts = ACCOUNTS;
00596 int branches = BRANCHES;
00597 int tellers = TELLERS;
00598 int history = HISTORY;
00599 int threads = 1;
00600 int mpool = 0;
00601 int ntxns = 0;
00602 boolean iflag = false;
00603 boolean txn_no_sync = false;
00604 long seed = (new GregorianCalendar()).get(Calendar.SECOND);
00605
00606 for (int i = 0; i < argv.length; ++i) {
00607 if (argv[i].equals("-a")) {
00608
00609 if ((accounts = Integer.parseInt(argv[++i])) <= 0)
00610 invarg(argv[i]);
00611 } else if (argv[i].equals("-b")) {
00612
00613 if ((branches = Integer.parseInt(argv[++i])) <= 0)
00614 invarg(argv[i]);
00615 } else if (argv[i].equals("-c")) {
00616
00617 if ((mpool = Integer.parseInt(argv[++i])) <= 0)
00618 invarg(argv[i]);
00619 } else if (argv[i].equals("-f")) {
00620
00621 txn_no_sync = true;
00622 } else if (argv[i].equals("-h")) {
00623
00624 home = new File(argv[++i]);
00625 } else if (argv[i].equals("-i")) {
00626
00627 iflag = true;
00628 } else if (argv[i].equals("-n")) {
00629
00630 if ((ntxns = Integer.parseInt(argv[++i])) <= 0)
00631 invarg(argv[i]);
00632 } else if (argv[i].equals("-S")) {
00633
00634 seed = Long.parseLong(argv[++i]);
00635 if (seed <= 0)
00636 invarg(argv[i]);
00637 } else if (argv[i].equals("-s")) {
00638
00639 if ((history = Integer.parseInt(argv[++i])) <= 0)
00640 invarg(argv[i]);
00641 } else if (argv[i].equals("-T")) {
00642
00643 if ((threads = Integer.parseInt(argv[++i])) <= 0)
00644 invarg(argv[i]);
00645 } else if (argv[i].equals("-t")) {
00646
00647 if ((tellers = Integer.parseInt(argv[++i])) <= 0)
00648 invarg(argv[i]);
00649 } else if (argv[i].equals("-v")) {
00650
00651 verbose = true;
00652 } else {
00653 usage();
00654 }
00655 }
00656
00657 rand.setSeed((int)seed);
00658
00659
00660
00661
00662 TpcbExample app = null;
00663 try {
00664 app = new TpcbExample(home, accounts, branches, tellers, history,
00665 mpool, txn_no_sync);
00666 } catch (Exception e1) {
00667 errExit(e1, "initializing environment failed");
00668 }
00669
00670 if (verbose)
00671 System.out.println((long)accounts + " Accounts, " +
00672 String.valueOf(branches) + " Branches, " +
00673 String.valueOf(tellers) + " Tellers, " +
00674 String.valueOf(history) + " History");
00675
00676 if (iflag) {
00677 if (ntxns != 0)
00678 usage();
00679 app.populate();
00680 } else {
00681 if (ntxns == 0)
00682 usage();
00683 app.run(ntxns, threads);
00684 }
00685
00686
00687
00688 try {
00689 app.close();
00690 } catch (DatabaseException dbe2) {
00691 errExit(dbe2, "appexit failed");
00692 }
00693
00694 System.exit(0);
00695 }
00696 };
00697
00698
00699
00700
00701
00702
00703
00704
00705 class Defrec {
00706 public Defrec() {
00707 data = new byte[TpcbExample.RECLEN];
00708 }
00709
00710 public int length() {
00711 return TpcbExample.RECLEN;
00712 }
00713
00714 public long get_id() {
00715 return TpcbExample.get_int_in_array(data, 0);
00716 }
00717
00718 public void set_id(long value) {
00719 TpcbExample.set_int_in_array(data, 0, value);
00720 }
00721
00722 public long get_balance() {
00723 return TpcbExample.get_int_in_array(data, 4);
00724 }
00725
00726 public void set_balance(long value) {
00727 TpcbExample.set_int_in_array(data, 4, value);
00728 }
00729
00730 static {
00731 Defrec d = new Defrec();
00732 d.set_balance(500000);
00733 }
00734
00735 public byte[] data;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747 class Histrec {
00748 public Histrec() {
00749 data = new byte[TpcbExample.RECLEN];
00750 }
00751
00752 public int length() {
00753 return TpcbExample.RECLEN;
00754 }
00755
00756 public long get_aid() {
00757 return TpcbExample.get_int_in_array(data, 0);
00758 }
00759
00760 public void set_aid(long value) {
00761 TpcbExample.set_int_in_array(data, 0, value);
00762 }
00763
00764 public long get_bid() {
00765 return TpcbExample.get_int_in_array(data, 4);
00766 }
00767
00768 public void set_bid(long value) {
00769 TpcbExample.set_int_in_array(data, 4, value);
00770 }
00771
00772 public long get_tid() {
00773 return TpcbExample.get_int_in_array(data, 8);
00774 }
00775
00776 public void set_tid(long value) {
00777 TpcbExample.set_int_in_array(data, 8, value);
00778 }
00779
00780 public long get_amount() {
00781 return TpcbExample.get_int_in_array(data, 12);
00782 }
00783
00784 public void set_amount(long value) {
00785 TpcbExample.set_int_in_array(data, 12, value);
00786 }
00787
00788 public byte[] data;
00789 }