1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1997,2008 Oracle. All rights reserved. 5 * 6 * $Id: TpcbExample.java,v 12.11 2008/01/08 20:58:32 bostic Exp $ 7 */ 8 9package db; 10 11import com.sleepycat.db.*; 12 13import java.io.File; 14import java.io.FileNotFoundException; 15import java.math.BigDecimal; 16import java.util.Calendar; 17import java.util.Date; 18import java.util.Random; 19import java.util.GregorianCalendar; 20 21// 22// This program implements a basic TPC/B driver program. To create the 23// TPC/B database, run with the -i (init) flag. The number of records 24// with which to populate the account, history, branch, and teller tables 25// is specified by the a, s, b, and t flags respectively. To run a TPC/B 26// test, use the n flag to indicate a number of transactions to run in 27// each thread and -T to specify the number of threads. 28// 29class TpcbExample { 30 public static final int TELLERS_PER_BRANCH = 10; 31 public static final int ACCOUNTS_PER_TELLER = 10000; 32 public static final int HISTORY_PER_BRANCH = 2592000; 33 34 // 35 // The default configuration that adheres to TPCB scaling rules requires 36 // nearly 3 GB of space. To avoid requiring that much space for testing, 37 // we set the parameters much lower. If you want to run a valid 10 TPS 38 // configuration, uncomment the VALID_SCALING configuration 39 // 40 41 // VALID_SCALING configuration 42 /* 43 public static final int ACCOUNTS = 1000000; 44 public static final int BRANCHES = 10; 45 public static final int TELLERS = 100; 46 public static final int HISTORY = 25920000; 47 */ 48 49 // TINY configuration 50 /* 51 public static final int ACCOUNTS = 1000; 52 public static final int BRANCHES = 10; 53 public static final int TELLERS = 100; 54 public static final int HISTORY = 10000; 55 */ 56 57 // Default configuration 58 public static final int ACCOUNTS = 100000; 59 public static final int BRANCHES = 10; 60 public static final int TELLERS = 100; 61 public static final int HISTORY = 259200; 62 63 public static final int HISTORY_LEN = 100; 64 public static final int RECLEN = 100; 65 public static final int BEGID = 1000000; 66 67 // used by random_id() 68 public static final int ACCOUNT = 0; 69 public static final int BRANCH = 1; 70 public static final int TELLER = 2; 71 72 public static boolean verbose = false; 73 public static final String progname = "TpcbExample"; // Program name. 74 75 Environment dbenv; 76 int accounts, branches, tellers, history; 77 78 public TpcbExample(File home, 79 int accounts, int branches, int tellers, int history, 80 int cachesize, boolean noSync) 81 throws DatabaseException, FileNotFoundException { 82 83 this.accounts = accounts; 84 this.branches = branches; 85 this.tellers = tellers; 86 this.history = history; 87 88 EnvironmentConfig config = new EnvironmentConfig(); 89 config.setErrorStream(System.err); 90 config.setErrorPrefix(progname); 91 config.setCacheSize(cachesize == 0 ? 4 * 1024 * 1024 : cachesize); 92 config.setTxnNoSync(noSync); 93 config.setLockDetectMode(LockDetectMode.DEFAULT); 94 config.setAllowCreate(true); 95 96 config.setInitializeCache(true); 97 config.setTransactional(true); 98 config.setInitializeLocking(true); 99 config.setInitializeLogging(true); 100 101 dbenv = new Environment(home, config); 102 } 103 104 public void close() 105 throws DatabaseException { 106 107 try { 108 if (dbenv != null) 109 dbenv.close(); 110 } finally { 111 dbenv = null; 112 } 113 } 114 115 // 116 // Initialize the database to the number of accounts, branches, 117 // history records, and tellers given to the constructor. 118 // 119 public void populate() { 120 Database dbp = null; 121 122 int err; 123 int balance, idnum; 124 int end_anum, end_bnum, end_tnum; 125 int start_anum, start_bnum, start_tnum; 126 int h_nelem; 127 128 idnum = BEGID; 129 balance = 500000; 130 131 h_nelem = accounts; 132 133 try { 134 DatabaseConfig config = new DatabaseConfig(); 135 config.setType(DatabaseType.HASH); 136 config.setHashNumElements(h_nelem); 137 config.setAllowCreate(true); 138 dbp = dbenv.openDatabase(null, "account", null, config); 139 } catch (Exception e1) { 140 // can be DatabaseException or FileNotFoundException 141 errExit(e1, "Open of account file failed"); 142 } 143 144 start_anum = idnum; 145 populateTable(dbp, idnum, balance, h_nelem, "account"); 146 idnum += h_nelem; 147 end_anum = idnum - 1; 148 try { 149 dbp.close(); 150 } catch (DatabaseException e2) { 151 errExit(e2, "Account file close failed"); 152 } 153 154 if (verbose) 155 System.out.println("Populated accounts: " + 156 String.valueOf(start_anum) + " - " + 157 String.valueOf(end_anum)); 158 159 // 160 // Since the number of branches is very small, we want to use very 161 // small pages and only 1 key per page. This is the poor-man's way 162 // of getting key locking instead of page locking. 163 // 164 h_nelem = (int)branches; 165 166 try { 167 DatabaseConfig config = new DatabaseConfig(); 168 config.setType(DatabaseType.HASH); 169 config.setHashNumElements(h_nelem); 170 config.setHashFillFactor(1); 171 config.setPageSize(512); 172 config.setAllowCreate(true); 173 dbp = dbenv.openDatabase(null, "branch", null, config); 174 } catch (Exception e3) { 175 // can be DatabaseException or FileNotFoundException 176 errExit(e3, "Branch file create failed"); 177 } 178 179 start_bnum = idnum; 180 populateTable(dbp, idnum, balance, h_nelem, "branch"); 181 idnum += h_nelem; 182 end_bnum = idnum - 1; 183 184 try { 185 dbp.close(); 186 } catch (DatabaseException dbe4) { 187 errExit(dbe4, "Close of branch file failed"); 188 } 189 190 if (verbose) 191 System.out.println("Populated branches: " + 192 String.valueOf(start_bnum) + " - " + 193 String.valueOf(end_bnum)); 194 195 // 196 // In the case of tellers, we also want small pages, but we'll let 197 // the fill factor dynamically adjust itself. 198 // 199 h_nelem = (int)tellers; 200 201 try { 202 DatabaseConfig config = new DatabaseConfig(); 203 config.setType(DatabaseType.HASH); 204 config.setHashNumElements(h_nelem); 205 config.setHashFillFactor(0); 206 config.setPageSize(512); 207 config.setAllowCreate(true); 208 dbp = dbenv.openDatabase(null, "teller", null, config); 209 } catch (Exception e5) { 210 // can be DatabaseException or FileNotFoundException 211 errExit(e5, "Teller file create failed"); 212 } 213 214 start_tnum = idnum; 215 populateTable(dbp, idnum, balance, h_nelem, "teller"); 216 idnum += h_nelem; 217 end_tnum = idnum - 1; 218 219 try { 220 dbp.close(); 221 } catch (DatabaseException e6) { 222 errExit(e6, "Close of teller file failed"); 223 } 224 225 if (verbose) 226 System.out.println("Populated tellers: " + 227 String.valueOf(start_tnum) + " - " + 228 String.valueOf(end_tnum)); 229 230 try { 231 DatabaseConfig config = new DatabaseConfig(); 232 config.setType(DatabaseType.RECNO); 233 config.setRecordLength(HISTORY_LEN); 234 config.setAllowCreate(true); 235 dbp = dbenv.openDatabase(null, "history", null, config); 236 } catch (Exception e7) { 237 // can be DatabaseException or FileNotFoundException 238 errExit(e7, "Create of history file failed"); 239 } 240 241 populateHistory(dbp); 242 243 try { 244 dbp.close(); 245 } catch (DatabaseException e8) { 246 errExit(e8, "Close of history file failed"); 247 } 248 } 249 250 public void populateTable(Database dbp, 251 int start_id, int balance, int nrecs, String msg) { 252 Defrec drec = new Defrec(); 253 254 DatabaseEntry kdbt = new DatabaseEntry(drec.data); 255 kdbt.setSize(4); // sizeof(int) 256 DatabaseEntry ddbt = new DatabaseEntry(drec.data); 257 ddbt.setSize(drec.data.length); // uses whole array 258 259 try { 260 for (int i = 0; i < nrecs; i++) { 261 kdbt.setRecordNumber(start_id + (int)i); 262 drec.set_balance(balance); 263 dbp.putNoOverwrite(null, kdbt, ddbt); 264 } 265 } catch (DatabaseException dbe) { 266 System.err.println("Failure initializing " + msg + " file: " + 267 dbe.toString()); 268 System.exit(1); 269 } 270 } 271 272 public void populateHistory(Database dbp) { 273 Histrec hrec = new Histrec(); 274 hrec.set_amount(10); 275 276 byte[] arr = new byte[4]; // sizeof(int) 277 int i; 278 DatabaseEntry kdbt = new DatabaseEntry(arr); 279 kdbt.setSize(arr.length); 280 DatabaseEntry ddbt = new DatabaseEntry(hrec.data); 281 ddbt.setSize(hrec.data.length); 282 283 try { 284 for (i = 1; i <= history; i++) { 285 kdbt.setRecordNumber(i); 286 287 hrec.set_aid(random_id(ACCOUNT)); 288 hrec.set_bid(random_id(BRANCH)); 289 hrec.set_tid(random_id(TELLER)); 290 291 dbp.append(null, kdbt, ddbt); 292 } 293 } catch (DatabaseException dbe) { 294 errExit(dbe, "Failure initializing history file"); 295 } 296 } 297 298 static Random rand = new Random(); 299 public static int random_int(int lo, int hi) { 300 int t = rand.nextInt(); 301 if (t < 0) 302 t = -t; 303 int ret = (int)(((double)t / ((double)(Integer.MAX_VALUE) + 1)) * 304 (hi - lo + 1)); 305 ret += lo; 306 return (ret); 307 } 308 309 public int random_id(int type) { 310 int min, max, num; 311 312 max = min = BEGID; 313 num = accounts; 314 switch(type) { 315 case TELLER: 316 min += branches; 317 num = tellers; 318 // fallthrough 319 case BRANCH: 320 if (type == BRANCH) 321 num = branches; 322 min += accounts; 323 // fallthrough 324 case ACCOUNT: 325 max = min + num - 1; 326 } 327 return (random_int(min, max)); 328 } 329 330 // The byte order is our choice. 331 // 332 static long get_int_in_array(byte[] array, int offset) { 333 return 334 ((0xff & array[offset + 0]) << 0) | 335 ((0xff & array[offset + 1]) << 8) | 336 ((0xff & array[offset + 2]) << 16) | 337 ((0xff & array[offset + 3]) << 24); 338 } 339 340 // Note: Value needs to be long to avoid sign extension 341 static void set_int_in_array(byte[] array, int offset, long value) { 342 array[offset + 0] = (byte)((value >> 0) & 0xff); 343 array[offset + 1] = (byte)((value >> 8) & 0xff); 344 array[offset + 2] = (byte)((value >> 16) & 0xff); 345 array[offset + 3] = (byte)((value >> 24) & 0xff); 346 } 347 348 // round 'd' to 'scale' digits, and return result as string 349 static String showRounded(double d, int scale) { 350 return new BigDecimal(d). 351 setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString(); 352 } 353 354 public void run(int ntxns, int threads) { 355 double gtps; 356 int txns, failed; 357 long curtime, starttime; 358 TxnThread[] txnList = new TxnThread[threads]; 359 for (int i = 0; i < threads; i++) 360 txnList[i] = new TxnThread("Thread " + String.valueOf(i), ntxns); 361 362 starttime = (new Date()).getTime(); 363 for (int i = 0; i < threads; i++) 364 txnList[i].start(); 365 for (int i = 0; i < threads; i++) 366 try { 367 txnList[i].join(); 368 } catch (Exception e1) { 369 errExit(e1, "join failed"); 370 } 371 372 curtime = (new Date()).getTime(); 373 txns = failed = 0; 374 for (int i = 0; i < threads; i++) { 375 txns += txnList[i].txns; 376 failed += txnList[i].failed; 377 } 378 gtps = (double)(txns - failed) / 379 ((curtime - starttime) / 1000.0); 380 System.out.print("\nTotal: " + 381 String.valueOf(txns) + " txns " + 382 String.valueOf(failed) + " failed "); 383 System.out.println(showRounded(gtps, 2) + " TPS"); 384 } 385 386 class TxnThread extends Thread { 387 private int ntxns; /* Number of txns we were asked to run. */ 388 public int txns, failed; /* Number that succeeded / failed. */ 389 private Database adb, bdb, hdb, tdb; 390 391 public TxnThread(String name, int ntxns) { 392 super(name); 393 this.ntxns = ntxns; 394 } 395 396 public void run() { 397 double gtps, itps; 398 int n, ret; 399 long start_time, end_time; 400 401 // 402 // Open the database files. 403 // 404 int err; 405 try { 406 DatabaseConfig config = new DatabaseConfig(); 407 config.setTransactional(true); 408 adb = dbenv.openDatabase(null, "account", null, config); 409 bdb = dbenv.openDatabase(null, "branch", null, config); 410 tdb = dbenv.openDatabase(null, "teller", null, config); 411 hdb = dbenv.openDatabase(null, "history", null, config); 412 } catch (DatabaseException dbe) { 413 TpcbExample.errExit(dbe, "Open of db files failed"); 414 } catch (FileNotFoundException fnfe) { 415 TpcbExample.errExit(fnfe, "Open of db files failed, missing file"); 416 } 417 418 start_time = (new Date()).getTime(); 419 for (txns = n = ntxns, failed = 0; n-- > 0;) 420 if ((ret = txn()) != 0) 421 failed++; 422 end_time = (new Date()).getTime(); 423 if (end_time == start_time) 424 end_time++; 425 426 System.out.println(getName() + ": " + (long)txns + " txns: " + 427 failed + " failed, " + TpcbExample.showRounded( 428 (txns - failed) / (double)(end_time - start_time), 2) + " TPS"); 429 430 try { 431 adb.close(); 432 bdb.close(); 433 tdb.close(); 434 hdb.close(); 435 } catch (DatabaseException dbe2) { 436 TpcbExample.errExit(dbe2, "Close of db files failed"); 437 } 438 } 439 440 // 441 // XXX Figure out the appropriate way to pick out IDs. 442 // 443 int txn() { 444 Cursor acurs = null; 445 Cursor bcurs = null; 446 Cursor hcurs = null; 447 Cursor tcurs = null; 448 Transaction t = null; 449 450 Defrec rec = new Defrec(); 451 Histrec hrec = new Histrec(); 452 int account, branch, teller; 453 454 DatabaseEntry d_dbt = new DatabaseEntry(); 455 DatabaseEntry d_histdbt = new DatabaseEntry(); 456 DatabaseEntry k_dbt = new DatabaseEntry(); 457 DatabaseEntry k_histdbt = new DatabaseEntry(); 458 459 account = TpcbExample.this.random_id(TpcbExample.ACCOUNT); 460 branch = TpcbExample.this.random_id(TpcbExample.BRANCH); 461 teller = TpcbExample.this.random_id(TpcbExample.TELLER); 462 463 // The history key will not actually be retrieved, 464 // but it does need to be set to something. 465 byte[] hist_key = new byte[4]; 466 k_histdbt.setData(hist_key); 467 k_histdbt.setSize(4 /* == sizeof(int)*/); 468 469 byte[] key_bytes = new byte[4]; 470 k_dbt.setData(key_bytes); 471 k_dbt.setSize(4 /* == sizeof(int)*/); 472 473 d_dbt.setData(rec.data); 474 d_dbt.setUserBuffer(rec.length(), true); 475 476 hrec.set_aid(account); 477 hrec.set_bid(branch); 478 hrec.set_tid(teller); 479 hrec.set_amount(10); 480 // Request 0 bytes since we're just positioning. 481 d_histdbt.setPartial(0, 0, true); 482 483 // START PER-TRANSACTION TIMING. 484 // 485 // Technically, TPCB requires a limit on response time, you only 486 // get to count transactions that complete within 2 seconds. 487 // That's not an issue for this sample application -- regardless, 488 // here's where the transaction begins. 489 try { 490 t = dbenv.beginTransaction(null, null); 491 492 acurs = adb.openCursor(t, null); 493 bcurs = bdb.openCursor(t, null); 494 tcurs = tdb.openCursor(t, null); 495 hcurs = hdb.openCursor(t, null); 496 497 // Account record 498 k_dbt.setRecordNumber(account); 499 if (acurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 500 throw new Exception("acurs get failed"); 501 rec.set_balance(rec.get_balance() + 10); 502 acurs.putCurrent(d_dbt); 503 504 // Branch record 505 k_dbt.setRecordNumber(branch); 506 if (bcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 507 throw new Exception("bcurs get failed"); 508 rec.set_balance(rec.get_balance() + 10); 509 bcurs.putCurrent(d_dbt); 510 511 // Teller record 512 k_dbt.setRecordNumber(teller); 513 if (tcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 514 throw new Exception("ccurs get failed"); 515 rec.set_balance(rec.get_balance() + 10); 516 tcurs.putCurrent(d_dbt); 517 518 // History record 519 d_histdbt.setPartial(0, 0, false); 520 d_histdbt.setData(hrec.data); 521 d_histdbt.setUserBuffer(hrec.length(), true); 522 if (hdb.append(t, k_histdbt, d_histdbt) != OperationStatus.SUCCESS) 523 throw new DatabaseException("put failed"); 524 525 acurs.close(); 526 acurs = null; 527 bcurs.close(); 528 bcurs = null; 529 tcurs.close(); 530 tcurs = null; 531 hcurs.close(); 532 hcurs = null; 533 534 // null out t in advance; if the commit fails, 535 // we don't want to abort it in the catch clause. 536 Transaction tmptxn = t; 537 t = null; 538 tmptxn.commit(); 539 540 // END TIMING 541 return (0); 542 } catch (Exception e) { 543 try { 544 if (acurs != null) 545 acurs.close(); 546 if (bcurs != null) 547 bcurs.close(); 548 if (tcurs != null) 549 tcurs.close(); 550 if (hcurs != null) 551 hcurs.close(); 552 if (t != null) 553 t.abort(); 554 } catch (DatabaseException dbe) { 555 // not much we can do here. 556 } 557 558 if (TpcbExample.this.verbose) { 559 System.out.println("Transaction A=" + String.valueOf(account) + 560 " B=" + String.valueOf(branch) + 561 " T=" + String.valueOf(teller) + 562 " failed"); 563 System.out.println("Reason: " + e.toString()); 564 } 565 return (-1); 566 } 567 } 568 } 569 570 private static void usage() { 571 System.err.println( 572 "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" + 573 " [-c cachesize] [-h home] [-n transactions]\n" + 574 " [-T threads] [-S seed] [-s history] [-t tellers]"); 575 System.exit(1); 576 } 577 578 private static void invarg(String str) { 579 System.err.println("TpcbExample: invalid argument: " + str); 580 System.exit(1); 581 } 582 583 public static void errExit(Exception err, String s) { 584 System.err.print(progname + ": "); 585 if (s != null) { 586 System.err.print(s + ": "); 587 } 588 System.err.println(err.toString()); 589 System.exit(1); 590 } 591 592 public static void main(String[] argv) throws java.io.IOException { 593 File home = new File("TESTDIR"); 594 int accounts = ACCOUNTS; 595 int branches = BRANCHES; 596 int tellers = TELLERS; 597 int history = HISTORY; 598 int threads = 1; 599 int mpool = 0; 600 int ntxns = 0; 601 boolean iflag = false; 602 boolean txn_no_sync = false; 603 long seed = (new GregorianCalendar()).get(Calendar.SECOND); 604 605 for (int i = 0; i < argv.length; ++i) { 606 if (argv[i].equals("-a")) { 607 // Number of account records 608 if ((accounts = Integer.parseInt(argv[++i])) <= 0) 609 invarg(argv[i]); 610 } else if (argv[i].equals("-b")) { 611 // Number of branch records 612 if ((branches = Integer.parseInt(argv[++i])) <= 0) 613 invarg(argv[i]); 614 } else if (argv[i].equals("-c")) { 615 // Cachesize in bytes 616 if ((mpool = Integer.parseInt(argv[++i])) <= 0) 617 invarg(argv[i]); 618 } else if (argv[i].equals("-f")) { 619 // Fast mode: no txn sync. 620 txn_no_sync = true; 621 } else if (argv[i].equals("-h")) { 622 // DB home. 623 home = new File(argv[++i]); 624 } else if (argv[i].equals("-i")) { 625 // Initialize the test. 626 iflag = true; 627 } else if (argv[i].equals("-n")) { 628 // Number of transactions 629 if ((ntxns = Integer.parseInt(argv[++i])) <= 0) 630 invarg(argv[i]); 631 } else if (argv[i].equals("-S")) { 632 // Random number seed. 633 seed = Long.parseLong(argv[++i]); 634 if (seed <= 0) 635 invarg(argv[i]); 636 } else if (argv[i].equals("-s")) { 637 // Number of history records 638 if ((history = Integer.parseInt(argv[++i])) <= 0) 639 invarg(argv[i]); 640 } else if (argv[i].equals("-T")) { 641 // Number of threads 642 if ((threads = Integer.parseInt(argv[++i])) <= 0) 643 invarg(argv[i]); 644 } else if (argv[i].equals("-t")) { 645 // Number of teller records 646 if ((tellers = Integer.parseInt(argv[++i])) <= 0) 647 invarg(argv[i]); 648 } else if (argv[i].equals("-v")) { 649 // Verbose option. 650 verbose = true; 651 } else { 652 usage(); 653 } 654 } 655 656 rand.setSeed((int)seed); 657 658 // Initialize the database environment. 659 // Must be done in within a try block. 660 // 661 TpcbExample app = null; 662 try { 663 app = new TpcbExample(home, accounts, branches, tellers, history, 664 mpool, iflag || txn_no_sync); 665 } catch (Exception e1) { 666 errExit(e1, "initializing environment failed"); 667 } 668 669 if (verbose) 670 System.out.println((long)accounts + " Accounts, " + 671 String.valueOf(branches) + " Branches, " + 672 String.valueOf(tellers) + " Tellers, " + 673 String.valueOf(history) + " History"); 674 675 if (iflag) { 676 if (ntxns != 0) 677 usage(); 678 app.populate(); 679 } else { 680 if (ntxns == 0) 681 usage(); 682 app.run(ntxns, threads); 683 } 684 685 // Shut down the application. 686 687 try { 688 app.close(); 689 } catch (DatabaseException dbe2) { 690 errExit(dbe2, "appexit failed"); 691 } 692 693 System.exit(0); 694 } 695}; 696 697// Simulate the following C struct: 698// struct Defrec { 699// u_int32_t id; 700// u_int32_t balance; 701// u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)]; 702// }; 703 704class Defrec { 705 public Defrec() { 706 data = new byte[TpcbExample.RECLEN]; 707 } 708 709 public int length() { 710 return TpcbExample.RECLEN; 711 } 712 713 public long get_id() { 714 return TpcbExample.get_int_in_array(data, 0); 715 } 716 717 public void set_id(long value) { 718 TpcbExample.set_int_in_array(data, 0, value); 719 } 720 721 public long get_balance() { 722 return TpcbExample.get_int_in_array(data, 4); 723 } 724 725 public void set_balance(long value) { 726 TpcbExample.set_int_in_array(data, 4, value); 727 } 728 729 static { 730 Defrec d = new Defrec(); 731 d.set_balance(500000); 732 } 733 734 public byte[] data; 735} 736 737// Simulate the following C struct: 738// struct Histrec { 739// u_int32_t aid; 740// u_int32_t bid; 741// u_int32_t tid; 742// u_int32_t amount; 743// u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; 744// }; 745 746class Histrec { 747 public Histrec() { 748 data = new byte[TpcbExample.RECLEN]; 749 } 750 751 public int length() { 752 return TpcbExample.RECLEN; 753 } 754 755 public long get_aid() { 756 return TpcbExample.get_int_in_array(data, 0); 757 } 758 759 public void set_aid(long value) { 760 TpcbExample.set_int_in_array(data, 0, value); 761 } 762 763 public long get_bid() { 764 return TpcbExample.get_int_in_array(data, 4); 765 } 766 767 public void set_bid(long value) { 768 TpcbExample.set_int_in_array(data, 4, value); 769 } 770 771 public long get_tid() { 772 return TpcbExample.get_int_in_array(data, 8); 773 } 774 775 public void set_tid(long value) { 776 TpcbExample.set_int_in_array(data, 8, value); 777 } 778 779 public long get_amount() { 780 return TpcbExample.get_int_in_array(data, 12); 781 } 782 783 public void set_amount(long value) { 784 TpcbExample.set_int_in_array(data, 12, value); 785 } 786 787 public byte[] data; 788} 789