1 /*- 2 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved. 3 * 4 * See the file EXAMPLES-LICENSE for license information. 5 * 6 */ 7 8 package db; 9 10 import com.sleepycat.db.*; 11 12 import java.io.File; 13 import java.io.FileNotFoundException; 14 import java.math.BigDecimal; 15 import java.util.Calendar; 16 import java.util.Date; 17 import java.util.Random; 18 import java.util.GregorianCalendar; 19 20 // 21 // This program implements a basic TPC/B driver program. To create the 22 // TPC/B database, run with the -i (init) flag. The number of records 23 // with which to populate the account, history, branch, and teller tables 24 // is specified by the a, s, b, and t flags respectively. To run a TPC/B 25 // test, use the n flag to indicate a number of transactions to run in 26 // each thread and -T to specify the number of threads. 27 // 28 class TpcbExample { 29 public static final int TELLERS_PER_BRANCH = 10; 30 public static final int ACCOUNTS_PER_TELLER = 10000; 31 public static final int HISTORY_PER_BRANCH = 2592000; 32 33 // 34 // The default configuration that adheres to TPCB scaling rules requires 35 // nearly 3 GB of space. To avoid requiring that much space for testing, 36 // we set the parameters much lower. If you want to run a valid 10 TPS 37 // configuration, uncomment the VALID_SCALING configuration 38 // 39 40 // VALID_SCALING configuration 41 /* 42 public static final int ACCOUNTS = 1000000; 43 public static final int BRANCHES = 10; 44 public static final int TELLERS = 100; 45 public static final int HISTORY = 25920000; 46 */ 47 48 // TINY configuration 49 /* 50 public static final int ACCOUNTS = 1000; 51 public static final int BRANCHES = 10; 52 public static final int TELLERS = 100; 53 public static final int HISTORY = 10000; 54 */ 55 56 // Default configuration 57 public static final int ACCOUNTS = 100000; 58 public static final int BRANCHES = 10; 59 public static final int TELLERS = 100; 60 public static final int HISTORY = 259200; 61 62 public static final int HISTORY_LEN = 100; 63 public static final int RECLEN = 100; 64 public static final int BEGID = 1000000; 65 66 // used by random_id() 67 public static final int ACCOUNT = 0; 68 public static final int BRANCH = 1; 69 public static final int TELLER = 2; 70 71 public static boolean verbose = false; 72 public static final String progname = "TpcbExample"; // Program name. 73 74 Environment dbenv; 75 int accounts, branches, tellers, history; 76 TpcbExample(File home, int accounts, int branches, int tellers, int history, int cachesize, boolean noSync)77 public TpcbExample(File home, 78 int accounts, int branches, int tellers, int history, 79 int cachesize, boolean noSync) 80 throws DatabaseException, FileNotFoundException { 81 82 this.accounts = accounts; 83 this.branches = branches; 84 this.tellers = tellers; 85 this.history = history; 86 87 EnvironmentConfig config = new EnvironmentConfig(); 88 config.setErrorStream(System.err); 89 config.setErrorPrefix(progname); 90 config.setLockDetectMode(LockDetectMode.DEFAULT); 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 close()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 // populate()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 (DatabaseException | FileNotFoundException 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 (DatabaseException | FileNotFoundException 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 (DatabaseException | FileNotFoundException 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 (DatabaseException | FileNotFoundException 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 populateTable(Database dbp, int start_id, int balance, int nrecs, String msg)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 populateHistory(Database dbp)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(); random_int(int lo, int hi)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 random_id(int type)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 // get_int_in_array(byte[] array, int offset)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 set_int_in_array(byte[] array, int offset, long value)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 showRounded(double d, int scale)349 static String showRounded(double d, int scale) { 350 return new BigDecimal(d). 351 setScale(scale, BigDecimal.ROUND_HALF_DOWN).toString(); 352 } 353 run(int ntxns, int threads)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 final 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 TxnThread(String name, int ntxns)391 public TxnThread(String name, int ntxns) { 392 super(name); 393 this.ntxns = ntxns; 394 } 395 396 @Override run()397 public void run() { 398 double gtps, itps; 399 int n, ret; 400 long start_time, end_time; 401 402 // 403 // Open the database files. 404 // 405 int err; 406 try { 407 DatabaseConfig config = new DatabaseConfig(); 408 config.setTransactional(true); 409 adb = dbenv.openDatabase(null, "account", null, config); 410 bdb = dbenv.openDatabase(null, "branch", null, config); 411 tdb = dbenv.openDatabase(null, "teller", null, config); 412 hdb = dbenv.openDatabase(null, "history", null, config); 413 } catch (DatabaseException dbe) { 414 TpcbExample.errExit(dbe, "Open of db files failed"); 415 } catch (FileNotFoundException fnfe) { 416 TpcbExample.errExit(fnfe, "Open of db files failed, missing file"); 417 } 418 419 start_time = (new Date()).getTime(); 420 for (txns = n = ntxns, failed = 0; n-- > 0;) 421 if ((ret = txn()) != 0) 422 failed++; 423 end_time = (new Date()).getTime(); 424 if (end_time == start_time) 425 end_time++; 426 427 System.out.println(getName() + ": " + (long)txns + " txns: " + 428 failed + " failed, " + TpcbExample.showRounded( 429 (txns - failed) / (double)(end_time - start_time), 2) + " TPS"); 430 431 try { 432 adb.close(); 433 bdb.close(); 434 tdb.close(); 435 hdb.close(); 436 } catch (DatabaseException dbe2) { 437 TpcbExample.errExit(dbe2, "Close of db files failed"); 438 } 439 } 440 441 // 442 // XXX Figure out the appropriate way to pick out IDs. 443 // txn()444 int txn() { 445 Cursor acurs = null; 446 Cursor bcurs = null; 447 Cursor hcurs = null; 448 Cursor tcurs = null; 449 Transaction t = null; 450 451 Defrec rec = new Defrec(); 452 Histrec hrec = new Histrec(); 453 int account, branch, teller; 454 455 DatabaseEntry d_dbt = new DatabaseEntry(); 456 DatabaseEntry d_histdbt = new DatabaseEntry(); 457 DatabaseEntry k_dbt = new DatabaseEntry(); 458 DatabaseEntry k_histdbt = new DatabaseEntry(); 459 460 account = TpcbExample.this.random_id(TpcbExample.ACCOUNT); 461 branch = TpcbExample.this.random_id(TpcbExample.BRANCH); 462 teller = TpcbExample.this.random_id(TpcbExample.TELLER); 463 464 // The history key will not actually be retrieved, 465 // but it does need to be set to something. 466 byte[] hist_key = new byte[4]; 467 k_histdbt.setData(hist_key); 468 k_histdbt.setSize(4 /* == sizeof(int)*/); 469 470 byte[] key_bytes = new byte[4]; 471 k_dbt.setData(key_bytes); 472 k_dbt.setSize(4 /* == sizeof(int)*/); 473 474 d_dbt.setData(rec.data); 475 d_dbt.setUserBuffer(rec.length(), true); 476 477 hrec.set_aid(account); 478 hrec.set_bid(branch); 479 hrec.set_tid(teller); 480 hrec.set_amount(10); 481 // Request 0 bytes since we're just positioning. 482 d_histdbt.setPartial(0, 0, true); 483 484 // START PER-TRANSACTION TIMING. 485 // 486 // Technically, TPCB requires a limit on response time, you only 487 // get to count transactions that complete within 2 seconds. 488 // That's not an issue for this sample application -- regardless, 489 // here's where the transaction begins. 490 try { 491 t = dbenv.beginTransaction(null, null); 492 493 acurs = adb.openCursor(t, null); 494 bcurs = bdb.openCursor(t, null); 495 tcurs = tdb.openCursor(t, null); 496 hcurs = hdb.openCursor(t, null); 497 498 // Account record 499 k_dbt.setRecordNumber(account); 500 if (acurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 501 throw new Exception("acurs get failed"); 502 rec.set_balance(rec.get_balance() + 10); 503 acurs.putCurrent(d_dbt); 504 505 // Branch record 506 k_dbt.setRecordNumber(branch); 507 if (bcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 508 throw new Exception("bcurs get failed"); 509 rec.set_balance(rec.get_balance() + 10); 510 bcurs.putCurrent(d_dbt); 511 512 // Teller record 513 k_dbt.setRecordNumber(teller); 514 if (tcurs.getSearchKey(k_dbt, d_dbt, null) != OperationStatus.SUCCESS) 515 throw new Exception("ccurs get failed"); 516 rec.set_balance(rec.get_balance() + 10); 517 tcurs.putCurrent(d_dbt); 518 519 // History record 520 d_histdbt.setPartial(0, 0, false); 521 d_histdbt.setData(hrec.data); 522 d_histdbt.setUserBuffer(hrec.length(), true); 523 if (hdb.append(t, k_histdbt, d_histdbt) != OperationStatus.SUCCESS) 524 throw new DatabaseException("put failed"); 525 526 acurs.close(); 527 acurs = null; 528 bcurs.close(); 529 bcurs = null; 530 tcurs.close(); 531 tcurs = null; 532 hcurs.close(); 533 hcurs = null; 534 535 // null out t in advance; if the commit fails, 536 // we don't want to abort it in the catch clause. 537 Transaction tmptxn = t; 538 t = null; 539 tmptxn.commit(); 540 541 // END TIMING 542 return (0); 543 } catch (Exception e) { 544 try { 545 if (acurs != null) 546 acurs.close(); 547 if (bcurs != null) 548 bcurs.close(); 549 if (tcurs != null) 550 tcurs.close(); 551 if (hcurs != null) 552 hcurs.close(); 553 if (t != null) 554 t.abort(); 555 } catch (DatabaseException dbe) { 556 // not much we can do here. 557 } 558 559 if (TpcbExample.this.verbose) { 560 System.out.println("Transaction A=" + String.valueOf(account) + 561 " B=" + String.valueOf(branch) + 562 " T=" + String.valueOf(teller) + 563 " failed"); 564 System.out.println("Reason: " + e.toString()); 565 } 566 return (-1); 567 } 568 } 569 } 570 usage()571 private static void usage() { 572 System.err.println( 573 "usage: TpcbExample [-fiv] [-a accounts] [-b branches]\n" + 574 " [-c cachesize] [-h home] [-n transactions]\n" + 575 " [-T threads] [-S seed] [-s history] [-t tellers]"); 576 System.exit(1); 577 } 578 invarg(String str)579 private static void invarg(String str) { 580 System.err.println("TpcbExample: invalid argument: " + str); 581 System.exit(1); 582 } 583 errExit(Exception err, String s)584 public static void errExit(Exception err, String s) { 585 System.err.print(progname + ": "); 586 if (s != null) { 587 System.err.print(s + ": "); 588 } 589 System.err.println(err.toString()); 590 System.exit(1); 591 } 592 main(String[] argv)593 public static void main(String[] argv) throws java.io.IOException { 594 File home = new File("TESTDIR"); 595 int accounts = ACCOUNTS; 596 int branches = BRANCHES; 597 int tellers = TELLERS; 598 int history = HISTORY; 599 int threads = 1; 600 int mpool = 0; 601 int ntxns = 0; 602 boolean iflag = false; 603 boolean txn_no_sync = false; 604 long seed = (new GregorianCalendar()).get(Calendar.SECOND); 605 606 for (int i = 0; i < argv.length; ++i) { 607 switch (argv[i]) { 608 case "-a": 609 // Number of account records 610 if ((accounts = Integer.parseInt(argv[++i])) <= 0) 611 invarg(argv[i]); 612 break; 613 case "-b": 614 // Number of branch records 615 if ((branches = Integer.parseInt(argv[++i])) <= 0) 616 invarg(argv[i]); 617 break; 618 case "-c": 619 // Cachesize in bytes 620 if ((mpool = Integer.parseInt(argv[++i])) <= 0) 621 invarg(argv[i]); 622 break; 623 case "-f": 624 // Fast mode: no txn sync. 625 txn_no_sync = true; 626 break; 627 case "-h": 628 // DB home. 629 home = new File(argv[++i]); 630 break; 631 case "-i": 632 // Initialize the test. 633 iflag = true; 634 break; 635 case "-n": 636 // Number of transactions 637 if ((ntxns = Integer.parseInt(argv[++i])) <= 0) 638 invarg(argv[i]); 639 break; 640 case "-S": 641 // Random number seed. 642 seed = Long.parseLong(argv[++i]); 643 if (seed <= 0) 644 invarg(argv[i]); 645 break; 646 case "-s": 647 // Number of history records 648 if ((history = Integer.parseInt(argv[++i])) <= 0) 649 invarg(argv[i]); 650 break; 651 case "-T": 652 // Number of threads 653 if ((threads = Integer.parseInt(argv[++i])) <= 0) 654 invarg(argv[i]); 655 break; 656 case "-t": 657 // Number of teller records 658 if ((tellers = Integer.parseInt(argv[++i])) <= 0) 659 invarg(argv[i]); 660 break; 661 case "-v": 662 // Verbose option. 663 verbose = true; 664 break; 665 default: 666 usage(); 667 break; 668 } 669 } 670 671 rand.setSeed((int)seed); 672 673 // Initialize the database environment. 674 // Must be done in within a try block. 675 // 676 TpcbExample app = null; 677 try { 678 app = new TpcbExample(home, accounts, branches, tellers, history, 679 mpool, iflag || txn_no_sync); 680 } catch (DatabaseException | FileNotFoundException e1) { 681 errExit(e1, "initializing environment failed"); 682 } 683 684 if (verbose) 685 System.out.println((long)accounts + " Accounts, " + 686 String.valueOf(branches) + " Branches, " + 687 String.valueOf(tellers) + " Tellers, " + 688 String.valueOf(history) + " History"); 689 690 if (iflag) { 691 if (ntxns != 0) 692 usage(); 693 app.populate(); 694 } else { 695 if (ntxns == 0) 696 usage(); 697 app.run(ntxns, threads); 698 } 699 700 // Shut down the application. 701 702 try { 703 app.close(); 704 } catch (DatabaseException dbe2) { 705 errExit(dbe2, "appexit failed"); 706 } 707 708 System.exit(0); 709 } 710 }; 711 712 // Simulate the following C struct: 713 // struct Defrec { 714 // u_int32_t id; 715 // u_int32_t balance; 716 // u_int8_t pad[RECLEN - sizeof(int) - sizeof(int)]; 717 // }; 718 719 class Defrec { Defrec()720 public Defrec() { 721 data = new byte[TpcbExample.RECLEN]; 722 } 723 length()724 public int length() { 725 return TpcbExample.RECLEN; 726 } 727 get_id()728 public long get_id() { 729 return TpcbExample.get_int_in_array(data, 0); 730 } 731 set_id(long value)732 public void set_id(long value) { 733 TpcbExample.set_int_in_array(data, 0, value); 734 } 735 get_balance()736 public long get_balance() { 737 return TpcbExample.get_int_in_array(data, 4); 738 } 739 set_balance(long value)740 public void set_balance(long value) { 741 TpcbExample.set_int_in_array(data, 4, value); 742 } 743 744 static { 745 Defrec d = new Defrec(); 746 d.set_balance(500000); 747 } 748 749 public byte[] data; 750 } 751 752 // Simulate the following C struct: 753 // struct Histrec { 754 // u_int32_t aid; 755 // u_int32_t bid; 756 // u_int32_t tid; 757 // u_int32_t amount; 758 // u_int8_t pad[RECLEN - 4 * sizeof(u_int32_t)]; 759 // }; 760 761 class Histrec { Histrec()762 public Histrec() { 763 data = new byte[TpcbExample.RECLEN]; 764 } 765 length()766 public int length() { 767 return TpcbExample.RECLEN; 768 } 769 get_aid()770 public long get_aid() { 771 return TpcbExample.get_int_in_array(data, 0); 772 } 773 set_aid(long value)774 public void set_aid(long value) { 775 TpcbExample.set_int_in_array(data, 0, value); 776 } 777 get_bid()778 public long get_bid() { 779 return TpcbExample.get_int_in_array(data, 4); 780 } 781 set_bid(long value)782 public void set_bid(long value) { 783 TpcbExample.set_int_in_array(data, 4, value); 784 } 785 get_tid()786 public long get_tid() { 787 return TpcbExample.get_int_in_array(data, 8); 788 } 789 set_tid(long value)790 public void set_tid(long value) { 791 TpcbExample.set_int_in_array(data, 8, value); 792 } 793 get_amount()794 public long get_amount() { 795 return TpcbExample.get_int_in_array(data, 12); 796 } 797 set_amount(long value)798 public void set_amount(long value) { 799 TpcbExample.set_int_in_array(data, 12, value); 800 } 801 802 public byte[] data; 803 } 804