diff options
author | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:40:46 +0900 |
---|---|---|
committer | Kim Kibum <kb0929.kim@samsung.com> | 2012-05-21 17:40:46 +0900 |
commit | 2e082c838d2ca750f5daac6dcdabecc22dfd4e46 (patch) | |
tree | 01c1dd87d4cc0b62a655c0d768ff695d2d244728 /examples_java/src/db/TpcbExample.java | |
parent | a86e3ca152fb414b376e64c449c201d762e414dd (diff) | |
download | db4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.tar.gz db4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.tar.bz2 db4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.zip |
Upload Tizen:Base source
Diffstat (limited to 'examples_java/src/db/TpcbExample.java')
-rw-r--r-- | examples_java/src/db/TpcbExample.java | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/examples_java/src/db/TpcbExample.java b/examples_java/src/db/TpcbExample.java new file mode 100644 index 0000000..883dca4 --- /dev/null +++ b/examples_java/src/db/TpcbExample.java @@ -0,0 +1,789 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1997-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package db; + +import com.sleepycat.db.*; + +import java.io.File; +import java.io.FileNotFoundException; +import java.math.BigDecimal; +import java.util.Calendar; +import java.util.Date; +import java.util.Random; +import java.util.GregorianCalendar; + +// +// This program implements a basic TPC/B driver program. To create the +// TPC/B database, run with the -i (init) flag. The number of records +// with which to populate the account, history, branch, and teller tables +// is specified by the a, s, b, and t flags respectively. To run a TPC/B +// test, use the n flag to indicate a number of transactions to run in +// each thread and -T to specify the number of threads. +// +class TpcbExample { + public static final int TELLERS_PER_BRANCH = 10; + public static final int ACCOUNTS_PER_TELLER = 10000; + public static final int HISTORY_PER_BRANCH = 2592000; + + // + // The default configuration that adheres to TPCB scaling rules requires + // nearly 3 GB of space. To avoid requiring that much space for testing, + // we set the parameters much lower. If you want to run a valid 10 TPS + // configuration, uncomment the VALID_SCALING configuration + // + + // VALID_SCALING configuration + /* + public static final int ACCOUNTS = 1000000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 25920000; + */ + + // TINY configuration + /* + public static final int ACCOUNTS = 1000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 10000; + */ + + // Default configuration + public static final int ACCOUNTS = 100000; + public static final int BRANCHES = 10; + public static final int TELLERS = 100; + public static final int HISTORY = 259200; + + public static final int HISTORY_LEN = 100; + public static final int RECLEN = 100; + public static final int BEGID = 1000000; + + // used by random_id() + public static final int ACCOUNT = 0; + public static final int BRANCH = 1; + public static final int TELLER = 2; + + public static boolean verbose = false; + public static final String progname = "TpcbExample"; // Program name. + + Environment dbenv; + int accounts, branches, tellers, history; + + public TpcbExample(File home, + int accounts, int branches, int tellers, int history, + int cachesize, boolean noSync) + throws DatabaseException, FileNotFoundException { + + this.accounts = accounts; + this.branches = branches; + this.tellers = tellers; + this.history = history; + + EnvironmentConfig config = new EnvironmentConfig(); + config.setErrorStream(System.err); + config.setErrorPrefix(progname); + config.setLockDetectMode(LockDetectMode.DEFAULT); + config.setCacheSize(cachesize == 0 ? 4 * 1024 * 1024 : cachesize); + config.setTxnNoSync(noSync); + config.setLockDetectMode(LockDetectMode.DEFAULT); + config.setAllowCreate(true); + + config.setInitializeCache(true); + config.setTransactional(true); + config.setInitializeLocking(true); + config.setInitializeLogging(true); + + dbenv = new Environment(home, config); + } + + public void close() + throws DatabaseException { + + try { + if (dbenv != null) + dbenv.close(); + } finally { + dbenv = null; + } + } + + // + // Initialize the database to the number of accounts, branches, + // history records, and tellers given to the constructor. + // + public void populate() { + Database dbp = null; + + int err; + int balance, idnum; + int end_anum, end_bnum, end_tnum; + int start_anum, start_bnum, start_tnum; + int h_nelem; + + idnum = BEGID; + balance = 500000; + + h_nelem = accounts; + + try { + DatabaseConfig config = new DatabaseConfig(); + config.setType(DatabaseType.HASH); + config.setHashNumElements(h_nelem); + config.setAllowCreate(true); + dbp = dbenv.openDatabase(null, "account", null, config); + } catch (Exception e1) { + // can be DatabaseException or FileNotFoundException + errExit(e1, "Open of account file failed"); + } + + start_anum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "account"); + idnum += h_nelem; + end_anum = idnum - 1; + try { + dbp.close(); + } catch (DatabaseException e2) { + errExit(e2, "Account file close failed"); + } + + if (verbose) + System.out.println("Populated accounts: " + + String.valueOf(start_anum) + " - " + + String.valueOf(end_anum)); + + // + // Since the number of branches is very small, we want to use very + // small pages and only 1 key per page. This is the poor-man's way + // of getting key locking instead of page locking. + // + h_nelem = (int)branches; + + try { + DatabaseConfig config = new DatabaseConfig(); + config.setType(DatabaseType.HASH); + config.setHashNumElements(h_nelem); + config.setHashFillFactor(1); + config.setPageSize(512); + config.setAllowCreate(true); + dbp = dbenv.openDatabase(null, "branch", null, config); + } catch (Exception e3) { + // can be DatabaseException or FileNotFoundException + errExit(e3, "Branch file create failed"); + } + + start_bnum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "branch"); + idnum += h_nelem; + end_bnum = idnum - 1; + + try { + dbp.close(); + } catch (DatabaseException dbe4) { + errExit(dbe4, "Close of branch file failed"); + } + + if (verbose) + System.out.println("Populated branches: " + + String.valueOf(start_bnum) + " - " + + String.valueOf(end_bnum)); + + // + // In the case of tellers, we also want small pages, but we'll let + // the fill factor dynamically adjust itself. + // + h_nelem = (int)tellers; + + try { + DatabaseConfig config = new DatabaseConfig(); + config.setType(DatabaseType.HASH); + config.setHashNumElements(h_nelem); + config.setHashFillFactor(0); + config.setPageSize(512); + config.setAllowCreate(true); + dbp = dbenv.openDatabase(null, "teller", null, config); + } catch (Exception e5) { + // can be DatabaseException or FileNotFoundException + errExit(e5, "Teller file create failed"); + } + + start_tnum = idnum; + populateTable(dbp, idnum, balance, h_nelem, "teller"); + idnum += h_nelem; + end_tnum = idnum - 1; + + try { + dbp.close(); + } catch (DatabaseException e6) { + errExit(e6, "Close of teller file failed"); + } + + if (verbose) + System.out.println("Populated tellers: " + + String.valueOf(start_tnum) + " - " + + String.valueOf(end_tnum)); + + try { + DatabaseConfig config = new DatabaseConfig(); + config.setType(DatabaseType.RECNO); + config.setRecordLength(HISTORY_LEN); + config.setAllowCreate(true); + dbp = dbenv.openDatabase(null, "history", null, config); + } catch (Exception e7) { + // can be DatabaseException or FileNotFoundException + errExit(e7, "Create of history file failed"); + } + + populateHistory(dbp); + + try { + dbp.close(); + } catch (DatabaseException e8) { + errExit(e8, "Close of history file failed"); + } + } + + public void populateTable(Database dbp, + int start_id, int balance, int nrecs, String msg) { + Defrec drec = new Defrec(); + + DatabaseEntry kdbt = new DatabaseEntry(drec.data); + kdbt.setSize(4); // sizeof(int) + DatabaseEntry ddbt = new DatabaseEntry(drec.data); + ddbt.setSize(drec.data.length); // uses whole array + + try { + for (int i = 0; i < nrecs; i++) { + kdbt.setRecordNumber(start_id + (int)i); + drec.set_balance(balance); + dbp.putNoOverwrite(null, kdbt, ddbt); + } + } catch (DatabaseException dbe) { + System.err.println("Failure initializing " + msg + " file: " + + dbe.toString()); + System.exit(1); + } + } + + public void populateHistory(Database dbp) { + Histrec hrec = new Histrec(); + hrec.set_amount(10); + + byte[] arr = new byte[4]; // sizeof(int) + int i; + DatabaseEntry kdbt = new DatabaseEntry(arr); + kdbt.setSize(arr.length); + DatabaseEntry ddbt = new DatabaseEntry(hrec.data); + ddbt.setSize(hrec.data.length); + + try { + for (i = 1; i <= history; i++) { + kdbt.setRecordNumber(i); + + hrec.set_aid(random_id(ACCOUNT)); + hrec.set_bid(random_id(BRANCH)); + hrec.set_tid(random_id(TELLER)); + + dbp.append(null, kdbt, ddbt); + } + } catch (DatabaseException dbe) { + errExit(dbe, "Failure initializing history file"); + } + } + + static Random rand = new Random(); + public static int random_int(int lo, int hi) { + int t = rand.nextInt(); + if (t < 0) + t = -t; + int ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) * + (hi - lo + 1)); + ret += lo; + return (ret); + } + + public int random_id(int type) { + int min, max, num; + + max = min = BEGID; + num = accounts; + switch(type) { + case TELLER: + min += branches; + num = tellers; + // fallthrough + case BRANCH: + if (type == BRANCH) + num = branches; + min += accounts; + // fallthrough + case ACCOUNT: + max = min + num - 1; + } + return (random_int(min, max)); + } + + // The byte order is our choice. + // + static long get_int_in_array(byte[] array, int offset) { + return + ((0xff & array[offset + 0]) << 0) | + ((0xff & array[offset + 1]) << 8) | + ((0xff & array[offset + 2]) << 16) | + ((0xff & array[offset + 3]) << 24); + } + + // Note: Value needs to be long to avoid sign extension + static void set_int_in_array(byte[] array, int offset, long value) { + array[offset + 0] = (byte)((value >> 0) & 0xff); + array[offset + 1] = (byte)((value >> 8) & 0xff); + array[offset + 2] = (byte)((value >> 16) & 0xff); + array[offset + 3] = (byte)((value >> 24) & 0xff); + } + + // round 'd' to 'scale' digits, and return result as string + static String showRounded(double d, int scale) { + return new BigDecimal(d). + setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString(); + } + + public void run(int ntxns, int threads) { + double gtps; + int txns, failed; + long curtime, starttime; + TxnThread[] txnList = new TxnThread[threads]; + for (int i = 0; i < threads; i++) + txnList[i] = new TxnThread("Thread " + String.valueOf(i), ntxns); + + starttime = (new Date()).getTime(); + for (int i = 0; i < threads; i++) + txnList[i].start(); + for (int i = 0; i < threads; i++) + try { + txnList[i].join(); + } catch (Exception e1) { + errExit(e1, "join failed"); + } + + curtime = (new Date()).getTime(); + txns = failed = 0; + for (int i = 0; i < threads; i++) { + txns += txnList[i].txns; + failed += txnList[i].failed; + } + gtps = (double)(txns - failed) / + ((curtime - starttime) / 1000.0); + System.out.print("\nTotal: " + + String.valueOf(txns) + " txns " + + String.valueOf(failed) + " failed "); + System.out.println(showRounded(gtps, 2) + " TPS"); + } + + class TxnThread extends Thread { + private int ntxns; /* Number of txns we were asked to run. */ + public int txns, failed; /* Number that succeeded / failed. */ + private Database adb, bdb, hdb, tdb; + + public TxnThread(String name, int ntxns) { + super(name); + this.ntxns = ntxns; + } + + public void run() { + double gtps, itps; + int n, ret; + long start_time, end_time; + + // + // Open the database files. + // + int err; + try { + DatabaseConfig config = new DatabaseConfig(); + config.setTransactional(true); + adb = dbenv.openDatabase(null, "account", null, config); + bdb = dbenv.openDatabase(null, "branch", null, config); + tdb = dbenv.openDatabase(null, "teller", null, config); + hdb = dbenv.openDatabase(null, "history", null, config); + } catch (DatabaseException dbe) { + TpcbExample.errExit(dbe, "Open of db files failed"); + } catch (FileNotFoundException fnfe) { + TpcbExample.errExit(fnfe, "Open of db files failed, missing file"); + } + + start_time = (new Date()).getTime(); + for (txns = n = ntxns, failed = 0; n-- > 0;) + if ((ret = txn()) != 0) + failed++; + end_time = (new Date()).getTime(); + if (end_time == start_time) + end_time++; + + System.out.println(getName() + ": " + (long)txns + " txns: " + + failed + " failed, " + TpcbExample.showRounded( + (txns - failed) / (double)(end_time - start_time), 2) + " TPS"); + + try { + adb.close(); + bdb.close(); + tdb.close(); + hdb.close(); + } catch (DatabaseException dbe2) { + TpcbExample.errExit(dbe2, "Close of db files failed"); + } + } + + // + // XXX Figure out the appropriate way to pick out IDs. + // + int txn() { + Cursor acurs = null; + Cursor bcurs = null; + Cursor hcurs = null; + Cursor tcurs = null; + Transaction t = null; + + Defrec rec = new Defrec(); + Histrec hrec = new Histrec(); + int account, branch, teller; + + DatabaseEntry d_dbt = new DatabaseEntry(); + DatabaseEntry d_histdbt = new DatabaseEntry(); + DatabaseEntry k_dbt = new DatabaseEntry(); + DatabaseEntry k_histdbt = new DatabaseEntry(); + + account = TpcbExample.this.random_id(TpcbExample.ACCOUNT); + branch = TpcbExample.this.random_id(TpcbExample.BRANCH); + teller = TpcbExample.this.random_id(TpcbExample.TELLER); + + // The history key will not actually be retrieved, + // but it does need to be set to something. + byte[] hist_key = new byte[4]; + k_histdbt.setData(hist_key); + k_histdbt.setSize(4 /* == sizeof(int)*/); + + byte[] key_bytes = new byte[4]; + k_dbt.setData(key_bytes); + k_dbt.setSize(4 /* == sizeof(int)*/); + + d_dbt.setData(rec.data); + d_dbt.setUserBuffer(rec.length(), true); + + hrec.set_aid(account); + hrec.set_bid(branch); + hrec.set_tid(teller); + hrec.set_amount(10); + // Request 0 bytes since we're just positioning. + d_histdbt.setPartial(0, 0, true); + + // START PER-TRANSACTION TIMING. + // + // Technically, TPCB requires a limit on response time, you only + // get to count transactions that complete within 2 seconds. + // That's not an issue for this sample application -- regardless, + // here's where the transaction begins. + try { + t = dbenv.beginTransaction(null, null); + + acurs = adb.openCursor(t, null); + bcurs = bdb.openCursor(t, null); + tcurs = tdb.openCursor(t, null); + hcurs = hdb.openCursor(t, null); + + // Account record + k_dbt.setRecordNumber(account); + if (acurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) + throw new Exception("acurs get failed"); + rec.set_balance(rec.get_balance() + 10); + acurs.putCurrent(d_dbt); + + // Branch record + k_dbt.setRecordNumber(branch); + if (bcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) + throw new Exception("bcurs get failed"); + rec.set_balance(rec.get_balance() + 10); + bcurs.putCurrent(d_dbt); + + // Teller record + k_dbt.setRecordNumber(teller); + if (tcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) + throw new Exception("ccurs get failed"); + rec.set_balance(rec.get_balance() + 10); + tcurs.putCurrent(d_dbt); + + // History record + d_histdbt.setPartial(0, 0, false); + d_histdbt.setData(hrec.data); + d_histdbt.setUserBuffer(hrec.length(), true); + if (hdb.append(t, k_histdbt, d_histdbt) != OperationStatus.SUCCESS) + throw new DatabaseException("put failed"); + + acurs.close(); + acurs = null; + bcurs.close(); + bcurs = null; + tcurs.close(); + tcurs = null; + hcurs.close(); + hcurs = null; + + // null out t in advance; if the commit fails, + // we don't want to abort it in the catch clause. + Transaction tmptxn = t; + t = null; + tmptxn.commit(); + + // END TIMING + return (0); + } catch (Exception e) { + try { + if (acurs != null) + acurs.close(); + if (bcurs != null) + bcurs.close(); + if (tcurs != null) + tcurs.close(); + if (hcurs != null) + hcurs.close(); + if (t != null) + t.abort(); + } catch (DatabaseException dbe) { + // not much we can do here. + } + + if (TpcbExample.this.verbose) { + System.out.println("Transaction A=" + String.valueOf(account) + + " B=" + String.valueOf(branch) + + " T=" + String.valueOf(teller) + + " failed"); + System.out.println("Reason: " + e.toString()); + } + return (-1); + } + } + } + + private static void usage() { + System.err.println( + "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" + + " [-c cachesize] [-h home] [-n transactions]\n" + + " [-T threads] [-S seed] [-s history] [-t tellers]"); + System.exit(1); + } + + private static void invarg(String str) { + System.err.println("TpcbExample: invalid argument: " + str); + System.exit(1); + } + + public static void errExit(Exception err, String s) { + System.err.print(progname + ": "); + if (s != null) { + System.err.print(s + ": "); + } + System.err.println(err.toString()); + System.exit(1); + } + + public static void main(String[] argv) throws java.io.IOException { + File home = new File("TESTDIR"); + int accounts = ACCOUNTS; + int branches = BRANCHES; + int tellers = TELLERS; + int history = HISTORY; + int threads = 1; + int mpool = 0; + int ntxns = 0; + boolean iflag = false; + boolean txn_no_sync = false; + long seed = (new GregorianCalendar()).get(Calendar.SECOND); + + for (int i = 0; i < argv.length; ++i) { + if (argv[i].equals("-a")) { + // Number of account records + if ((accounts = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-b")) { + // Number of branch records + if ((branches = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-c")) { + // Cachesize in bytes + if ((mpool = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-f")) { + // Fast mode: no txn sync. + txn_no_sync = true; + } else if (argv[i].equals("-h")) { + // DB home. + home = new File(argv[++i]); + } else if (argv[i].equals("-i")) { + // Initialize the test. + iflag = true; + } else if (argv[i].equals("-n")) { + // Number of transactions + if ((ntxns = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-S")) { + // Random number seed. + seed = Long.parseLong(argv[++i]); + if (seed <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-s")) { + // Number of history records + if ((history = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-T")) { + // Number of threads + if ((threads = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-t")) { + // Number of teller records + if ((tellers = Integer.parseInt(argv[++i])) <= 0) + invarg(argv[i]); + } else if (argv[i].equals("-v")) { + // Verbose option. + verbose = true; + } else { + usage(); + } + } + + rand.setSeed((int)seed); + + // Initialize the database environment. + // Must be done in within a try block. + // + TpcbExample app = null; + try { + app = new TpcbExample(home, accounts, branches, tellers, history, + mpool, iflag || txn_no_sync); + } catch (Exception e1) { + errExit(e1, "initializing environment failed"); + } + + if (verbose) + System.out.println((long)accounts + " Accounts, " + + String.valueOf(branches) + " Branches, " + + String.valueOf(tellers) + " Tellers, " + + String.valueOf(history) + " History"); + + if (iflag) { + if (ntxns != 0) + usage(); + app.populate(); + } else { + if (ntxns == 0) + usage(); + app.run(ntxns, threads); + } + + // Shut down the application. + + try { + app.close(); + } catch (DatabaseException dbe2) { + errExit(dbe2, "appexit failed"); + } + + System.exit(0); + } +}; + +// Simulate the following C struct: +// struct Defrec { +// u_int32_t id; +// u_int32_t balance; +// u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)]; +// }; + +class Defrec { + public Defrec() { + data = new byte[TpcbExample.RECLEN]; + } + + public int length() { + return TpcbExample.RECLEN; + } + + public long get_id() { + return TpcbExample.get_int_in_array(data, 0); + } + + public void set_id(long value) { + TpcbExample.set_int_in_array(data, 0, value); + } + + public long get_balance() { + return TpcbExample.get_int_in_array(data, 4); + } + + public void set_balance(long value) { + TpcbExample.set_int_in_array(data, 4, value); + } + + static { + Defrec d = new Defrec(); + d.set_balance(500000); + } + + public byte[] data; +} + +// Simulate the following C struct: +// struct Histrec { +// u_int32_t aid; +// u_int32_t bid; +// u_int32_t tid; +// u_int32_t amount; +// u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; +// }; + +class Histrec { + public Histrec() { + data = new byte[TpcbExample.RECLEN]; + } + + public int length() { + return TpcbExample.RECLEN; + } + + public long get_aid() { + return TpcbExample.get_int_in_array(data, 0); + } + + public void set_aid(long value) { + TpcbExample.set_int_in_array(data, 0, value); + } + + public long get_bid() { + return TpcbExample.get_int_in_array(data, 4); + } + + public void set_bid(long value) { + TpcbExample.set_int_in_array(data, 4, value); + } + + public long get_tid() { + return TpcbExample.get_int_in_array(data, 8); + } + + public void set_tid(long value) { + TpcbExample.set_int_in_array(data, 8, value); + } + + public long get_amount() { + return TpcbExample.get_int_in_array(data, 12); + } + + public void set_amount(long value) { + TpcbExample.set_int_in_array(data, 12, value); + } + + public byte[] data; +} |