From e6abd29d9236b5693d470571096bece3673a8c65 Mon Sep 17 00:00:00 2001 From: thawk105 Date: Thu, 14 May 2026 08:45:27 +0000 Subject: [PATCH] =?UTF-8?q?style:=20=E3=82=BD=E3=83=BC=E3=82=B9=E5=85=A8?= =?UTF-8?q?=E4=BD=93=E3=82=92=20.clang-format=20=E3=81=AB=E5=90=88?= =?UTF-8?q?=E3=82=8F=E3=81=9B=E3=81=A6=E4=B8=80=E6=8B=AC=20reformat?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `cc/ include/ common/` 配下の 240 ファイル (`.cc` / `.hh` / `.cpp`) に clang-format 14 を機械適用。意味的変更はゼロ。 #75 で .clang-format をリファインしたが、その整形を全ソースに適用する #76 はベースが refine-clang-format ブランチのままマージされ master に 届いていなかった。本コミットで現 master (= #79 / #80 取り込み済み) に 対して reformat を当て直す。Closes #74。 --- cc/cicada/bomb_cicada.cc | 37 +- cc/cicada/cicada.cc | 316 ++-- cc/cicada/include/cicada_op_element.hh | 43 +- cc/cicada/include/common.hh | 45 +- cc/cicada/include/lock.hh | 11 +- cc/cicada/include/result.hh | 2 +- cc/cicada/include/scan_callback.hh | 11 +- cc/cicada/include/time_stamp.hh | 2 +- cc/cicada/include/transaction.hh | 77 +- cc/cicada/include/tuple.hh | 19 +- cc/cicada/include/util.hh | 2 +- cc/cicada/include/version.hh | 49 +- cc/cicada/sbomb_cicada.cc | 31 +- cc/cicada/testzip.cc | 18 +- cc/cicada/tpcc_cicada.cc | 31 +- cc/cicada/transaction.cc | 213 +-- cc/cicada/util.cc | 45 +- cc/cicada/ycsb_cicada.cc | 28 +- cc/d2pl/dbomb_d2pl.cc | 41 +- cc/d2pl/include/common.hh | 2 +- cc/d2pl/include/d2pl_op_element.hh | 24 +- cc/d2pl/include/result.hh | 2 +- cc/d2pl/include/transaction.hh | 39 +- cc/d2pl/include/tuple.hh | 3 +- cc/d2pl/include/util.hh | 3 +- cc/d2pl/sbomb_d2pl.cc | 41 +- cc/d2pl/transaction.cc | 92 +- cc/d2pl/util.cc | 23 +- cc/ermia/bomb_ermia.cc | 53 +- cc/ermia/ermia.cc | 70 +- cc/ermia/garbage_collection.cc | 16 +- cc/ermia/include/common.hh | 22 +- cc/ermia/include/ermia_op_element.hh | 27 +- cc/ermia/include/garbage_collection.hh | 27 +- cc/ermia/include/lock.hh | 11 +- cc/ermia/include/result.hh | 2 +- cc/ermia/include/scan_callback.hh | 11 +- cc/ermia/include/transaction.hh | 60 +- cc/ermia/include/transaction_table.hh | 10 +- cc/ermia/include/tuple.hh | 13 +- cc/ermia/include/util.hh | 4 +- cc/ermia/include/version.hh | 10 +- cc/ermia/sbomb_ermia.cc | 47 +- cc/ermia/tpcc_ermia.cc | 47 +- cc/ermia/transaction.cc | 183 +- cc/ermia/util.cc | 28 +- cc/ermia/ycsb_ermia.cc | 44 +- cc/mocc/bomb_mocc.cc | 53 +- cc/mocc/include/atomic_tool.hh | 2 +- cc/mocc/include/common.hh | 18 +- cc/mocc/include/lock.hh | 75 +- cc/mocc/include/mocc_op_element.hh | 24 +- cc/mocc/include/result.hh | 2 +- cc/mocc/include/scan_callback.hh | 11 +- cc/mocc/include/transaction.hh | 46 +- cc/mocc/include/tuple.hh | 27 +- cc/mocc/include/util.hh | 3 +- cc/mocc/lock.cc | 252 +-- cc/mocc/mocc.cc | 70 +- cc/mocc/sbomb_mocc.cc | 47 +- cc/mocc/tpcc_mocc.cc | 47 +- cc/mocc/transaction.cc | 220 +-- cc/mocc/util.cc | 24 +- cc/mocc/ycsb_mocc.cc | 43 +- cc/mvto/bomb_mvto.cc | 37 +- cc/mvto/include/common.hh | 36 +- cc/mvto/include/lock.hh | 11 +- cc/mvto/include/mvto_op_element.hh | 43 +- cc/mvto/include/result.hh | 2 +- cc/mvto/include/time_stamp.hh | 2 +- cc/mvto/include/transaction.hh | 87 +- cc/mvto/include/tuple.hh | 16 +- cc/mvto/include/version.hh | 47 +- cc/mvto/tpcc_mvto.cc | 33 +- cc/mvto/transaction.cc | 179 +- cc/mvto/util.cc | 27 +- cc/occ/include/common.hh | 6 +- cc/occ/include/log.hh | 10 +- cc/occ/include/occ_op_element.hh | 4 +- cc/occ/include/transaction.hh | 2 +- cc/occ/include/tuple.hh | 2 +- cc/occ/include/util.hh | 2 +- cc/occ/occ.cc | 12 +- cc/occ/transaction.cc | 24 +- cc/occ/util.cc | 28 +- cc/oze/bomb_oze.cc | 45 +- cc/oze/debug.cc | 30 +- cc/oze/include/atomic_tool.hh | 2 +- cc/oze/include/cc_mode.hh | 36 +- cc/oze/include/common.hh | 23 +- cc/oze/include/debug.hh | 6 +- cc/oze/include/lock.hh | 11 +- cc/oze/include/oze.hh | 64 +- cc/oze/include/oze_op_element.hh | 26 +- cc/oze/include/result.hh | 2 +- cc/oze/include/scan.hh | 33 +- cc/oze/include/scan_callback.hh | 11 +- cc/oze/include/test.hh | 208 ++- cc/oze/include/thread_management.hh | 4 +- cc/oze/include/time_stamp.hh | 2 +- cc/oze/include/transaction.hh | 2096 ++++++++++----------- cc/oze/include/tuple.hh | 33 +- cc/oze/include/txid.hh | 57 +- cc/oze/include/util.hh | 4 +- cc/oze/include/version.hh | 86 +- cc/oze/oze.cc | 70 +- cc/oze/tpcc_oze.cc | 39 +- cc/oze/transaction.cc | 1377 +++++++------- cc/oze/util.cc | 18 +- cc/oze/ycsb_oze.cc | 33 +- cc/si/bomb_si.cc | 53 +- cc/si/garbage_collection.cc | 16 +- cc/si/include/common.hh | 22 +- cc/si/include/garbage_collection.hh | 27 +- cc/si/include/lock.hh | 11 +- cc/si/include/result.hh | 2 +- cc/si/include/scan_callback.hh | 11 +- cc/si/include/si_op_element.hh | 27 +- cc/si/include/transaction.hh | 60 +- cc/si/include/transaction_table.hh | 10 +- cc/si/include/tuple.hh | 13 +- cc/si/include/util.hh | 4 +- cc/si/include/version.hh | 10 +- cc/si/sbomb_si.cc | 47 +- cc/si/si.cc | 70 +- cc/si/tpcc_si.cc | 47 +- cc/si/transaction.cc | 123 +- cc/si/util.cc | 28 +- cc/si/ycsb_si.cc | 44 +- cc/silo/bomb_silo.cc | 41 +- cc/silo/include/atomic_tool.hh | 2 +- cc/silo/include/common.hh | 10 +- cc/silo/include/log.hh | 10 +- cc/silo/include/result.hh | 2 +- cc/silo/include/scan_callback.hh | 11 +- cc/silo/include/silo_op_element.hh | 53 +- cc/silo/include/transaction.hh | 28 +- cc/silo/include/tuple.hh | 21 +- cc/silo/include/util.hh | 9 +- cc/silo/replayTest.cc | 6 +- cc/silo/sbomb_silo.cc | 35 +- cc/silo/silo.cc | 209 ++- cc/silo/tpcc_silo.cc | 35 +- cc/silo/transaction.cc | 131 +- cc/silo/util.cc | 14 +- cc/silo/ycsb_silo.cc | 31 +- cc/ss2pl/bomb_ss2pl.cc | 41 +- cc/ss2pl/include/result.hh | 2 +- cc/ss2pl/include/ss2pl_op_element.hh | 18 +- cc/ss2pl/include/transaction.hh | 48 +- cc/ss2pl/include/tuple.hh | 5 +- cc/ss2pl/include/util.hh | 3 +- cc/ss2pl/ss2pl.cc | 42 +- cc/ss2pl/test/make_db_test.cpp | 28 +- cc/ss2pl/tpcc_ss2pl.cc | 35 +- cc/ss2pl/transaction.cc | 96 +- cc/ss2pl/util.cc | 29 +- cc/tictoc/bomb_tictoc.cc | 32 +- cc/tictoc/include/atomic_tool.hh | 2 +- cc/tictoc/include/common.hh | 2 +- cc/tictoc/include/result.hh | 2 +- cc/tictoc/include/scan_callback.hh | 11 +- cc/tictoc/include/tictoc_op_element.hh | 27 +- cc/tictoc/include/transaction.hh | 36 +- cc/tictoc/include/tuple.hh | 15 +- cc/tictoc/sbomb_tictoc.cc | 26 +- cc/tictoc/tictoc.cc | 20 +- cc/tictoc/tpcc_tictoc.cc | 26 +- cc/tictoc/transaction.cc | 135 +- cc/tictoc/util.cc | 10 +- cc/tictoc/ycsb_tictoc.cc | 20 +- common/result.cc | 206 ++- common/util.cc | 22 +- include/atomic_wrapper.hh | 50 +- include/backoff.hh | 11 +- include/bomb.hh | 2186 +++++++++++----------- include/bomb_pessimistic.hh | 2369 ++++++++++++------------ include/bomb_static.hh | 172 +- include/check.hh | 2 +- include/cpu.hh | 36 +- include/dbomb_deterministic.hh | 776 ++++---- include/debug.hh | 91 +- include/delay.hh | 3 +- include/fence.hh | 2 +- include/fileio.hh | 54 +- include/heap_object.hh | 58 +- include/lock.hh | 15 +- include/masstree_wrapper.hh | 121 +- include/op_element.hh | 14 +- include/procedure.hh | 2 +- include/queue.hh | 6 +- include/random.hh | 8 +- include/result.hh | 26 +- include/sbomb_deterministic.hh | 380 ++-- include/string.hh | 8 +- include/tpcc.hh | 168 +- include/tpcc/tpcc_common.hh | 9 +- include/tpcc/tpcc_initializer.hh | 210 ++- include/tpcc/tpcc_query.hh | 54 +- include/tpcc/tpcc_tables.hh | 200 +- include/tpcc/tpcc_tx_delivery.hh | 117 +- include/tpcc/tpcc_tx_neworder.hh | 221 +-- include/tpcc/tpcc_tx_orderstatus.hh | 59 +- include/tpcc/tpcc_tx_payment.hh | 112 +- include/tpcc/tpcc_tx_stocklevel.hh | 32 +- include/tpcc/tpcc_util.hh | 71 +- include/tsc.hh | 11 +- include/tuple_body.hh | 21 +- include/tx_executor_concept.hh | 29 +- include/util.hh | 60 +- include/workload.hh | 28 +- include/ycsb.hh | 222 +-- include/zipf.hh | 35 +- 213 files changed, 8997 insertions(+), 9089 deletions(-) diff --git a/cc/cicada/bomb_cicada.cc b/cc/cicada/bomb_cicada.cc index ec87e864..6933aadc 100644 --- a/cc/cicada/bomb_cicada.cc +++ b/cc/cicada/bomb_cicada.cc @@ -36,10 +36,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &CicadaResult[thid], quit); - BombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &CicadaResult[thid], quit); + BombWorkload workload; workload.prepare(trans, new TupleInitParam()); #ifdef Linux @@ -47,13 +47,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -62,19 +62,19 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB Cicada benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); + BombWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - BombWorkload::makeDB(param); + BombWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -83,33 +83,30 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { CicadaResult[0].addLocalAllResult(CicadaResult[i]); CicadaResult[0].addLocalPerTxResult(CicadaResult[i], TxTypes); } ShowOptParameters(); - CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; CicadaResult[0].displayPerTxResult(TxTypes); // TODO: enable this if really necessary // deleteDB(); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/cicada/cicada.cc b/cc/cicada/cicada.cc index 67fd0ee2..b53103be 100644 --- a/cc/cicada/cicada.cc +++ b/cc/cicada/cicada.cc @@ -36,13 +36,13 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { YcsbWorkload workload; // Xoroshiro128Plus rnd; // rnd.init(); Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &CicadaResult[thid], quit); - Result &myres = std::ref(CicadaResult[thid]); + TxExecutor trans(thid, backoff, (Result*) &CicadaResult[thid], quit); + Result& myres = std::ref(CicadaResult[thid]); // FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); #ifdef Linux @@ -50,184 +50,182 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin uint64_t tuples = FLAGS_tuple_num; - if (FLAGS_batch_simple_rr) { - tuples = FLAGS_tuple_num - FLAGS_batch_tuples; - } + if (FLAGS_batch_simple_rr) { tuples = FLAGS_tuple_num - FLAGS_batch_tuples; } storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); -// /* シングル実行で絶対に競合を起こさないワークロードにおいて, -// * 自トランザクションで read した後に write するのは複雑になる. -// * write した後に read であれば,write set から read -// * するので挙動がシンプルになる. -// * スレッドごとにアクセスブロックを作る形でパーティションを作って -// * スレッド間の競合を無くした後に sort して同一キーに対しては -// * write - read とする. -// * */ -// #if SINGLE_EXEC -// makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, -// FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, thid, myres); -// sort(trans.pro_set_.begin(), trans.pro_set_.end()); -// #else -// #if PARTITION_TABLE -// makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, -// FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, thid, myres); -// #else -// auto r = rnd.next() % 100; -// if ((FLAGS_thread_num && thid >= FLAGS_thread_num) -// || (r < FLAGS_batch_ratio)) { -// trans.is_batch_ = true; -// makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, -// FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, -// myres); -// } else if (r >= FLAGS_batch_ratio -// && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { -// trans.is_batch_ = false; -// makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, -// FLAGS_max_ope, myres); -// } else { -// trans.is_batch_ = false; -// makeProcedure(trans.pro_set_, rnd, zipf, tuples, FLAGS_max_ope, -// FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, -// false, thid, myres); -// } -// #endif -// #endif + workload.run(trans); + // /* シングル実行で絶対に競合を起こさないワークロードにおいて, + // * 自トランザクションで read した後に write するのは複雑になる. + // * write した後に read であれば,write set から read + // * するので挙動がシンプルになる. + // * スレッドごとにアクセスブロックを作る形でパーティションを作って + // * スレッド間の競合を無くした後に sort して同一キーに対しては + // * write - read とする. + // * */ + // #if SINGLE_EXEC + // makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, + // FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, thid, myres); + // sort(trans.pro_set_.begin(), trans.pro_set_.end()); + // #else + // #if PARTITION_TABLE + // makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, + // FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, thid, myres); + // #else + // auto r = rnd.next() % 100; + // if ((FLAGS_thread_num && thid >= FLAGS_thread_num) + // || (r < FLAGS_batch_ratio)) { + // trans.is_batch_ = true; + // makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, + // FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, + // myres); + // } else if (r >= FLAGS_batch_ratio + // && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + // trans.is_batch_ = false; + // makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, + // FLAGS_max_ope, myres); + // } else { + // trans.is_batch_ = false; + // makeProcedure(trans.pro_set_, rnd, zipf, tuples, FLAGS_max_ope, + // FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, + // false, thid, myres); + // } + // #endif + // #endif -// RETRY: -// if (thid == 0) { -// leaderWork(std::ref(backoff)); -// #if BACK_OFF -// leaderBackoffWork(backoff, CicadaResult); -// #endif -// } -// if (loadAcquire(quit)) break; + // RETRY: + // if (thid == 0) { + // leaderWork(std::ref(backoff)); + // #if BACK_OFF + // leaderBackoffWork(backoff, CicadaResult); + // #endif + // } + // if (loadAcquire(quit)) break; -// trans.tbegin(); -// for (auto itr = trans.pro_set_.begin(); itr != trans.pro_set_.end(); -// ++itr) { -// if ((*itr).ope_ == Ope::READ) { -// trans.tread((*itr).key_); -// #ifdef INSERT_READ_DELAY_MS -// sleepMs(INSERT_READ_DELAY_MS); -// #endif -// } else if ((*itr).ope_ == Ope::WRITE) { -// trans.twrite((*itr).key_); -// } else if ((*itr).ope_ == Ope::READ_MODIFY_WRITE) { -// trans.tread((*itr).key_); -// #ifdef INSERT_READ_DELAY_MS -// sleepMs(INSERT_READ_DELAY_MS); -// #endif -// trans.twrite((*itr).key_); -// } else { -// ERR; -// } + // trans.tbegin(); + // for (auto itr = trans.pro_set_.begin(); itr != trans.pro_set_.end(); + // ++itr) { + // if ((*itr).ope_ == Ope::READ) { + // trans.tread((*itr).key_); + // #ifdef INSERT_READ_DELAY_MS + // sleepMs(INSERT_READ_DELAY_MS); + // #endif + // } else if ((*itr).ope_ == Ope::WRITE) { + // trans.twrite((*itr).key_); + // } else if ((*itr).ope_ == Ope::READ_MODIFY_WRITE) { + // trans.tread((*itr).key_); + // #ifdef INSERT_READ_DELAY_MS + // sleepMs(INSERT_READ_DELAY_MS); + // #endif + // trans.twrite((*itr).key_); + // } else { + // ERR; + // } -// if (trans.status_ == TransactionStatus::abort) { -// trans.earlyAbort(); -// #if SINGLE_EXEC -// #else -// trans.mainte(); -// #endif -// goto RETRY; -// } -// } + // if (trans.status_ == TransactionStatus::abort) { + // trans.earlyAbort(); + // #if SINGLE_EXEC + // #else + // trans.mainte(); + // #endif + // goto RETRY; + // } + // } -// /** -// * Tanabe Optimization for analysis -// */ -// #if WORKER1_INSERT_DELAY_RPHASE -// if (unlikely(thid == 1) && WORKER1_INSERT_DELAY_RPHASE_US != 0) { -// clock_delay(WORKER1_INSERT_DELAY_RPHASE_US * FLAGS_clocks_per_us); -// } -// #endif + // /** + // * Tanabe Optimization for analysis + // */ + // #if WORKER1_INSERT_DELAY_RPHASE + // if (unlikely(thid == 1) && WORKER1_INSERT_DELAY_RPHASE_US != 0) { + // clock_delay(WORKER1_INSERT_DELAY_RPHASE_US * FLAGS_clocks_per_us); + // } + // #endif -// #ifdef INSERT_BATCH_DELAY_MS -// if (trans.is_batch_) { -// sleepMs(INSERT_BATCH_DELAY_MS); -// } -// #endif + // #ifdef INSERT_BATCH_DELAY_MS + // if (trans.is_batch_) { + // sleepMs(INSERT_BATCH_DELAY_MS); + // } + // #endif -// /** -// * Excerpt from original paper 3.1 Multi-Clocks Timestamp Allocation -// * A read-only transaction uses (thread.rts) instead, -// * and does not track or validate the read set; -// */ -// if ((*trans.pro_set_.begin()).ronly_) { -// /** -// * local_commit_counts is used at ../include/backoff.hh to calcurate about -// * backoff. -// */ -// if (trans.is_batch_) { -// storeRelease(myres.local_batch_commit_counts_, -// loadAcquire(myres.local_batch_commit_counts_) + 1); -// } else { -// storeRelease(myres.local_commit_counts_, -// loadAcquire(myres.local_commit_counts_) + 1); -// } -// } else { -// /** -// * Validation phase -// */ -// if (!trans.validation()) { -// trans.abort(); -// #if SINGLE_EXEC -// #else -// /** -// * Maintenance phase -// */ -// trans.mainte(); -// #endif -// goto RETRY; -// } + // /** + // * Excerpt from original paper 3.1 Multi-Clocks Timestamp Allocation + // * A read-only transaction uses (thread.rts) instead, + // * and does not track or validate the read set; + // */ + // if ((*trans.pro_set_.begin()).ronly_) { + // /** + // * local_commit_counts is used at ../include/backoff.hh to calcurate about + // * backoff. + // */ + // if (trans.is_batch_) { + // storeRelease(myres.local_batch_commit_counts_, + // loadAcquire(myres.local_batch_commit_counts_) + 1); + // } else { + // storeRelease(myres.local_commit_counts_, + // loadAcquire(myres.local_commit_counts_) + 1); + // } + // } else { + // /** + // * Validation phase + // */ + // if (!trans.validation()) { + // trans.abort(); + // #if SINGLE_EXEC + // #else + // /** + // * Maintenance phase + // */ + // trans.mainte(); + // #endif + // goto RETRY; + // } -// /** -// * Write phase -// */ -// trans.writePhase(); -// /** -// * local_commit_counts is used at ../include/backoff.hh to calcurate about -// * backoff. -// */ -// if (trans.is_batch_) { -// storeRelease(myres.local_batch_commit_counts_, -// loadAcquire(myres.local_batch_commit_counts_) + 1); -// } else { -// storeRelease(myres.local_commit_counts_, -// loadAcquire(myres.local_commit_counts_) + 1); -// } + // /** + // * Write phase + // */ + // trans.writePhase(); + // /** + // * local_commit_counts is used at ../include/backoff.hh to calcurate about + // * backoff. + // */ + // if (trans.is_batch_) { + // storeRelease(myres.local_batch_commit_counts_, + // loadAcquire(myres.local_batch_commit_counts_) + 1); + // } else { + // storeRelease(myres.local_commit_counts_, + // loadAcquire(myres.local_commit_counts_) + 1); + // } -// /** -// * Maintenance phase -// */ -// #if SINGLE_EXEC -// #else -// trans.mainte(); -// #endif -// } + // /** + // * Maintenance phase + // */ + // #if SINGLE_EXEC + // #else + // trans.mainte(); + // #endif + // } } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("Cicada benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - YcsbWorkload::makeDB(param); + YcsbWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -240,23 +238,19 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { CicadaResult[0].addLocalAllResult(CicadaResult[i]); } ShowOptParameters(); CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); // TODO: enable this if really necessary // deleteDB(); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/cicada/include/cicada_op_element.hh b/cc/cicada/include/cicada_op_element.hh index 62ebc589..d18eb9ef 100644 --- a/cc/cicada/include/cicada_op_element.hh +++ b/cc/cicada/include/cicada_op_element.hh @@ -4,26 +4,28 @@ #include "version.hh" -template +template class ReadElement : public OpElement { public: using OpElement::OpElement; Version *later_ver_, *ver_; - ReadElement(Storage s, std::string_view key, T *rcdptr, Version *later_ver, Version *ver) - : OpElement::OpElement(s, key, rcdptr) { + ReadElement(Storage s, std::string_view key, T* rcdptr, Version* later_ver, + Version* ver) + : OpElement::OpElement(s, key, rcdptr) { later_ver_ = later_ver; ver_ = ver; } - bool operator<(const ReadElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const ReadElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class WriteElement : public OpElement { public: using OpElement::OpElement; @@ -31,39 +33,46 @@ public: Version *later_ver_, *new_ver_; bool finish_version_install_; - WriteElement(Storage s, std::string_view key, T *rcdptr, Version *later_ver, Version *new_ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + WriteElement(Storage s, std::string_view key, T* rcdptr, Version* later_ver, + Version* new_ver, OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { later_ver_ = later_ver; new_ver_ = new_ver; finish_version_install_ = false; } - WriteElement(Storage s, std::string_view key, T *rcdptr, Version *new_ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + WriteElement(Storage s, std::string_view key, T* rcdptr, Version* new_ver, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { // for insert later_ver_ = nullptr; new_ver_ = new_ver; finish_version_install_ = true; } - bool operator<(const WriteElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const WriteElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class GCElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; uint64_t wts_; - GCElement() : ver_(nullptr), wts_(0) { this->s; this->key_ = ""; } + GCElement() : ver_(nullptr), wts_(0) { + this->s; + this->key_ = ""; + } - GCElement(Storage s, std::string_view key, T *rcdptr, Version *ver, uint64_t wts) - : OpElement::OpElement(s, key, rcdptr) { + GCElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + uint64_t wts) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; this->wts_ = wts; } diff --git a/cc/cicada/include/common.hh b/cc/cicada/include/common.hh index 97e76d96..16b2a15b 100644 --- a/cc/cicada/include/common.hh +++ b/cc/cicada/include/common.hh @@ -29,22 +29,26 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; alignas(CACHE_LINE_SIZE) GLOBAL std::atomic MinRts; alignas(CACHE_LINE_SIZE) GLOBAL std::atomic MinWts; alignas( -CACHE_LINE_SIZE) GLOBAL std::atomic FirstAllocateTimestamp; + CACHE_LINE_SIZE) GLOBAL std::atomic FirstAllocateTimestamp; #if MASSTREE_USE alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #endif #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint64(clocks_per_us, 2100, "CPU_MHz. Use this info for measuring time."); +DEFINE_uint64(clocks_per_us, 2100, + "CPU_MHz. Use this info for measuring time."); DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(gc_inter_us, 10, "GC interval[us]."); DEFINE_uint64(group_commit, 0, "Group commit number of transactions."); -DEFINE_uint64(group_commit_timeout_us, 2, "Timeout used for deadlock resolution when performing group commit[us]."); +DEFINE_uint64( + group_commit_timeout_us, 2, + "Timeout used for deadlock resolution when performing group commit[us]."); DEFINE_uint64(io_time_ns, 5, "Delay inserted instead of IO."); DEFINE_uint64(max_ope, 10, "Total number of operations per single transaction."); -DEFINE_uint64(pre_reserve_version, 10000, "Pre-allocating memory for the version."); +DEFINE_uint64(pre_reserve_version, 10000, + "Pre-allocating memory for the version."); DEFINE_bool(p_wal, false, "Parallel write-ahead logging."); DEFINE_bool(rmw, false, "True means read modify write, false means blind write."); @@ -54,7 +58,8 @@ DEFINE_uint64(thread_num, 10, "Total number of worker threads."); DEFINE_uint64(tuple_num, 1000000, "Total number of records."); DEFINE_bool(ycsb, true, "True uses zipf_skew, false uses faster random generator."); -DEFINE_uint64(worker1_insert_delay_rphase_us, 0, "Worker 1 insert delay in the end of read phase[us]."); +DEFINE_uint64(worker1_insert_delay_rphase_us, 0, + "Worker 1 insert delay in the end of read phase[us]."); DEFINE_double(zipf_skew, 0, "zipf skew. 0 ~ 0.999..."); DEFINE_uint64(ronly_ratio, 0, "ratio of read-only online transaction."); DEFINE_uint64(batch_th_num, 0, "Number of batch worker threads."); @@ -62,8 +67,10 @@ DEFINE_uint64(batch_ratio, 0, "ratio of batch transaction."); DEFINE_uint64(batch_max_ope, 1000, "Total number of operations per single batch transaction."); DEFINE_uint64(batch_rratio, 100, "read ratio of single batch transaction."); -DEFINE_uint64(batch_tuples, 0, "Number of update-only records for batch transaction."); -DEFINE_bool(batch_simple_rr, false, "No one touches update-only records of batch transaction."); +DEFINE_uint64(batch_tuples, 0, + "Number of update-only records for batch transaction."); +DEFINE_bool(batch_simple_rr, false, + "No one touches update-only records of batch transaction."); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(extime); @@ -93,25 +100,25 @@ DECLARE_bool(batch_simple_rr); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThreadWtsArray; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThreadRtsArray; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte - *ThreadRtsArrayForGroup; // グループコミットをする時,これが必要である. +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThreadWtsArray; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThreadRtsArray; +alignas(CACHE_LINE_SIZE) GLOBAL + uint64_t_64byte* ThreadRtsArrayForGroup; // グループコミットをする時,これが必要である. -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GROUP_COMMIT_INDEX; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte - *GROUP_COMMIT_COUNTER; // s-walの時は[0]のみ使用。全スレッドで共有。 +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GROUP_COMMIT_INDEX; +alignas(CACHE_LINE_SIZE) GLOBAL + uint64_t_64byte* GROUP_COMMIT_COUNTER; // s-walの時は[0]のみ使用。全スレッドで共有。 alignas( -CACHE_LINE_SIZE) GLOBAL Version ***PLogSet; // [thID][index] pointer array -alignas(CACHE_LINE_SIZE) GLOBAL Version **SLogSet; // [index] pointer array + CACHE_LINE_SIZE) GLOBAL Version*** PLogSet; // [thID][index] pointer array +alignas(CACHE_LINE_SIZE) GLOBAL Version** SLogSet; // [index] pointer array GLOBAL RWLock SwalLock; GLOBAL RWLock CtrLock; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GCFlag; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GCExecuteFlag; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GCFlag; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GCExecuteFlag; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; alignas(CACHE_LINE_SIZE) GLOBAL uint64_t InitialWts; #define SPIN_WAIT_TIMEOUT_US 2 diff --git a/cc/cicada/include/lock.hh b/cc/cicada/include/lock.hh index 4553d945..dcc5a582 100644 --- a/cc/cicada/include/lock.hh +++ b/cc/cicada/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -40,7 +38,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -56,7 +54,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/cc/cicada/include/result.hh b/cc/cicada/include/result.hh index 009bd5ed..609d0533 100644 --- a/cc/cicada/include/result.hh +++ b/cc/cicada/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector CicadaResult; +extern std::vector CicadaResult; extern void initResult(); diff --git a/cc/cicada/include/scan_callback.hh b/cc/cicada/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/cicada/include/scan_callback.hh +++ b/cc/cicada/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/cicada/include/time_stamp.hh b/cc/cicada/include/time_stamp.hh index 52538215..cd4c8c04 100644 --- a/cc/cicada/include/time_stamp.hh +++ b/cc/cicada/include/time_stamp.hh @@ -14,7 +14,7 @@ public: inline uint64_t get_ts() { return ts_; } - inline void set_ts(uint64_t &ts) { this->ts_ = ts; } + inline void set_ts(uint64_t& ts) { this->ts_ = ts; } inline void set_clockBoost(unsigned int CLOCK_PER_US) { // set 0 or some value equivalent to 1 us. diff --git a/cc/cicada/include/transaction.hh b/cc/cicada/include/transaction.hh index 9dd15a3a..dbaeb1b3 100644 --- a/cc/cicada/include/transaction.hh +++ b/cc/cicada/include/transaction.hh @@ -44,9 +44,9 @@ public: std::unordered_map node_map_; std::deque gc_records_; // for records std::deque> gcq_; // for versions - std::deque reuse_version_from_gc_; + std::deque reuse_version_from_gc_; std::vector pro_set_; - Result *result_ = nullptr; + Result* result_ = nullptr; const bool& quit_; // for thread termination control TxScanCallback callback_; Backoff& backoff_; @@ -57,15 +57,17 @@ public: uint8_t thid_ = 0; uint64_t rts_; - uint64_t start_, stop_; // for one-sided synchronization - uint64_t grpcmt_start_, grpcmt_stop_; // for group commit - uint64_t gcstart_, gcstop_; // for garbage collection + uint64_t start_, stop_; // for one-sided synchronization + uint64_t grpcmt_start_, grpcmt_stop_; // for group commit + uint64_t gcstart_, gcstop_; // for garbage collection - TxExecutor(uint8_t thid, Backoff& backoff, Result *res, const bool &quit) - : result_(res), quit_(quit), callback_(TxScanCallback(this)), backoff_(backoff), thid_(thid) { + TxExecutor(uint8_t thid, Backoff& backoff, Result* res, const bool& quit) + : result_(res), quit_(quit), callback_(TxScanCallback(this)), + backoff_(backoff), thid_(thid) { // wait to initialize MinWts - while (MinWts.load(memory_order_acquire) == 0); + while (MinWts.load(memory_order_acquire) == 0) + ; rts_ = MinWts.load(memory_order_acquire) - 1; wts_.generateTimeStampFirst(thid_); @@ -108,15 +110,15 @@ public: bool chkGcpvTimeout(); - void cpv(); // commit pending versions + void cpv(); // commit pending versions void displayWriteSet(); void earlyAbort(); - void mainte(); // maintenance - void gcpv(); // group commit pending versions - void precpv(); // pre-commit pending versions - void pwal(); // parallel write ahead log. + void mainte(); // maintenance + void gcpv(); // group commit pending versions + void precpv(); // pre-commit pending versions + void pwal(); // parallel write ahead log. void swal(); void begin(); @@ -130,15 +132,13 @@ public: Status delete_record(Storage s, std::string_view key); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); bool validation(); @@ -150,9 +150,9 @@ public: void leaderWork(); - void reconnoiter_begin(); + void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_end(); void gc_records(); @@ -170,27 +170,27 @@ public: #endif } - void gcAfterThisVersion([[maybe_unused]] Tuple *tuple, Version *delTarget) { + void gcAfterThisVersion([[maybe_unused]] Tuple* tuple, Version* delTarget) { while (delTarget != nullptr) { // escape next pointer - Version *tmp = delTarget->next_.load(std::memory_order_acquire); + Version* tmp = delTarget->next_.load(std::memory_order_acquire); #if INLINE_VERSION_OPT if (delTarget == &(tuple->inline_ver_)) { tuple->returnInlineVersionRight(); goto gcAfterThisVersion_NEXT_LOOP; } -#endif // if INLINE_VERSION_OPT +#endif // if INLINE_VERSION_OPT #if REUSE_VERSION reuse_version_from_gc_.emplace_back(delTarget); -#else // if REUSE_VERSION +#else // if REUSE_VERSION delete delTarget; -#endif // if REUSE_VERSION +#endif // if REUSE_VERSION -[[maybe_unused]] gcAfterThisVersion_NEXT_LOOP : + [[maybe_unused]] gcAfterThisVersion_NEXT_LOOP : #if ADD_ANALYSIS - ++result_->local_gc_version_counts_; + ++result_->local_gc_version_counts_; #endif delTarget = tmp; } @@ -214,7 +214,8 @@ public: #endif #endif - Version *newVersionGeneration([[maybe_unused]] Tuple *tuple, TupleBody&& body) { + Version* newVersionGeneration([[maybe_unused]] Tuple* tuple, + TupleBody&& body) { #if INLINE_VERSION_OPT if (tuple->getInlineVersionRight()) { tuple->inline_ver_.set(0, this->wts_.ts_, std::move(body)); @@ -223,7 +224,7 @@ public: #endif return &(tuple->inline_ver_); } -#endif // if INLINE_VERSION_OPT +#endif // if INLINE_VERSION_OPT #if REUSE_VERSION if (!reuse_version_from_gc_.empty()) { @@ -264,7 +265,7 @@ public: if ((*itr).op_ == OpType::INSERT) continue; if ((*itr).rcdptr_->continuing_commit_.load(memory_order_acquire) < CONTINUING_COMMIT_THRESHOLD) { - Version *ver; + Version* ver; if ((*itr).op_ == OpType::RMW || (*itr).op_ == OpType::DELETE) { ver = (*itr).rcdptr_->ldAcqLatest(); if (ver->ldAcqWts() > this->wts_.ts_ || @@ -279,8 +280,8 @@ public: (*itr).later_ver_ = ver; ver = ver->ldAcqNext(); } - while (ver->ldAcqStatus() != VersionStatus::committed - && ver->ldAcqStatus() != VersionStatus::deleted) { + while (ver->ldAcqStatus() != VersionStatus::committed && + ver->ldAcqStatus() != VersionStatus::deleted) { ver = ver->ldAcqNext(); } if (ver->ldAcqRts() > this->wts_.ts_) return false; @@ -313,8 +314,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline ReadElement *searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { + inline ReadElement* searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -330,8 +331,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline WriteElement *searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { + inline WriteElement* searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -366,7 +367,7 @@ public: write_set_.clear(); } - static INLINE Tuple *get_tuple(Tuple *table, uint64_t key) { + static INLINE Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } }; diff --git a/cc/cicada/include/tuple.hh b/cc/cicada/include/tuple.hh index 3b37e797..0cbbd30b 100644 --- a/cc/cicada/include/tuple.hh +++ b/cc/cicada/include/tuple.hh @@ -17,7 +17,7 @@ public: TupleInitParam() { tstmp.generateTimeStampFirst(0); - initial_wts = tstmp.ts_; + initial_wts = tstmp.ts_; } }; @@ -25,17 +25,17 @@ class Tuple { public: alignas(CACHE_LINE_SIZE) #if INLINE_VERSION_OPT - Version inline_ver_; + Version inline_ver_; #endif - atomic latest_; - atomic min_wts_; - atomic continuing_commit_; - atomic gc_lock_; + atomic latest_; + atomic min_wts_; + atomic continuing_commit_; + atomic gc_lock_; TupleBody body_; // only used for index tuple as single version Tuple() : latest_(nullptr), gc_lock_(0) {} - Version *ldAcqLatest() { return latest_.load(std::memory_order_acquire); } + Version* ldAcqLatest() { return latest_.load(std::memory_order_acquire); } bool getGCRight(uint8_t thid) { uint8_t expected, desired(thid); @@ -71,7 +71,8 @@ public: } #endif - void init([[maybe_unused]] size_t thid, TupleBody&& body, TupleInitParam* param) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + TupleInitParam* param) { // for initializer min_wts_ = param->initial_wts; gc_lock_.store(0, std::memory_order_release); @@ -85,7 +86,7 @@ public: #else latest_.store(new Version(), std::memory_order_release); (latest_.load(std::memory_order_acquire)) - ->set(0, param->initial_wts, nullptr, VersionStatus::committed); + ->set(0, param->initial_wts, nullptr, VersionStatus::committed); (latest_.load(std::memory_order_acquire))->body_ = std::move(body); body_ = std::ref((latest_.load(std::memory_order_acquire))->body_); #endif diff --git a/cc/cicada/include/util.hh b/cc/cicada/include/util.hh index c3a459b6..69e5cd38 100644 --- a/cc/cicada/include/util.hh +++ b/cc/cicada/include/util.hh @@ -24,7 +24,7 @@ extern void displayParameter(); extern void cicadaLeaderWork(); -extern void makeDB(uint64_t *initial_wts); +extern void makeDB(uint64_t* initial_wts); extern void partTableDelete([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); diff --git a/cc/cicada/include/version.hh b/cc/cicada/include/version.hh index e6666088..12de93b8 100644 --- a/cc/cicada/include/version.hh +++ b/cc/cicada/include/version.hh @@ -1,7 +1,7 @@ #pragma once #include -#include // memcpy +#include // memcpy #include #include @@ -16,7 +16,7 @@ enum class VersionStatus : uint8_t { invalid, pending, aborted, - precommitted, // now, unuse. + precommitted, // now, unuse. committed, deleted, unused, @@ -24,10 +24,10 @@ enum class VersionStatus : uint8_t { class Version { public: - alignas(CACHE_LINE_SIZE) atomic rts_; - atomic wts_; - atomic next_; - atomic status_; // commit record + alignas(CACHE_LINE_SIZE) atomic rts_; + atomic wts_; + atomic next_; + atomic status_; // commit record TupleBody body_; @@ -44,14 +44,14 @@ public: } Version(const uint64_t rts, const uint64_t wts, TupleBody&& body) - : body_(body) { + : body_(body) { rts_.store(rts, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); status_.store(VersionStatus::pending, memory_order_release); next_.store(nullptr, memory_order_release); } - Version(const uint64_t wts) { + Version(const uint64_t wts) { rts_.store(0, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); status_.store(VersionStatus::pending, memory_order_release); @@ -59,21 +59,20 @@ public: } void displayInfo() { - printf( - "Version::displayInfo(): this: %p rts_: %lu: wts_: %lu: next_: %p: " - "status_: " - "%u\n", - this, ldAcqRts(), ldAcqWts(), ldAcqNext(), (uint8_t) ldAcqStatus()); + printf("Version::displayInfo(): this: %p rts_: %lu: wts_: %lu: next_: %p: " + "status_: " + "%u\n", + this, ldAcqRts(), ldAcqWts(), ldAcqNext(), (uint8_t) ldAcqStatus()); } - Version *latestCommittedVersionAfterThis() { - Version *version = this; + Version* latestCommittedVersionAfterThis() { + Version* version = this; while (version->ldAcqStatus() != VersionStatus::committed) version = version->ldAcqNext(); return version; } - Version *ldAcqNext() { return next_.load(std::memory_order_acquire); } + Version* ldAcqNext() { return next_.load(std::memory_order_acquire); } uint64_t ldAcqRts() { return rts_.load(std::memory_order_acquire); } @@ -91,7 +90,7 @@ public: body_ = std::move(body); } - void set(const uint64_t rts, const uint64_t wts, Version *next, + void set(const uint64_t rts, const uint64_t wts, Version* next, const VersionStatus status) { rts_.store(rts, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); @@ -99,9 +98,9 @@ public: next_.store(next, memory_order_release); } - Version *skipTheStatusVersionAfterThis(const VersionStatus status, + Version* skipTheStatusVersionAfterThis(const VersionStatus status, const bool pendingWait) { - Version *ver = this; + Version* ver = this; VersionStatus local_status = ver->ldAcqStatus(); if (pendingWait) while (local_status == VersionStatus::pending) { @@ -118,20 +117,22 @@ public: return ver; } - Version *skipNotTheStatusVersionAfterThis(const VersionStatus status, + Version* skipNotTheStatusVersionAfterThis(const VersionStatus status, const bool pendingWait) { - Version *ver = this; + Version* ver = this; if (pendingWait) - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; while (ver->ldAcqStatus() != status) { ver = ver->ldAcqNext(); if (pendingWait) - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; } return ver; } - void strRelNext(Version *next) { // store release next = strRelNext + void strRelNext(Version* next) { // store release next = strRelNext next_.store(next, std::memory_order_release); } }; diff --git a/cc/cicada/sbomb_cicada.cc b/cc/cicada/sbomb_cicada.cc index 78041af6..de42a162 100644 --- a/cc/cicada/sbomb_cicada.cc +++ b/cc/cicada/sbomb_cicada.cc @@ -36,10 +36,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &CicadaResult[thid], quit); - StaticBombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &CicadaResult[thid], quit); + StaticBombWorkload workload; workload.prepare(trans, new TupleInitParam()); #ifdef Linux @@ -47,13 +47,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -62,19 +62,19 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB Cicada benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - StaticBombWorkload::makeDB(param); + StaticBombWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -87,24 +87,21 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { CicadaResult[0].addLocalAllResult(CicadaResult[i]); CicadaResult[0].addLocalPerTxResult(CicadaResult[i], TxTypes); } ShowOptParameters(); - CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; CicadaResult[0].displayPerTxResult(TxTypes); // TODO: enable this if really necessary // deleteDB(); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/cicada/testzip.cc b/cc/cicada/testzip.cc index abd8b8c7..d85f3736 100644 --- a/cc/cicada/testzip.cc +++ b/cc/cicada/testzip.cc @@ -10,16 +10,14 @@ using std::cout, std::endl; -int -main() { +int main() { pid_t pid = syscall(SYS_gettid); cpu_set_t cpu_set; CPU_ZERO(&cpu_set); CPU_SET(0, &cpu_set); - if (sched_setaffinity(pid, sizeof(cpu_set_t), &cpu_set) != 0) - ERR; + if (sched_setaffinity(pid, sizeof(cpu_set_t), &cpu_set) != 0) ERR; Xoroshiro128Plus rnd; rnd.init(); @@ -28,12 +26,10 @@ main() { FastZipf zipf(&rnd, 0, 10); // warm up - for (int i = 0; i < 100; ++i) - start = rnd.next(); + for (int i = 0; i < 100; ++i) start = rnd.next(); start = rdtscp(); - for (int i = 0; i < 1000000; ++i) - rnd.next(); + for (int i = 0; i < 1000000; ++i) rnd.next(); stop = rdtscp(); cout << "xoroshiro : " << (stop - start) / 1000000 << endl; @@ -48,11 +44,9 @@ main() { // cout << zipf() << endl; int ary[10] = {}; - for (uint i = 0; i < 10000; ++i) - ++ary[zipf()]; + for (uint i = 0; i < 10000; ++i) ++ary[zipf()]; - for (uint i = 0; i < 10; ++i) - cout << "ary[" << i << "] = " << ary[i] << endl; + for (uint i = 0; i < 10; ++i) cout << "ary[" << i << "] = " << ary[i] << endl; return 0; } diff --git a/cc/cicada/tpcc_cicada.cc b/cc/cicada/tpcc_cicada.cc index f8603935..c7e61b1f 100644 --- a/cc/cicada/tpcc_cicada.cc +++ b/cc/cicada/tpcc_cicada.cc @@ -36,10 +36,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &CicadaResult[thid], quit); - TPCCWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &CicadaResult[thid], quit); + TPCCWorkload workload; workload.prepare(trans, new TupleInitParam()); #ifdef Linux @@ -47,13 +47,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -62,19 +62,19 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C Cicada benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - TPCCWorkload::makeDB(param); + TPCCWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -87,24 +87,21 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { CicadaResult[0].addLocalAllResult(CicadaResult[i]); CicadaResult[0].addLocalPerTxResult(CicadaResult[i], TxTypes); } ShowOptParameters(); - CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; CicadaResult[0].displayPerTxResult(TxTypes); // TODO: enable this if really necessary // deleteDB(); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/cicada/transaction.cc b/cc/cicada/transaction.cc index d6ab426f..22eb12d1 100644 --- a/cc/cicada/transaction.cc +++ b/cc/cicada/transaction.cc @@ -16,7 +16,8 @@ #include "../../include/masstree_wrapper.hh" #include "../../include/tsc.hh" -extern bool chkClkSpan(const uint64_t start, const uint64_t stop, const uint64_t threshold); +extern bool chkClkSpan(const uint64_t start, const uint64_t stop, + const uint64_t threshold); extern void displaySLogSet(); extern void displayDB(); extern void cicadaLeaderWork(); @@ -76,7 +77,8 @@ void TxExecutor::begin() { */ } -Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Version* TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { // Search version Version *ver, *later_ver; later_ver = nullptr; @@ -104,13 +106,12 @@ Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple ver = ver->ldAcqNext(); if (ver == nullptr) return nullptr; } - while (ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { + while (ver->status_.load(memory_order_acquire) != VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { /** * Wait for the result of the pending version in the view. */ - while (ver->status_.load(memory_order_acquire) == VersionStatus::pending) { - } + while (ver->status_.load(memory_order_acquire) == VersionStatus::pending) {} if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { ver = ver->ldAcqNext(); } @@ -129,10 +130,10 @@ Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple #if INLINE_VERSION_PROMOTION #if ADD_ANALYSIS result_->local_read_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS inlineVersionPromotion(s, key, tuple, later_ver, ver); -#endif // if INLINE_VERSION_PROMOTION -#endif // if INLINE_VERSION_OPT +#endif // if INLINE_VERSION_PROMOTION +#endif // if INLINE_VERSION_OPT return ver; } @@ -144,7 +145,7 @@ Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS Version* ver; ReadElement* re; @@ -167,11 +168,11 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search versions from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; ver = read_internal(s, key, tuple); @@ -196,7 +197,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS /** * Update from local write set. @@ -204,10 +205,10 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { */ if (searchWriteSet(s, key)) goto FINISH_WRITE; - Tuple *tuple; + Tuple* tuple; bool rmw; rmw = false; - ReadElement *re; + ReadElement* re; re = searchReadSet(s, key); if (re) { /** @@ -228,7 +229,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } @@ -282,16 +283,17 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { goto FINISH_WRITE; } - Version *new_ver; + Version* new_ver; new_ver = newVersionGeneration(tuple, std::move(body)); - write_set_.emplace_back(s, key, tuple, later_ver, new_ver, rmw? OpType::RMW : OpType::UPDATE); -#endif // if SINGLE_EXEC + write_set_.emplace_back(s, key, tuple, later_ver, new_ver, + rmw ? OpType::RMW : OpType::UPDATE); +#endif // if SINGLE_EXEC FINISH_WRITE: #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } @@ -299,7 +301,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; @@ -307,23 +309,22 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); - Version *new_ver = newVersionGeneration(tuple, std::move(body)); + Version* new_ver = newVersionGeneration(tuple, std::move(body)); tuple->init(this->thid_, new_ver, this->wts_.ts_, std::move(body)); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -341,25 +342,23 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } Status TxExecutor::delete_record(Storage s, std::string_view key) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple; - ReadElement *re; + ReadElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -367,7 +366,7 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } @@ -398,39 +397,37 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { goto FINISH_DELETE; } - Version *new_ver; + Version* new_ver; new_ver = new Version(this->wts_.ts_); write_set_.emplace_back(s, key, tuple, later_ver, new_ver, OpType::DELETE); FINISH_DELETE: #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { // TODO: Tuple should have key? Accessing key through the latest ver is ugly // Must be a copy to avoid buffer overflow when changing the latest std::string key(itr->latest_.load(memory_order_acquire)->body_.get_key()); @@ -449,14 +446,14 @@ Status TxExecutor::scan(const Storage s, // read_internal pushes the visible version into read_set_ on success; // the caller appends from read_set_ at the bottom of scan(). The return // value is only useful for in-place reads, which scan() does not need. - (void)read_internal(s, key, itr); + (void) read_internal(s, key, itr); if (this->status_ == TransactionStatus::aborted) return Status::ERROR_PREEMPTIVE_ABORT; } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).ver_->body_)); } } @@ -467,7 +464,7 @@ Status TxExecutor::scan(const Storage s, bool TxExecutor::validation() { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS /** * Sort write set by contention. @@ -483,9 +480,7 @@ bool TxExecutor::validation() { * Install pending version */ for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - if ((*itr).op_ == OpType::INSERT) { - continue; - } + if ((*itr).op_ == OpType::INSERT) { continue; } // pre_ver is only read on the else branch below, which is reachable // only after the while-loop has assigned to it — but GCC 13 cannot // prove that across the (op != RMW && op != DELETE && !WRITE_LATEST_ONLY @@ -493,7 +488,8 @@ bool TxExecutor::validation() { // without changing runtime behavior. Version *expected(nullptr), *ver, *pre_ver = nullptr; for (;;) { - if ((*itr).op_ == OpType::RMW || (*itr).op_ == OpType::DELETE || WRITE_LATEST_ONLY) { + if ((*itr).op_ == OpType::RMW || (*itr).op_ == OpType::DELETE || + WRITE_LATEST_ONLY) { ver = expected = (*itr).rcdptr_->ldAcqLatest(); if (this->wts_.ts_ < ver->ldAcqWts()) { result = false; @@ -513,8 +509,8 @@ bool TxExecutor::validation() { } } - if ((*itr).op_ == OpType::RMW || (*itr).op_ == OpType::DELETE - || WRITE_LATEST_ONLY || ver == expected) { + if ((*itr).op_ == OpType::RMW || (*itr).op_ == OpType::DELETE || + WRITE_LATEST_ONLY || ver == expected) { // Latter half of condition meanings that it was not traversaling // version list in not rmw mode. (*itr).new_ver_->strRelNext(expected); @@ -546,7 +542,7 @@ bool TxExecutor::validation() { * currently visible version to the transaction. */ for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { - Version *ver; + Version* ver; if ((*itr).later_ver_) ver = (*itr).later_ver_; else @@ -555,11 +551,13 @@ bool TxExecutor::validation() { while (ver->ldAcqWts() >= this->wts_.ts_) ver = ver->ldAcqNext(); // if write after read occured, it may happen "==". - while (ver->ldAcqStatus() == VersionStatus::pending); - while (ver->ldAcqStatus() != VersionStatus::committed - && ver->ldAcqStatus() != VersionStatus::deleted) { + while (ver->ldAcqStatus() == VersionStatus::pending) + ; + while (ver->ldAcqStatus() != VersionStatus::committed && + ver->ldAcqStatus() != VersionStatus::deleted) { ver = ver->ldAcqNext(); - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; } /** * This part is different from the original. @@ -577,18 +575,19 @@ bool TxExecutor::validation() { * satisfies (v.rts) <= (tx.ts) */ for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - if ((*itr).op_ == OpType::INSERT) { - continue; - } - Version *ver = (*itr).new_ver_->ldAcqNext(); - while (ver->ldAcqStatus() == VersionStatus::pending); - while (ver->ldAcqStatus() != VersionStatus::committed - && ver->ldAcqStatus() != VersionStatus::deleted) { + if ((*itr).op_ == OpType::INSERT) { continue; } + Version* ver = (*itr).new_ver_->ldAcqNext(); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; + while (ver->ldAcqStatus() != VersionStatus::committed && + ver->ldAcqStatus() != VersionStatus::deleted) { ver = ver->ldAcqNext(); - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; } - if (ver->ldAcqRts() > this->wts_.ts_ || ver->ldAcqStatus() == VersionStatus::deleted) { + if (ver->ldAcqRts() > this->wts_.ts_ || + ver->ldAcqStatus() == VersionStatus::deleted) { result = false; goto FINISH_VALIDATION; } @@ -596,7 +595,7 @@ bool TxExecutor::validation() { // validate the node set for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { result = false; goto FINISH_VALIDATION; @@ -606,12 +605,12 @@ bool TxExecutor::validation() { FINISH_VALIDATION: #if ADD_ANALYSIS result_->local_vali_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return result; } void TxExecutor::swal() { - if (!FLAGS_group_commit) { // non-group commit + if (!FLAGS_group_commit) { // non-group commit SwalLock.w_lock(); int i = 0; @@ -622,11 +621,10 @@ void TxExecutor::swal() { double threshold = FLAGS_clocks_per_us * FLAGS_io_time_ns / 1000; uint64_t spinstart = rdtscp(); - while ((rdtscp() - spinstart) < threshold) { - } // spin-wait + while ((rdtscp() - spinstart) < threshold) {} // spin-wait SwalLock.w_unlock(); - } else { // group commit + } else { // group commit SwalLock.w_lock(); for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { SLogSet[GROUP_COMMIT_INDEX[0].obj_] = (*itr).new_ver_; @@ -634,7 +632,7 @@ void TxExecutor::swal() { } if (GROUP_COMMIT_COUNTER[0].obj_ == 0) { - grpcmt_start_ = rdtscp(); // it can also initialize. + grpcmt_start_ = rdtscp(); // it can also initialize. } ++GROUP_COMMIT_COUNTER[0].obj_; @@ -642,8 +640,7 @@ void TxExecutor::swal() { if (GROUP_COMMIT_COUNTER[0].obj_ == FLAGS_group_commit) { double threshold = FLAGS_clocks_per_us * FLAGS_io_time_ns / 1000; uint64_t spinstart = rdtscp(); - while ((rdtscp() - spinstart) < threshold) { - } // spin-wait + while ((rdtscp() - spinstart) < threshold) {} // spin-wait // group commit pending version. gcpv(); @@ -663,8 +660,7 @@ void TxExecutor::pwal() { // it gives lat ency instead of flush. double threshold = FLAGS_clocks_per_us * FLAGS_io_time_ns / 1000; uint64_t spinstart = rdtscp(); - while ((rdtscp() - spinstart) < threshold) { - } // spin-wait + while ((rdtscp() - spinstart) < threshold) {} // spin-wait } else { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { PLogSet[thid_][GROUP_COMMIT_INDEX[thid_].obj_] = (*itr).new_ver_; @@ -672,7 +668,7 @@ void TxExecutor::pwal() { } if (GROUP_COMMIT_COUNTER[this->thid_].obj_ == 0) { - grpcmt_start_ = rdtscp(); // it can also initialize. + grpcmt_start_ = rdtscp(); // it can also initialize. ThreadRtsArrayForGroup[this->thid_].obj_ = this->rts_; } @@ -682,15 +678,14 @@ void TxExecutor::pwal() { // it gives latency instead of flush. double threshold = FLAGS_clocks_per_us * FLAGS_io_time_ns / 1000; uint64_t spinstart = rdtscp(); - while ((rdtscp() - spinstart) < threshold) { - } // spin-wait + while ((rdtscp() - spinstart) < threshold) {} // spin-wait gcpv(); } } } -inline void TxExecutor::cpv() // commit pending versions +inline void TxExecutor::cpv() // commit pending versions { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { /* memcpy は commit 確定前に書くことと,確定後に書くことができる. @@ -713,13 +708,15 @@ inline void TxExecutor::cpv() // commit pending versions #endif if ((*itr).op_ == OpType::DELETE) { Masstrees[get_storage((*itr).storage_)].remove_value((*itr).key_); - (*itr).new_ver_->status_.store(VersionStatus::deleted, std::memory_order_release); + (*itr).new_ver_->status_.store(VersionStatus::deleted, + std::memory_order_release); gc_records_.push_back((*itr).rcdptr_); } else { - (*itr).new_ver_->status_.store(VersionStatus::committed, std::memory_order_release); + (*itr).new_ver_->status_.store(VersionStatus::committed, + std::memory_order_release); } - gcq_.emplace_back(GCElement((*itr).storage_, (*itr).key_, - (*itr).rcdptr_, (*itr).new_ver_, this->wts_.ts_)); + gcq_.emplace_back(GCElement((*itr).storage_, (*itr).key_, (*itr).rcdptr_, + (*itr).new_ver_, this->wts_.ts_)); ++(*itr).rcdptr_->continuing_commit_; } } @@ -759,9 +756,7 @@ void TxExecutor::abort() { read_set_.clear(); node_map_.clear(); - if (FLAGS_group_commit) { - chkGcpvTimeout(); - } + if (FLAGS_group_commit) { chkGcpvTimeout(); } this->wts_.set_clockBoost(FLAGS_clocks_per_us); @@ -824,7 +819,7 @@ void TxExecutor::gc_versions() { continue; } - Tuple *tuple = gcq_.front().rcdptr_; + Tuple* tuple = gcq_.front().rcdptr_; // (b) v.wts > record.min_wts if (gcq_.front().wts_ <= tuple->min_wts_) { // releases the lock @@ -834,8 +829,8 @@ void TxExecutor::gc_versions() { } // this pointer may be dangling. - Version *delTarget = - gcq_.front().ver_->next_.load(std::memory_order_acquire); + Version* delTarget = + gcq_.front().ver_->next_.load(std::memory_order_acquire); // the thread detaches the rest of the version list from v gcq_.front().ver_->next_.store(nullptr, std::memory_order_release); @@ -886,7 +881,8 @@ void TxExecutor::mainte() { } this->gcstop_ = rdtscp(); - if (chkClkSpan(this->gcstart_, this->gcstop_, FLAGS_gc_inter_us * FLAGS_clocks_per_us) && + if (chkClkSpan(this->gcstart_, this->gcstop_, + FLAGS_gc_inter_us * FLAGS_clocks_per_us) && (loadAcquire(GCFlag[thid_].obj_) == 0)) { storeRelease(GCFlag[thid_].obj_, 1); this->gcstart_ = this->gcstop_; @@ -944,9 +940,7 @@ bool TxExecutor::commit() { /** * Validation phase */ - if (!validation()) { - return false; - } + if (!validation()) { return false; } /** * Write phase @@ -964,9 +958,7 @@ bool TxExecutor::commit() { } } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { cicadaLeaderWork(); @@ -975,9 +967,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); @@ -986,10 +976,11 @@ void TxExecutor::reconnoiter_end() { begin(); } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/cicada/util.cc b/cc/cicada/util.cc index 61fce07d..1cc276f3 100644 --- a/cc/cicada/util.cc +++ b/cc/cicada/util.cc @@ -1,7 +1,7 @@ #include #include #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include #include @@ -35,33 +35,33 @@ void chkArg() { exit(0); } - if (posix_memalign((void **) &ThreadRtsArrayForGroup, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadRtsArrayForGroup, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &ThreadWtsArray, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadWtsArray, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &ThreadRtsArray, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadRtsArray, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GROUP_COMMIT_INDEX, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GROUP_COMMIT_INDEX, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GROUP_COMMIT_COUNTER, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GROUP_COMMIT_COUNTER, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GCFlag, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GCFlag, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GCExecuteFlag, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GCExecuteFlag, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - SLogSet = new Version *[(FLAGS_max_ope) * (FLAGS_group_commit)]; - PLogSet = new Version **[TotalThreadNum]; + SLogSet = new Version*[(FLAGS_max_ope) * (FLAGS_group_commit)]; + PLogSet = new Version**[TotalThreadNum]; for (unsigned int i = 0; i < TotalThreadNum; ++i) { - PLogSet[i] = new Version *[(FLAGS_max_ope) * (FLAGS_group_commit)]; + PLogSet[i] = new Version*[(FLAGS_max_ope) * (FLAGS_group_commit)]; } // init @@ -133,14 +133,17 @@ void displayParameter() { cout << "#FLAGS_extime:\t\t\t\t" << FLAGS_extime << endl; cout << "#FLAGS_gc_inter_us:\t\t\t" << FLAGS_gc_inter_us << endl; cout << "#FLAGS_group_commit:\t\t\t" << FLAGS_group_commit << endl; - cout << "#FLAGS_group_commit_timeout_us:\t\t" << FLAGS_group_commit_timeout_us << endl; + cout << "#FLAGS_group_commit_timeout_us:\t\t" << FLAGS_group_commit_timeout_us + << endl; cout << "#FLAGS_io_time_ns:\t\t\t" << FLAGS_io_time_ns << endl; - cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version << endl; + cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version + << endl; cout << "#FLAGS_p_wal:\t\t\t\t" << FLAGS_p_wal << endl; cout << "#FLAGS_s_wal:\t\t\t\t" << FLAGS_s_wal << endl; cout << "#FLAGS_thread_num:\t\t\t" << FLAGS_thread_num << endl; cout << "#FLAGS_ycsb:\t\t\t\t" << FLAGS_ycsb << endl; - cout << "#FLAGS_worker1_insert_delay_rphase_us:\t" << FLAGS_worker1_insert_delay_rphase_us << endl; + cout << "#FLAGS_worker1_insert_delay_rphase_us:\t" + << FLAGS_worker1_insert_delay_rphase_us << endl; if (FLAGS_batch_th_num > 0 || FLAGS_batch_ratio > 0) { cout << "#FLAGS_batch_th_num:\t\t\t" << FLAGS_batch_th_num << endl; cout << "#FLAGS_batch_ratio:\t\t\t" << FLAGS_batch_ratio << endl; @@ -216,9 +219,9 @@ void displayThreadRtsArray() { void partTableDelete([[maybe_unused]] size_t thid, uint64_t start, uint64_t end) { for (uint64_t i = start; i <= end; ++i) { - Tuple *tuple; + Tuple* tuple; tuple = TxExecutor::get_tuple(Table, i); - Version *ver = tuple->latest_; + Version* ver = tuple->latest_; while (ver != nullptr) { #if INLINE_VERSION_OPT if (ver == &tuple->inline_ver_) { @@ -226,7 +229,7 @@ void partTableDelete([[maybe_unused]] size_t thid, uint64_t start, continue; } #endif - Version *del = ver; + Version* del = ver; ver = ver->next_.load(memory_order_acquire); delete del; } @@ -239,7 +242,7 @@ void deleteDB() { for (size_t i = 0; i < maxthread; ++i) thv.emplace_back(partTableDelete, i, i * (FLAGS_tuple_num / maxthread), (i + 1) * (FLAGS_tuple_num / maxthread) - 1); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); delete Table; delete ThreadRtsArrayForGroup; @@ -286,18 +289,18 @@ void cicadaLeaderWork() { } if (gc_update) { uint64_t minw = - __atomic_load_n(&(ThreadWtsArray[0].obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(ThreadWtsArray[0].obj_), __ATOMIC_ACQUIRE); uint64_t minr; if (FLAGS_group_commit == 0) { minr = __atomic_load_n(&(ThreadRtsArray[0].obj_), __ATOMIC_ACQUIRE); } else { minr = - __atomic_load_n(&(ThreadRtsArrayForGroup[0].obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(ThreadRtsArrayForGroup[0].obj_), __ATOMIC_ACQUIRE); } for (unsigned int i = 1; i < TotalThreadNum; ++i) { uint64_t tmp = - __atomic_load_n(&(ThreadWtsArray[i].obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(ThreadWtsArray[i].obj_), __ATOMIC_ACQUIRE); if (minw > tmp) minw = tmp; if (FLAGS_group_commit == 0) { tmp = __atomic_load_n(&(ThreadRtsArray[i].obj_), __ATOMIC_ACQUIRE); diff --git a/cc/cicada/ycsb_cicada.cc b/cc/cicada/ycsb_cicada.cc index e4f55603..6460853c 100644 --- a/cc/cicada/ycsb_cicada.cc +++ b/cc/cicada/ycsb_cicada.cc @@ -36,40 +36,40 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { YcsbWorkload workload; Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &CicadaResult[thid], quit); + TxExecutor trans(thid, backoff, (Result*) &CicadaResult[thid], quit); #ifdef Linux setThreadAffinity(thid); // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("YCSB Cicada benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - YcsbWorkload::makeDB(param); + YcsbWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -82,23 +82,19 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { CicadaResult[0].addLocalAllResult(CicadaResult[i]); } ShowOptParameters(); CicadaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); // TODO: enable this if really necessary // deleteDB(); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/d2pl/dbomb_d2pl.cc b/cc/d2pl/dbomb_d2pl.cc index a1969d38..f2f1a422 100644 --- a/cc/d2pl/dbomb_d2pl.cc +++ b/cc/d2pl/dbomb_d2pl.cc @@ -34,10 +34,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(D2PLResult[thid]); - TxExecutor trans(thid, (Result*)&myres, quit); - DeterministicBombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(D2PLResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + DeterministicBombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -57,18 +57,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("Determinisitc BOMB D2PL benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - DeterministicBombWorkload::displayWorkloadParameter(); - DeterministicBombWorkload::makeDB(nullptr); + DeterministicBombWorkload::displayWorkloadParameter(); + DeterministicBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -76,25 +76,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { D2PLResult[0].addLocalAllResult(D2PLResult[i]); @@ -102,11 +100,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - D2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + D2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; D2PLResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/d2pl/include/common.hh b/cc/d2pl/include/common.hh index e69ebc8b..9a171399 100644 --- a/cc/d2pl/include/common.hh +++ b/cc/d2pl/include/common.hh @@ -54,4 +54,4 @@ DECLARE_double(zipf_skew); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; diff --git a/cc/d2pl/include/d2pl_op_element.hh b/cc/d2pl/include/d2pl_op_element.hh index 91407834..ce7ae300 100644 --- a/cc/d2pl/include/d2pl_op_element.hh +++ b/cc/d2pl/include/d2pl_op_element.hh @@ -2,26 +2,28 @@ #include "../../../include/op_element.hh" -template +template class SetElement : public OpElement { public: using OpElement::OpElement; TupleBody body_; - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body) - : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) {} + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body) + : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) {} - SetElement(Storage s, std::string_view key, T *rcdptr) - : OpElement::OpElement(s, key, rcdptr) {} + SetElement(Storage s, std::string_view key, T* rcdptr) + : OpElement::OpElement(s, key, rcdptr) {} - SetElement(Storage s, std::string_view key, T *rcdptr, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) {} + SetElement(Storage s, std::string_view key, T* rcdptr, OpType op) + : OpElement::OpElement(s, key, rcdptr, op) {} - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body, OpType op) - : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) {} + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) {} - bool operator<(const SetElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const SetElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; diff --git a/cc/d2pl/include/result.hh b/cc/d2pl/include/result.hh index b07f30d6..0c9d0fcf 100644 --- a/cc/d2pl/include/result.hh +++ b/cc/d2pl/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector D2PLResult; +extern std::vector D2PLResult; extern void initResult(); diff --git a/cc/d2pl/include/transaction.hh b/cc/d2pl/include/transaction.hh index cbc9dbd0..8389e63c 100644 --- a/cc/d2pl/include/transaction.hh +++ b/cc/d2pl/include/transaction.hh @@ -22,19 +22,19 @@ enum class TransactionStatus : uint8_t { aborted, }; -extern void writeValGenerator(char *writeVal, size_t val_size, size_t thid); +extern void writeValGenerator(char* writeVal, size_t val_size, size_t thid); class TxExecutor { public: alignas(CACHE_LINE_SIZE) int thid_; - std::vector r_lock_list_; - std::vector w_lock_list_; + std::vector r_lock_list_; + std::vector w_lock_list_; TransactionStatus status_ = TransactionStatus::inflight; - Result *result_; + Result* result_; Backoff backoff_; - vector > read_set_; - vector > write_set_; - vector pro_set_; + vector> read_set_; + vector> write_set_; + vector pro_set_; std::deque gc_records_; const bool& quit_; // for thread termination control bool reconnoitering_ = false; @@ -49,14 +49,15 @@ public: key_ = key; is_exclusive_ = is_exclusive; } - bool operator<(const LockEntry &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const LockEntry& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; std::vector lock_entries_; - TxExecutor(int thid, Result *res, const bool &quit) + TxExecutor(int thid, Result* res, const bool& quit) : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit) { // read_set_.reserve(FLAGS_max_ope); // write_set_.reserve(FLAGS_max_ope); @@ -65,9 +66,9 @@ public: // w_lock_list_.reserve(FLAGS_max_ope); } - SetElement *searchReadSet(Storage s, std::string_view key); + SetElement* searchReadSet(Storage s, std::string_view key); - SetElement *searchWriteSet(Storage s, std::string_view key); + SetElement* searchWriteSet(Storage s, std::string_view key); void begin(); @@ -75,15 +76,13 @@ public: Status read(Storage s, std::string_view key, TupleBody** body); void read_internal(Storage s, std::string_view key, Tuple* tuple); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); void write(uint64_t key); Status update(Storage s, std::string_view key, TupleBody&& body); @@ -107,13 +106,13 @@ public: void leaderWork(); void gc_records(); - + void reconnoiter_begin(); void reconnoiter_end(); // inline - Tuple *get_tuple(Tuple *table, uint64_t key) { return &table[key]; } + Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } }; static_assert(TxExecutorLike); diff --git a/cc/d2pl/include/tuple.hh b/cc/d2pl/include/tuple.hh index a77e7837..ff0ee789 100644 --- a/cc/d2pl/include/tuple.hh +++ b/cc/d2pl/include/tuple.hh @@ -17,7 +17,8 @@ public: Tuple() {} - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* p) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* p) { body_ = std::move(body); } diff --git a/cc/d2pl/include/util.hh b/cc/d2pl/include/util.hh index 547508fa..a768dac1 100644 --- a/cc/d2pl/include/util.hh +++ b/cc/d2pl/include/util.hh @@ -8,6 +8,7 @@ extern void displayParameter(); extern void makeDB(); -extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); +extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, + uint64_t end); extern void ShowOptParameters(); diff --git a/cc/d2pl/sbomb_d2pl.cc b/cc/d2pl/sbomb_d2pl.cc index 8f27539a..90abe1ae 100644 --- a/cc/d2pl/sbomb_d2pl.cc +++ b/cc/d2pl/sbomb_d2pl.cc @@ -34,10 +34,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(D2PLResult[thid]); - TxExecutor trans(thid, (Result*)&myres, quit); - DeterministicSbombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(D2PLResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + DeterministicSbombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -57,18 +57,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("Determinisitc BOMB D2PL benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - DeterministicSbombWorkload::displayWorkloadParameter(); - DeterministicSbombWorkload::makeDB(nullptr); + DeterministicSbombWorkload::displayWorkloadParameter(); + DeterministicSbombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -76,25 +76,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { D2PLResult[0].addLocalAllResult(D2PLResult[i]); @@ -102,11 +100,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - D2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + D2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; D2PLResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/d2pl/transaction.cc b/cc/d2pl/transaction.cc index 3b3fa371..fb7292e5 100644 --- a/cc/d2pl/transaction.cc +++ b/cc/d2pl/transaction.cc @@ -13,10 +13,10 @@ using namespace std; -extern void display_procedure_vector(std::vector &pro); +extern void display_procedure_vector(std::vector& pro); -SetElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { +SetElement* TxExecutor::searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -24,8 +24,8 @@ SetElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { return nullptr; } -SetElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { +SetElement* TxExecutor::searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -75,8 +75,8 @@ bool TxExecutor::commit() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { switch ((*itr).op_) { case OpType::UPDATE: { - memcpy((*itr).rcdptr_->body_.get_val_ptr(), - (*itr).body_.get_val_ptr(), (*itr).body_.get_val_size()); + memcpy((*itr).rcdptr_->body_.get_val_ptr(), (*itr).body_.get_val_ptr(), + (*itr).body_.get_val_size()); break; } case OpType::INSERT: { @@ -85,7 +85,8 @@ bool TxExecutor::commit() { case OpType::DELETE: { // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present( + (*itr).key_); // create information for garbage collection gc_records_.push_back((*itr).rcdptr_); break; @@ -123,7 +124,7 @@ void TxExecutor::begin() { this->status_ = TransactionStatus::inflight; } Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // ADD_ANALYSIS +#endif // ADD_ANALYSIS TupleBody b; SetElement* e; @@ -144,7 +145,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -168,31 +169,31 @@ void TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { /** * read payload. */ - body = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), tuple->body_.get_val_align()); + body = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), + tuple->body_.get_val_align()); read_set_.emplace_back(s, key, tuple, std::move(body)); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { SetElement* e = searchReadSet(s, itr->body_.get_key()); if (e) { result.emplace_back(&(e->body_)); @@ -209,8 +210,8 @@ Status TxExecutor::scan(const Storage s, } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).body_)); } } @@ -234,10 +235,10 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS - ++result_->local_tree_traversal_; + ++result_->local_tree_traversal_; #endif if (tuple == nullptr) return Status::WARN_NOT_FOUND; @@ -246,7 +247,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { FINISH_WRITE: #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // ADD_ANALYSIS +#endif // ADD_ANALYSIS return Status::OK; } @@ -261,9 +262,7 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(std::move(body)); @@ -291,18 +290,14 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple == nullptr) { - return Status::WARN_NOT_FOUND; - } + if (tuple == nullptr) { return Status::WARN_NOT_FOUND; } write_set_.emplace_back(s, key, tuple, OpType::DELETE); @@ -319,11 +314,12 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { bool TxExecutor::lockList() { std::sort(lock_entries_.begin(), lock_entries_.end()); for (auto& le : lock_entries_) { - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(le.storage_)].get_value(le.key_); if (tuple == nullptr) { std::stringstream ss; - ss << "WARN: key not found " << (uint32_t)le.storage_ << " " << str_view_hex(le.key_); + ss << "WARN: key not found " << (uint32_t) le.storage_ << " " + << str_view_hex(le.key_); dump(thid_, ss.str()); return false; } @@ -350,8 +346,8 @@ void TxExecutor::unlockList() { for (auto itr = w_lock_list_.begin(); itr != w_lock_list_.end(); ++itr) { // if (thid_ == 2) { - // std::stringstream ss; ss << "unlock: " << (*itr); - // dump(thid_, ss.str()); + // std::stringstream ss; ss << "unlock: " << (*itr); + // dump(thid_, ss.str()); // } (*itr)->w_unlock(); } @@ -365,19 +361,15 @@ void TxExecutor::unlockList() { lock_entries_.clear(); } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { - read_set_.clear(); - reconnoitering_ = false; - begin(); + read_set_.clear(); + reconnoitering_ = false; + begin(); } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { #if BACK_OFF diff --git a/cc/d2pl/util.cc b/cc/d2pl/util.cc index d1ad2290..3d4baa53 100644 --- a/cc/d2pl/util.cc +++ b/cc/d2pl/util.cc @@ -1,8 +1,8 @@ #include -#include // syscall(SYS_gettid), -#include // syscall(SSY_gettid), -#include // syscall(SSY_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SSY_gettid), +#include // syscall(SSY_gettid), #include #include @@ -30,9 +30,7 @@ void chkArg() { TotalThreadNum = FLAGS_thread_num; - if (FLAGS_rratio > 100) { - ERR; - } + if (FLAGS_rratio > 100) { ERR; } if (FLAGS_clocks_per_us < 100) { cout << "CPU_MHZ is less than 100. are your really?" << endl; @@ -52,14 +50,9 @@ void displayParameter() { cout << "#FLAGS_zipf_skew:\t" << FLAGS_zipf_skew << endl; } -void -ShowOptParameters() { +void ShowOptParameters() { cout << "#ShowOptParameters()" - << ": ADD_ANALYSIS " << ADD_ANALYSIS - << ": BACK_OFF " << BACK_OFF - << ": MASSTREE_USE " << MASSTREE_USE - << ": KEY_SIZE " << KEY_SIZE - << ": KEY_SORT " << KEY_SORT - << ": VAL_SIZE " << VAL_SIZE - << endl; + << ": ADD_ANALYSIS " << ADD_ANALYSIS << ": BACK_OFF " << BACK_OFF + << ": MASSTREE_USE " << MASSTREE_USE << ": KEY_SIZE " << KEY_SIZE + << ": KEY_SORT " << KEY_SORT << ": VAL_SIZE " << VAL_SIZE << endl; } diff --git a/cc/ermia/bomb_ermia.cc b/cc/ermia/bomb_ermia.cc index ce832501..bbba6b10 100644 --- a/cc/ermia/bomb_ermia.cc +++ b/cc/ermia/bomb_ermia.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &ErmiaResult[thid], quit); - BombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &ErmiaResult[thid], quit); + BombWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB ERMIA benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -75,25 +75,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -102,11 +100,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; ErmiaResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ermia/ermia.cc b/cc/ermia/ermia.cc index d51cc0ee..eed065b7 100644 --- a/cc/ermia/ermia.cc +++ b/cc/ermia/ermia.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -31,11 +31,11 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - TxExecutor trans(thid, (Result *) &ErmiaResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + TxExecutor trans(thid, (Result*) &ErmiaResult[thid]); Xoroshiro128Plus rnd; rnd.init(); - Result &myres = std::ref(ErmiaResult[thid]); + Result& myres = std::ref(ErmiaResult[thid]); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); GarbageCollection gcob; /** @@ -52,13 +52,11 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); uint64_t tuples = FLAGS_tuple_num; - if (FLAGS_batch_simple_rr) { - tuples = FLAGS_tuple_num - FLAGS_batch_tuples; - } + if (FLAGS_batch_simple_rr) { tuples = FLAGS_tuple_num - FLAGS_batch_tuples; } if (thid == 0) gcob.decideFirstRange(); storeRelease(ready, 1); @@ -66,14 +64,14 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { trans.gcstart_ = rdtscp(); while (!loadAcquire(quit)) { auto r = rnd.next() % 100; - if ((FLAGS_thread_num && thid >= FLAGS_thread_num) - || (r < FLAGS_batch_ratio)) { + if ((FLAGS_thread_num && thid >= FLAGS_thread_num) || + (r < FLAGS_batch_ratio)) { trans.is_batch_ = true; - makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, - FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, - myres); - } else if (r >= FLAGS_batch_ratio - && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, + FLAGS_batch_tuples, FLAGS_batch_max_ope, + FLAGS_batch_rratio, FLAGS_rmw, myres); + } else if (r >= FLAGS_batch_ratio && + r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { trans.is_batch_ = false; makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, FLAGS_max_ope, myres); @@ -83,7 +81,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, thid, myres); } -RETRY: + RETRY: if (thid == 0) { leaderWork(std::ref(gcob)); leaderBackoffWork(backoff, ErmiaResult); @@ -128,9 +126,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } #ifdef INSERT_BATCH_DELAY_MS - if (trans.is_batch_) { - sleepMs(INSERT_BATCH_DELAY_MS); - } + if (trans.is_batch_) { sleepMs(INSERT_BATCH_DELAY_MS); } #endif trans.ssn_parallel_commit(); @@ -141,10 +137,10 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { */ if (trans.is_batch_) { storeRelease(myres.local_batch_commit_counts_, - loadAcquire(myres.local_batch_commit_counts_) + 1); + loadAcquire(myres.local_batch_commit_counts_) + 1); } else { storeRelease(myres.local_commit_counts_, - loadAcquire(myres.local_commit_counts_) + 1); + loadAcquire(myres.local_commit_counts_) + 1); } } else if (trans.status_ == TransactionStatus::aborted) { trans.abort(); @@ -165,7 +161,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("ERMIA benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); @@ -182,15 +178,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { ErmiaResult[0].addLocalAllResult(ErmiaResult[i]); @@ -198,10 +192,8 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/ermia/garbage_collection.cc b/cc/ermia/garbage_collection.cc index abc60627..708e7ab7 100644 --- a/cc/ermia/garbage_collection.cc +++ b/cc/ermia/garbage_collection.cc @@ -14,7 +14,7 @@ using std::cout, std::endl; // start, for leader thread. bool GarbageCollection::chkSecondRange() { - TransactionTable *tmt; + TransactionTable* tmt; smin_ = UINT32_MAX; smax_ = 0; @@ -35,7 +35,7 @@ bool GarbageCollection::chkSecondRange() { } void GarbageCollection::decideFirstRange() { - TransactionTable *tmt; + TransactionTable* tmt; fmin_ = fmax_ = 0; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -50,7 +50,7 @@ void GarbageCollection::decideFirstRange() { // end, for leader thread. // for worker thread -void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { +void GarbageCollection::gcVersion([[maybe_unused]] Result* eres_) { uint32_t threshold = getGcThreshold(); // my customized Rapid garbage collection inspired from Cicada (sigmod 2017). @@ -60,7 +60,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { // (a) acquiring the garbage collection lock succeeds uint8_t zero = 0; uint8_t one = 1; - Tuple *tuple = gcq_for_version_.front().rcdptr_; + Tuple* tuple = gcq_for_version_.front().rcdptr_; if (!tuple->gc_lock_.compare_exchange_strong( zero, one, std::memory_order_acq_rel, std::memory_order_acquire)) { // fail acquiring the lock @@ -79,7 +79,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { } // this pointer may be dangling. - Version *delTarget = gcq_for_version_.front().ver_->prev_; + Version* delTarget = gcq_for_version_.front().ver_->prev_; if (delTarget == nullptr) { tuple->gc_lock_.store(0, std::memory_order_release); gcq_for_version_.pop_front(); @@ -94,7 +94,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { while (delTarget != nullptr) { // next pointer escape - Version *tmp = delTarget->prev_; + Version* tmp = delTarget->prev_; reuse_version_from_gc_.emplace_back(delTarget); delTarget = tmp; #if ADD_ANALYSIS @@ -141,12 +141,12 @@ void GarbageCollection::gcRecord() { return; } -void GarbageCollection::gcTMTelement([[maybe_unused]] Result *eres_) { +void GarbageCollection::gcTMTelement([[maybe_unused]] Result* eres_) { uint32_t threshold = getGcThreshold(); if (gcq_for_TMT_.empty()) return; for (;;) { - TransactionTable *tmt = gcq_for_TMT_.front(); + TransactionTable* tmt = gcq_for_TMT_.front(); if (tmt->txid_ < threshold) { gcq_for_TMT_.pop_front(); reuse_TMT_element_from_gc_.emplace_back(tmt); diff --git a/cc/ermia/include/common.hh b/cc/ermia/include/common.hh index de89e07d..23e2bc45 100644 --- a/cc/ermia/include/common.hh +++ b/cc/ermia/include/common.hh @@ -30,13 +30,17 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint64(clocks_per_us, 2100, "CPU_MHz. Use this info for measuring time."); +DEFINE_uint64(clocks_per_us, 2100, + "CPU_MHz. Use this info for measuring time."); DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(gc_inter_us, 10, "GC interval[us]."); DEFINE_uint64(max_ope, 10, "Total number of operations per single transaction."); -DEFINE_uint64(pre_reserve_tmt_element, 100, "Pre-allocating memory for the transaction mapping table elements."); -DEFINE_uint64(pre_reserve_version, 10000, "Pre-allocating memory for the version."); +DEFINE_uint64( + pre_reserve_tmt_element, 100, + "Pre-allocating memory for the transaction mapping table elements."); +DEFINE_uint64(pre_reserve_version, 10000, + "Pre-allocating memory for the version."); DEFINE_bool(rmw, false, "True means read modify write, false means blind write."); DEFINE_uint64(rratio, 50, "read ratio of single transaction."); @@ -51,8 +55,10 @@ DEFINE_uint64(batch_ratio, 0, "ratio of batch transaction."); DEFINE_uint64(batch_max_ope, 1000, "Total number of operations per single batch transaction."); DEFINE_uint64(batch_rratio, 100, "read ratio of single batch transaction."); -DEFINE_uint64(batch_tuples, 0, "Number of update-only records for batch transaction."); -DEFINE_bool(batch_simple_rr, false, "No one touches update-only records of batch transaction."); +DEFINE_uint64(batch_tuples, 0, + "Number of update-only records for batch transaction."); +DEFINE_bool(batch_simple_rr, false, + "No one touches update-only records of batch transaction."); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(extime); @@ -77,13 +83,13 @@ DECLARE_bool(batch_simple_rr); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; alignas(CACHE_LINE_SIZE) GLOBAL -TransactionTable **TMT; // Transaction Mapping Table + TransactionTable** TMT; // Transaction Mapping Table // See si/include/common.hh for the rationale; same EBR-style guard // that prevents gcRecord from freeing a Tuple while another thread // still has it in its per-thread gcq_for_version_. -alignas(CACHE_LINE_SIZE) GLOBAL std::atomic *MinQueuedCstamp; +alignas(CACHE_LINE_SIZE) GLOBAL std::atomic* MinQueuedCstamp; GLOBAL std::mutex SsnLock; diff --git a/cc/ermia/include/ermia_op_element.hh b/cc/ermia/include/ermia_op_element.hh index 43a344cf..0576c466 100644 --- a/cc/ermia/include/ermia_op_element.hh +++ b/cc/ermia/include/ermia_op_element.hh @@ -4,39 +4,42 @@ #include "version.hh" -template +template class SetElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; - SetElement(Storage s, std::string_view key, T *rcdptr, Version *ver) - : OpElement::OpElement(s, key, rcdptr) { + SetElement(Storage s, std::string_view key, T* rcdptr, Version* ver) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; } - SetElement(Storage s, std::string_view key, T *rcdptr, Version *ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + SetElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { this->ver_ = ver; } - bool operator<(const SetElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const SetElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class GCElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; uint32_t cstamp_; - GCElement(Storage s, std::string_view key, T *rcdptr, Version *ver, uint32_t cstamp) - : OpElement::OpElement(s, key, rcdptr) { + GCElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + uint32_t cstamp) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; this->cstamp_ = cstamp; } diff --git a/cc/ermia/include/garbage_collection.hh b/cc/ermia/include/garbage_collection.hh index 8faf2891..27149f45 100644 --- a/cc/ermia/include/garbage_collection.hh +++ b/cc/ermia/include/garbage_collection.hh @@ -15,17 +15,17 @@ class TransactionTable; class GarbageCollection { private: - uint32_t fmin_, fmax_; // first range of txid in TMT. - uint32_t smin_, smax_; // second range of txid in TMT. - static std::atomic - GC_threshold_; // share for all object (meaning all thread). + uint32_t fmin_, fmax_; // first range of txid in TMT. + uint32_t smin_, smax_; // second range of txid in TMT. + static std::atomic + GC_threshold_; // share for all object (meaning all thread). public: - std::deque gcq_for_TMT_; - std::deque reuse_TMT_element_from_gc_; - std::deque gcq_for_record_; - std::deque > gcq_for_version_; - std::deque reuse_version_from_gc_; + std::deque gcq_for_TMT_; + std::deque reuse_TMT_element_from_gc_; + std::deque gcq_for_record_; + std::deque> gcq_for_version_; + std::deque reuse_version_from_gc_; uint8_t thid_; GarbageCollection() {} @@ -56,11 +56,11 @@ public: // ----- // for worker thread - void gcVersion(Result *eres_); + void gcVersion(Result* eres_); void gcRecord(); - void gcTMTelement(Result *eres_); + void gcTMTelement(Result* eres_); // ----- // EBR-style guard: publish smallest cstamp in this thread's @@ -68,9 +68,8 @@ public: // Tuple whose delete cstamp >= min(MinQueuedCstamp[*]). See // si/include/garbage_collection.hh for the matching definition. INLINE void publishMinQueuedCstamp() { - uint32_t v = gcq_for_version_.empty() - ? UINT32_MAX - : gcq_for_version_.front().cstamp_; + uint32_t v = gcq_for_version_.empty() ? UINT32_MAX + : gcq_for_version_.front().cstamp_; MinQueuedCstamp[thid_].store(v, std::memory_order_release); } }; diff --git a/cc/ermia/include/lock.hh b/cc/ermia/include/lock.hh index 4553d945..dcc5a582 100644 --- a/cc/ermia/include/lock.hh +++ b/cc/ermia/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -40,7 +38,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -56,7 +54,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/cc/ermia/include/result.hh b/cc/ermia/include/result.hh index a0ff0b29..e3a9635e 100644 --- a/cc/ermia/include/result.hh +++ b/cc/ermia/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector ErmiaResult; +extern std::vector ErmiaResult; extern void initResult(); diff --git a/cc/ermia/include/scan_callback.hh b/cc/ermia/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/ermia/include/scan_callback.hh +++ b/cc/ermia/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/ermia/include/transaction.hh b/cc/ermia/include/transaction.hh index 0416bc2f..310b8fdd 100644 --- a/cc/ermia/include/transaction.hh +++ b/cc/ermia/include/transaction.hh @@ -27,40 +27,42 @@ class TxScanCallback; class TxExecutor { public: - uint8_t thid_; // thread ID - uint32_t cstamp_ = 0; // Transaction end time, c(T) - uint32_t pstamp_ = 0; // Predecessor high-water mark, η (T) - uint32_t sstamp_ = UINT32_MAX; // Successor low-water mark, pi (T) + uint8_t thid_; // thread ID + uint32_t cstamp_ = 0; // Transaction end time, c(T) + uint32_t pstamp_ = 0; // Predecessor high-water mark, η (T) + uint32_t sstamp_ = UINT32_MAX; // Successor low-water mark, pi (T) uint32_t pre_gc_threshold_ = 0; - uint32_t txid_; // TID and begin timestamp - the current log sequence number (LSN) - uint64_t gcstart_, gcstop_; // counter for garbage collection + uint32_t + txid_; // TID and begin timestamp - the current log sequence number (LSN) + uint64_t gcstart_, gcstop_; // counter for garbage collection - vector > read_set_; - vector > write_set_; + vector> read_set_; + vector> write_set_; std::unordered_map node_map_; - vector pro_set_; + vector pro_set_; bool reconnoitering_ = false; bool is_ronly_ = false; bool is_batch_ = false; - Result *result_; + Result* result_; TransactionStatus status_ = - TransactionStatus::inflight; // Status: inflight, committed, or aborted + TransactionStatus::inflight; // Status: inflight, committed, or aborted GarbageCollection gcobject_; GarbageCollection gcob; TxScanCallback callback_; Backoff& backoff_; const bool& quit_; // for thread termination control - TxExecutor(uint8_t thid, Backoff& backoff, Result *res, const bool &quit) - : thid_(thid), result_(res), callback_(TxScanCallback(this)), backoff_(backoff), quit_(quit) { + TxExecutor(uint8_t thid, Backoff& backoff, Result* res, const bool& quit) + : thid_(thid), result_(res), callback_(TxScanCallback(this)), + backoff_(backoff), quit_(quit) { gcobject_.set_thid_(thid); if (FLAGS_pre_reserve_tmt_element) { for (size_t i = 0; i < FLAGS_pre_reserve_tmt_element; ++i) gcobject_.reuse_TMT_element_from_gc_.emplace_back( - new TransactionTable()); + new TransactionTable()); } if (FLAGS_pre_reserve_version) { @@ -80,15 +82,13 @@ public: Status delete_record(Storage s, std::string_view key); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); void ssn_commit(); @@ -104,11 +104,11 @@ public: void leaderWork(); - void reconnoiter_begin(); + void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_end(); - Status install_version(Tuple* tuple, Version *ver); + Status install_version(Tuple* tuple, Version* ver); void verify_exclusion_or_abort(); @@ -116,7 +116,7 @@ public: void dispRS(); - void upReadersBits(Version *ver) { + void upReadersBits(Version* ver) { uint64_t expected, desired; expected = ver->readers_.load(memory_order_acquire); for (;;) { @@ -127,7 +127,7 @@ public: } } - void downReadersBits(Version *ver) { + void downReadersBits(Version* ver) { uint64_t expected, desired; expected = ver->readers_.load(memory_order_acquire); for (;;) { @@ -138,7 +138,7 @@ public: } } - static INLINE Tuple *get_tuple(Tuple *table, uint64_t key) { + static INLINE Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } @@ -150,8 +150,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline SetElement *searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { + inline SetElement* searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -167,8 +167,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline SetElement *searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { + inline SetElement* searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } diff --git a/cc/ermia/include/transaction_table.hh b/cc/ermia/include/transaction_table.hh index 3b615b81..d2a92191 100644 --- a/cc/ermia/include/transaction_table.hh +++ b/cc/ermia/include/transaction_table.hh @@ -8,11 +8,11 @@ class TransactionTable { public: - alignas(CACHE_LINE_SIZE) std::atomic txid_; - std::atomic cstamp_; - std::atomic sstamp_; - std::atomic lastcstamp_; - std::atomic status_; + alignas(CACHE_LINE_SIZE) std::atomic txid_; + std::atomic cstamp_; + std::atomic sstamp_; + std::atomic lastcstamp_; + std::atomic status_; TransactionTable() {} diff --git a/cc/ermia/include/tuple.hh b/cc/ermia/include/tuple.hh index 9483410a..1818b816 100644 --- a/cc/ermia/include/tuple.hh +++ b/cc/ermia/include/tuple.hh @@ -8,9 +8,9 @@ class Tuple { public: - alignas(CACHE_LINE_SIZE) std::atomic latest_; - std::atomic min_cstamp_; - std::atomic gc_lock_; + alignas(CACHE_LINE_SIZE) std::atomic latest_; + std::atomic min_cstamp_; + std::atomic gc_lock_; TupleBody body_; // only used for index tuple as single version Tuple() { @@ -18,11 +18,12 @@ public: gc_lock_.store(0, std::memory_order_release); } - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* param) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* param) { // for initializer min_cstamp_ = 0; latest_.store(new Version(), std::memory_order_release); - Version *verTmp = latest_.load(std::memory_order_acquire); + Version* verTmp = latest_.load(std::memory_order_acquire); verTmp->cstamp_ = 0; // verTmp->pstamp = 0; // verTmp->sstamp = UINT64_MAX & ~(1); @@ -40,7 +41,7 @@ public: void init(uint32_t txid, TupleBody&& body) { min_cstamp_ = 0; latest_.store(new Version(), std::memory_order_release); - Version *verTmp = latest_.load(std::memory_order_acquire); + Version* verTmp = latest_.load(std::memory_order_acquire); verTmp->cstamp_.store(txid, memory_order_release); verTmp->psstamp_.pstamp_ = 0; verTmp->psstamp_.sstamp_ = UINT32_MAX & ~(1); diff --git a/cc/ermia/include/util.hh b/cc/ermia/include/util.hh index 5ebf3d6c..4924c8ab 100644 --- a/cc/ermia/include/util.hh +++ b/cc/ermia/include/util.hh @@ -8,11 +8,11 @@ extern void displayDB(); extern void displayParameter(); -extern void leaderWork(GarbageCollection &gcob); +extern void leaderWork(GarbageCollection& gcob); extern void makeDB(); -extern void naiveGarbageCollection(const bool &quit); +extern void naiveGarbageCollection(const bool& quit); extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); diff --git a/cc/ermia/include/version.hh b/cc/ermia/include/version.hh index 211c0fca..9cb42249 100644 --- a/cc/ermia/include/version.hh +++ b/cc/ermia/include/version.hh @@ -92,11 +92,11 @@ struct Psstamp { class Version { public: alignas(CACHE_LINE_SIZE) Psstamp - psstamp_; // Version access stamp, eta(V), Version successor stamp, pi(V) - Version *prev_; // Pointer to overwritten version - std::atomic readers_; // summarize all of V's readers. - std::atomic cstamp_; // Version creation stamp, c(V) - std::atomic status_; + psstamp_; // Version access stamp, eta(V), Version successor stamp, pi(V) + Version* prev_; // Pointer to overwritten version + std::atomic readers_; // summarize all of V's readers. + std::atomic cstamp_; // Version creation stamp, c(V) + std::atomic status_; TupleBody body_; diff --git a/cc/ermia/sbomb_ermia.cc b/cc/ermia/sbomb_ermia.cc index 819bb2c0..04d54fc8 100644 --- a/cc/ermia/sbomb_ermia.cc +++ b/cc/ermia/sbomb_ermia.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &ErmiaResult[thid], quit); - StaticBombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &ErmiaResult[thid], quit); + StaticBombWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB ERMIA benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); - StaticBombWorkload::makeDB(nullptr); + StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -80,15 +80,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -97,11 +95,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; ErmiaResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ermia/tpcc_ermia.cc b/cc/ermia/tpcc_ermia.cc index 4cc911cc..528e2fb3 100644 --- a/cc/ermia/tpcc_ermia.cc +++ b/cc/ermia/tpcc_ermia.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &ErmiaResult[thid], quit); - TPCCWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &ErmiaResult[thid], quit); + TPCCWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C ERMIA benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -80,15 +80,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -97,11 +95,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; ErmiaResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ermia/transaction.cc b/cc/ermia/transaction.cc index 1d5b2573..826a591d 100644 --- a/cc/ermia/transaction.cc +++ b/cc/ermia/transaction.cc @@ -116,16 +116,17 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search versions from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif if (tuple == nullptr) return Status::WARN_NOT_FOUND; - Version *ver; + Version* ver; ver = read_internal(s, key, tuple); - if (ver == nullptr || ver->status_.load(memory_order_acquire) == VersionStatus::deleted) + if (ver == nullptr || + ver->status_.load(memory_order_acquire) == VersionStatus::deleted) return Status::WARN_NOT_FOUND; /** @@ -143,19 +144,18 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { return Status::OK; } -Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Version* TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { /** * Move to the points of this view. */ - Version *ver; + Version* ver; ver = tuple->latest_.load(memory_order_acquire); - while ((ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) - || txid_ < ver->cstamp_.load(memory_order_acquire)) { + while ((ver->status_.load(memory_order_acquire) != VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) || + txid_ < ver->cstamp_.load(memory_order_acquire)) { ver = ver->prev_; - if (ver == nullptr) { - return nullptr; - } + if (ver == nullptr) { return nullptr; } } uint32_t v_sstamp; @@ -165,15 +165,12 @@ Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple read_set_.emplace_back(s, key, tuple, ver); } else { // update pi with r:w edge - this->sstamp_ = - min(this->sstamp_, (v_sstamp >> TIDFLAG)); + this->sstamp_ = min(this->sstamp_, (v_sstamp >> TIDFLAG)); } upReadersBits(ver); verify_exclusion_or_abort(); - if (this->status_ == TransactionStatus::aborted) { - return nullptr; - } + if (this->status_ == TransactionStatus::aborted) { return nullptr; } return ver; } @@ -200,8 +197,9 @@ Status TxExecutor::install_version(Tuple* tuple, Version* desired) { // if latest version is not comitted. vertmp = expected; - while (vertmp->status_.load(memory_order_acquire) != VersionStatus::committed - && vertmp->status_.load(memory_order_acquire) != VersionStatus::deleted) + while (vertmp->status_.load(memory_order_acquire) != + VersionStatus::committed && + vertmp->status_.load(memory_order_acquire) != VersionStatus::deleted) vertmp = vertmp->prev_; // vertmp is latest committed version. @@ -244,7 +242,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * avoid false positive. */ - Tuple *tuple; + Tuple* tuple; tuple = nullptr; for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { if ((*itr).storage_ == s && (*itr).key_ == key) { @@ -275,7 +273,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { * Forbid a transaction to update a record that has a committed head version * later than its begin timestamp. */ - Version *desired; + Version* desired; desired = new Version(); if (gcobject_.reuse_version_from_gc_.empty()) { desired = new Version(); @@ -290,13 +288,12 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { ++result_->local_version_reuse_; #endif } - desired->cstamp_.store(this->txid_, memory_order_relaxed); // read operation, write operation, + desired->cstamp_.store( + this->txid_, memory_order_relaxed); // read operation, write operation, // it is also accessed by garbage collection. stat = install_version(tuple, desired); - if (stat != Status::OK) { - goto FINISH_WRITE; - } + if (stat != Status::OK) { goto FINISH_WRITE; } /** * Insert my tid for ver->prev_->sstamp_ @@ -311,7 +308,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { * Update eta with w:r edge */ this->pstamp_ = - max(this->pstamp_, desired->prev_->psstamp_.atomicLoadPstamp()); + max(this->pstamp_, desired->prev_->psstamp_.atomicLoadPstamp()); desired->body_ = std::move(body); write_set_.emplace_back(s, key, tuple, desired, OpType::UPDATE); @@ -327,7 +324,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; @@ -335,22 +332,21 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(this->txid_, std::move(body)); Version* ver = tuple->latest_.load(std::memory_order_acquire); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -368,22 +364,20 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } Status TxExecutor::delete_record(Storage s, std::string_view key) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS Status stat = Status::OK; // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple = nullptr; @@ -400,11 +394,11 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } - Version *desired; + Version* desired; desired = new Version(); if (gcobject_.reuse_version_from_gc_.empty()) { desired = new Version(); @@ -419,14 +413,13 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { ++result_->local_version_reuse_; #endif } - desired->cstamp_.store(this->txid_, memory_order_relaxed); // read operation, write operation, + desired->cstamp_.store( + this->txid_, memory_order_relaxed); // read operation, write operation, // it is also accessed by garbage collection. stat = install_version(tuple, desired); - if (stat != Status::OK) { - goto FINISH_DELETE; - } + if (stat != Status::OK) { goto FINISH_DELETE; } /** * Insert my tid for ver->prev_->sstamp_ @@ -440,7 +433,8 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { /** * Update eta with w:r edge */ - this->pstamp_ = max(this->pstamp_, desired->prev_->psstamp_.atomicLoadPstamp()); + this->pstamp_ = + max(this->pstamp_, desired->prev_->psstamp_.atomicLoadPstamp()); write_set_.emplace_back(s, key, tuple, desired, OpType::DELETE); verify_exclusion_or_abort(); @@ -452,28 +446,26 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { return stat; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); std::set seen; - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { // TODO: Tuple should have key? Accessing key through the latest ver is ugly // Must be a copy to avoid buffer overflow when changing the latest std::string key(itr->latest_.load(memory_order_acquire)->body_.get_key()); @@ -494,7 +486,8 @@ Status TxExecutor::scan(const Storage s, Version* v = read_internal(s, key, itr); if (this->status_ == TransactionStatus::aborted) return Status::ERROR_PREEMPTIVE_ABORT; - if (v == nullptr || v->status_.load(memory_order_acquire) == VersionStatus::deleted) + if (v == nullptr || + v->status_.load(memory_order_acquire) == VersionStatus::deleted) continue; if (seen.find(v) == seen.end()) { result.emplace_back(&(v->body_)); @@ -510,7 +503,7 @@ Status TxExecutor::scan(const Storage s, */ void TxExecutor::ssn_commit() { this->status_ = TransactionStatus::committing; - TransactionTable *tmt = loadAcquire(TMT[thid_]); + TransactionTable* tmt = loadAcquire(TMT[thid_]); tmt->status_.store(TransactionStatus::committing); this->cstamp_ = ++Lsn; @@ -548,7 +541,7 @@ void TxExecutor::ssn_commit() { // update eta for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { (*itr).ver_->psstamp_.atomicStorePstamp( - max((*itr).ver_->psstamp_.atomicLoadPstamp(), cstamp_)); + max((*itr).ver_->psstamp_.atomicLoadPstamp(), cstamp_)); // down readers bit downReadersBits((*itr).ver_); } @@ -583,7 +576,8 @@ void TxExecutor::ssn_commit() { (*itr).ver_->status_.store(VersionStatus::deleted, memory_order_release); gcobject_.gcq_for_record_.push_back((*itr).rcdptr_); } else { - (*itr).ver_->status_.store(VersionStatus::committed, memory_order_release); + (*itr).ver_->status_.store(VersionStatus::committed, + memory_order_release); } } @@ -603,7 +597,7 @@ void TxExecutor::ssn_parallel_commit() { uint64_t start(rdtscp()); #endif this->status_ = TransactionStatus::committing; - TransactionTable *tmt = TMT[thid_]; + TransactionTable* tmt = TMT[thid_]; tmt->status_.store(TransactionStatus::committing); this->cstamp_ = ++Lsn; @@ -634,7 +628,8 @@ void TxExecutor::ssn_parallel_commit() { * Worker is in ssn_parallel_commit(). * So it wait worker to get cstamp. */ - while (tmt->cstamp_.load(memory_order_acquire) == 0); + while (tmt->cstamp_.load(memory_order_acquire) == 0) + ; /** * If worker->cstamp_ is less than this->cstamp_, the worker can be pi. */ @@ -643,11 +638,12 @@ void TxExecutor::ssn_parallel_commit() { * It wait worker to end parallel_commit (determine sstamp). */ while (tmt->status_.load(memory_order_acquire) == - TransactionStatus::committing); + TransactionStatus::committing) + ; if (tmt->status_.load(memory_order_acquire) == TransactionStatus::committed) { this->sstamp_ = - min(this->sstamp_, tmt->sstamp_.load(memory_order_acquire)); + min(this->sstamp_, tmt->sstamp_.load(memory_order_acquire)); } } } @@ -665,9 +661,10 @@ void TxExecutor::ssn_parallel_commit() { /** * for r in v.prev.readers */ - Version *ver = (*itr).ver_; - while (ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) + Version* ver = (*itr).ver_; + while (ver->status_.load(memory_order_acquire) != + VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) ver = ver->prev_; uint64_t rdrs = ver->readers_.load(memory_order_acquire); for (unsigned int worker = 0; worker < TotalThreadNum; ++worker) { @@ -680,7 +677,8 @@ void TxExecutor::ssn_parallel_commit() { */ if (tmt->status_.load(memory_order_acquire) == TransactionStatus::committing) { - while (tmt->cstamp_.load(memory_order_acquire) == 0); + while (tmt->cstamp_.load(memory_order_acquire) == 0) + ; /** * If worker->cstamp_ is less than this->cstamp_, it can be eta. */ @@ -689,11 +687,12 @@ void TxExecutor::ssn_parallel_commit() { * Wait end of parallel_commit (determing sstamp). */ while (tmt->status_.load(memory_order_acquire) == - TransactionStatus::committing); + TransactionStatus::committing) + ; if (tmt->status_.load(memory_order_acquire) == TransactionStatus::committed) { this->pstamp_ = - max(this->pstamp_, tmt->cstamp_.load(memory_order_acquire)); + max(this->pstamp_, tmt->cstamp_.load(memory_order_acquire)); } } } @@ -721,7 +720,7 @@ void TxExecutor::ssn_parallel_commit() { // validate the node set for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { status_ = TransactionStatus::aborted; tmt->status_.store(TransactionStatus::aborted, memory_order_release); @@ -756,9 +755,11 @@ void TxExecutor::ssn_parallel_commit() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).op_ == OpType::UPDATE) { - Version *next_committed = (*itr).ver_->prev_; - while (next_committed->status_.load(memory_order_acquire) != VersionStatus::committed - && next_committed->status_.load(memory_order_acquire) != VersionStatus::deleted) + Version* next_committed = (*itr).ver_->prev_; + while (next_committed->status_.load(memory_order_acquire) != + VersionStatus::committed && + next_committed->status_.load(memory_order_acquire) != + VersionStatus::deleted) next_committed = next_committed->prev_; next_committed->psstamp_.atomicStoreSstamp(verSstamp); } @@ -774,10 +775,12 @@ void TxExecutor::ssn_parallel_commit() { (*itr).ver_->status_.store(VersionStatus::deleted, memory_order_release); gcobject_.gcq_for_record_.push_back((*itr).rcdptr_); } else { - (*itr).ver_->status_.store(VersionStatus::committed, memory_order_release); + (*itr).ver_->status_.store(VersionStatus::committed, + memory_order_release); } gcobject_.gcq_for_version_.emplace_back( - GCElement((*itr).storage_, (*itr).key_, (*itr).rcdptr_, (*itr).ver_, this->cstamp_)); + GCElement((*itr).storage_, (*itr).key_, (*itr).rcdptr_, (*itr).ver_, + this->cstamp_)); } // After pushing this commit's GCElements, expose the (possibly new) // queue front cstamp so other threads' gcRecord can advance safely. @@ -807,9 +810,11 @@ void TxExecutor::ssn_parallel_commit() { void TxExecutor::abort() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).op_ == OpType::UPDATE || (*itr).op_ == OpType::DELETE) { - Version *next_committed = (*itr).ver_->prev_; - while (next_committed->status_.load(memory_order_acquire) != VersionStatus::committed - && next_committed->status_.load(memory_order_acquire) != VersionStatus::deleted) + Version* next_committed = (*itr).ver_->prev_; + while (next_committed->status_.load(memory_order_acquire) != + VersionStatus::committed && + next_committed->status_.load(memory_order_acquire) != + VersionStatus::deleted) next_committed = next_committed->prev_; /** * cancel successor mark(sstamp). @@ -851,7 +856,7 @@ void TxExecutor::abort() { void TxExecutor::verify_exclusion_or_abort() { if (this->pstamp_ >= this->sstamp_) { this->status_ = TransactionStatus::aborted; - TransactionTable *tmt = loadAcquire(TMT[thid_]); + TransactionTable* tmt = loadAcquire(TMT[thid_]); tmt->status_.store(TransactionStatus::aborted, memory_order_release); } } @@ -900,8 +905,7 @@ void TxExecutor::mainte() { bool TxExecutor::commit() { ssn_parallel_commit(); - if (status_ == TransactionStatus::aborted) - return false; + if (status_ == TransactionStatus::aborted) return false; /** * Maintenance phase @@ -910,9 +914,7 @@ bool TxExecutor::commit() { return true; } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { if (gcob.chkSecondRange()) { @@ -924,9 +926,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); @@ -935,10 +935,11 @@ void TxExecutor::reconnoiter_end() { begin(); } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/ermia/util.cc b/cc/ermia/util.cc index 28c62c86..f1235d5d 100644 --- a/cc/ermia/util.cc +++ b/cc/ermia/util.cc @@ -2,9 +2,9 @@ #include #include #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include #include @@ -57,15 +57,13 @@ void chkArg() { } try { - TMT = new TransactionTable *[TotalThreadNum]; + TMT = new TransactionTable*[TotalThreadNum]; MinQueuedCstamp = new std::atomic[TotalThreadNum]; - } catch (const bad_alloc&) { - ERR; - } + } catch (const bad_alloc&) { ERR; } for (unsigned int i = 0; i < TotalThreadNum; ++i) { TMT[i] = - new TransactionTable(0, 0, UINT32_MAX, 0, TransactionStatus::inflight); + new TransactionTable(0, 0, UINT32_MAX, 0, TransactionStatus::inflight); MinQueuedCstamp[i].store(UINT32_MAX, std::memory_order_relaxed); } } @@ -113,8 +111,10 @@ void displayParameter() { cout << "#FLAGS_extime:\t\t\t\t" << FLAGS_extime << endl; cout << "#FLAGS_gc_inter_us:\t\t\t" << FLAGS_gc_inter_us << endl; cout << "#FLAGS_max_ope:\t\t\t\t" << FLAGS_max_ope << endl; - cout << "#FLAGS_pre_reserve_tmt_element:\t\t" << FLAGS_pre_reserve_tmt_element << endl; - cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version << endl; + cout << "#FLAGS_pre_reserve_tmt_element:\t\t" << FLAGS_pre_reserve_tmt_element + << endl; + cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version + << endl; cout << "#FLAGS_rmw:\t\t\t\t" << FLAGS_rmw << endl; cout << "#FLAGS_rratio:\t\t\t\t" << FLAGS_rratio << endl; cout << "#FLAGS_thread_num:\t\t\t" << FLAGS_thread_num << endl; @@ -176,8 +176,8 @@ void displayParameter() { // for (auto &th : thv) th.join(); // } -void naiveGarbageCollection(const bool &quit) { - TransactionTable *tmt; +void naiveGarbageCollection(const bool& quit) { + TransactionTable* tmt; uint32_t mintxID = UINT32_MAX; for (unsigned int i = 1; i < TotalThreadNum; ++i) { @@ -203,7 +203,7 @@ void naiveGarbageCollection(const bool &quit) { uint64_t verCstamp = verTmp->cstamp_.load(memory_order_acquire); while (mintxID < (verCstamp >> 1) || verTmp->status_.load(memory_order_acquire) != - VersionStatus::committed) { + VersionStatus::committed) { verTmp = verTmp->prev_; if (verTmp == nullptr) break; verCstamp = verTmp->cstamp_.load(memory_order_acquire); @@ -233,7 +233,7 @@ void naiveGarbageCollection(const bool &quit) { } } -void ermiaLeaderWork(GarbageCollection &gcob) { +void ermiaLeaderWork(GarbageCollection& gcob) { if (gcob.chkSecondRange()) { gcob.decideGcThreshold(); gcob.mvSecondRangeToFirstRange(); diff --git a/cc/ermia/ycsb_ermia.cc b/cc/ermia/ycsb_ermia.cc index db27cf0e..ddef0c7f 100644 --- a/cc/ermia/ycsb_ermia.cc +++ b/cc/ermia/ycsb_ermia.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,9 +33,9 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &ErmiaResult[thid], quit); + TxExecutor trans(thid, backoff, (Result*) &ErmiaResult[thid], quit); YcsbWorkload workload; #if MASSTREE_USE @@ -47,7 +47,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -56,17 +56,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); trans.gcstart_ = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("ERMIA benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -79,15 +79,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { ErmiaResult[0].addLocalAllResult(ErmiaResult[i]); @@ -95,10 +93,8 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; ErmiaResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mocc/bomb_mocc.cc b/cc/mocc/bomb_mocc.cc index 6279d836..567ff4e1 100644 --- a/cc/mocc/bomb_mocc.cc +++ b/cc/mocc/bomb_mocc.cc @@ -1,12 +1,12 @@ -#include // isdigit, +#include // isdigit, #include -#include // strlen, -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // strlen, +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // string +#include // string #define GLOBAL_VALUE_DEFINE @@ -30,10 +30,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(MoccResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(MoccResult[thid]); TxExecutor trans(thid, &myres, quit); - BombWorkload workload; + BombWorkload workload; workload.prepare(trans, nullptr); #if MASSTREE_USE @@ -42,24 +42,24 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { #ifdef Linux setThreadAffinity(thid); -#endif // Linux +#endif // Linux storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB MOCC benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -67,25 +67,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MoccResult[0].addLocalAllResult(MoccResult[i]); @@ -93,11 +91,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; MoccResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mocc/include/atomic_tool.hh b/cc/mocc/include/atomic_tool.hh index 2c05efdf..78a70c08 100644 --- a/cc/mocc/include/atomic_tool.hh +++ b/cc/mocc/include/atomic_tool.hh @@ -23,6 +23,6 @@ INLINE void atomicAddGE() { INLINE uint64_t atomicLoadGE() { uint64_t_64byte result = - __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); return result.obj_; } \ No newline at end of file diff --git a/cc/mocc/include/common.hh b/cc/mocc/include/common.hh index 11f71229..a1bfffcf 100644 --- a/cc/mocc/include/common.hh +++ b/cc/mocc/include/common.hh @@ -28,7 +28,7 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #endif -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThLocalEpoch; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThLocalEpoch; #ifdef GLOBAL_VALUE_DEFINE DEFINE_uint64(clocks_per_us, 2100, @@ -38,7 +38,9 @@ DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(max_ope, 10, "Total number of operations per single transaction."); DEFINE_uint64(temp_threshold, 10, "temperature threshold"); -DEFINE_uint64(per_xx_temp, 4096, "What record size (bytes) does it integrate about temperature statistics."); +DEFINE_uint64( + per_xx_temp, 4096, + "What record size (bytes) does it integrate about temperature statistics."); DEFINE_bool(rmw, false, "True means read modify write, false means blind write."); DEFINE_uint64(rratio, 50, "read ratio of single transaction."); @@ -53,8 +55,10 @@ DEFINE_uint64(batch_ratio, 0, "ratio of batch transaction."); DEFINE_uint64(batch_max_ope, 1000, "Total number of operations per single batch transaction."); DEFINE_uint64(batch_rratio, 100, "read ratio of single batch transaction."); -DEFINE_uint64(batch_tuples, 0, "Number of update-only records for batch transaction."); -DEFINE_bool(batch_simple_rr, false, "No one touches update-only records of batch transaction."); +DEFINE_uint64(batch_tuples, 0, + "Number of update-only records for batch transaction."); +DEFINE_bool(batch_simple_rr, false, + "No one touches update-only records of batch transaction."); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(epoch_time); @@ -83,14 +87,14 @@ alignas(CACHE_LINE_SIZE) GLOBAL uint32_t ReclamationEpoch; GLOBAL ReaderWriterLock CtrLock; // for logging emulation -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *Start; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *Stop; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* Start; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* Stop; // 下記,ifdef で外すと lock.cc のコードから // 参照出来なくてエラーが起きる. // lock.hh, lock.cc の全てを ifdef で分岐させるのは大変な労力なので, // 行わず,これは RWLOCK モードでも宣言だけしておく. -alignas(CACHE_LINE_SIZE) GLOBAL MQLNode **MQLNodeTable; +alignas(CACHE_LINE_SIZE) GLOBAL MQLNode** MQLNodeTable; // first dimension index number corresponds to the thread number. // second dimension index number corresponds to the key of records. // the element mean MQLnode whihch is owned by the thread which has the thread diff --git a/cc/mocc/include/lock.hh b/cc/mocc/include/lock.hh index 846e3a96..5b29b148 100644 --- a/cc/mocc/include/lock.hh +++ b/cc/mocc/include/lock.hh @@ -14,30 +14,24 @@ class Tuple; // defined at tuple.hh enum class SentinelValue : uint32_t { None = 0, - Acquired, // 1 - SuccessorLeaving, // 2 + Acquired, // 1 + SuccessorLeaving, // 2 }; -enum class LockMode : uint8_t { - None, Reader, Writer -}; +enum class LockMode : uint8_t { None, Reader, Writer }; -enum class LockStatus : uint8_t { - Waiting, Granted, Leaving -}; +enum class LockStatus : uint8_t { Waiting, Granted, Leaving }; -enum class MQL_RESULT : uint8_t { - Acquired, Cancelled -}; +enum class MQL_RESULT : uint8_t { Acquired, Cancelled }; struct MQLMetaInfo { union { uint64_t obj; struct { - bool busy: 1; // 0 == not busy, 1 == busy; - LockMode stype: 8; // 0 == none, 1 == reader, 2 == writer - LockStatus status: 8; // 0 == waiting, 1 == granted, 2 == leaving - uint32_t next: 32; // store a thrad id. and you know where the qnode; + bool busy : 1; // 0 == not busy, 1 == busy; + LockMode stype : 8; // 0 == none, 1 == reader, 2 == writer + LockStatus status : 8; // 0 == waiting, 1 == granted, 2 == leaving + uint32_t next : 32; // store a thrad id. and you know where the qnode; }; }; @@ -65,8 +59,8 @@ struct MQLMetaInfo { class MQLNode { public: // interact with predecessor - std::atomic type; - std::atomic prev; + std::atomic type; + std::atomic prev; std::atomic granted; // ----- // interact with successor @@ -98,8 +92,8 @@ public: class MQLock { public: std::atomic nreaders; - std::atomic tail; - std::atomic next_writer; + std::atomic tail; + std::atomic next_writer; MQLock() { nreaders = 0; @@ -111,18 +105,15 @@ public: MQL_RESULT acquire_writer_lock(uint32_t me, Tuple* key, bool trylock); - MQL_RESULT acquire_reader_lock_check_reader_pred(uint32_t me, - Tuple* key, + MQL_RESULT acquire_reader_lock_check_reader_pred(uint32_t me, Tuple* key, uint32_t pred, bool trylock); - MQL_RESULT acquire_reader_lock_check_writer_pred(uint32_t me, - Tuple* key, + MQL_RESULT acquire_reader_lock_check_writer_pred(uint32_t me, Tuple* key, uint32_t pred, bool trylock); MQL_RESULT cancel_reader_lock(uint32_t me, Tuple* key); - MQL_RESULT cancel_reader_lock_relink(uint32_t pred, uint32_t me, - Tuple* key); + MQL_RESULT cancel_reader_lock_relink(uint32_t pred, uint32_t me, Tuple* key); MQL_RESULT cancel_reader_lock_with_reader_pred(uint32_t me, Tuple* key, uint32_t pred); @@ -154,47 +145,47 @@ public: ReaderWriterLock() { counter_.store(0, std::memory_order_release); } - void r_lock(); // read lock - bool r_trylock(); // read try lock - void r_unlock(); // read unlock - void w_lock(); // write lock - bool w_trylock(); // write try lock - void w_unlock(); // write unlock - bool upgrade(); // upgrade from reader to writer + void r_lock(); // read lock + bool r_trylock(); // read try lock + void r_unlock(); // read unlock + void w_lock(); // write lock + bool w_trylock(); // write try lock + void w_unlock(); // write unlock + bool upgrade(); // upgrade from reader to writer int ldAcqCounter() { return counter_.load(std::memory_order_acquire); } }; // for lock list -template +template class LockElement { public: - Tuple* key_; // record を識別する. - T *lock_; - bool mode_; // 0 read-mode, 1 write-mode + Tuple* key_; // record を識別する. + T* lock_; + bool mode_; // 0 read-mode, 1 write-mode - LockElement(Tuple* key, T *lock, bool mode) - : key_(key), lock_(lock), mode_(mode) {} + LockElement(Tuple* key, T* lock, bool mode) + : key_(key), lock_(lock), mode_(mode) {} - bool operator<(const LockElement &right) const { + bool operator<(const LockElement& right) const { return this->key_ < right.key_; } // Copy constructor - LockElement(const LockElement &other) { + LockElement(const LockElement& other) { key_ = other.key_; lock_ = other.lock_; mode_ = other.mode_; } // move constructor - LockElement(LockElement &&other) { + LockElement(LockElement&& other) { key_ = other.key_; lock_ = other.lock_; mode_ = other.mode_; } - LockElement &operator=(LockElement &&other) noexcept { + LockElement& operator=(LockElement&& other) noexcept { if (this != &other) { key_ = other.key_; lock_ = other.lock_; diff --git a/cc/mocc/include/mocc_op_element.hh b/cc/mocc/include/mocc_op_element.hh index 9cfc2011..ba37c855 100644 --- a/cc/mocc/include/mocc_op_element.hh +++ b/cc/mocc/include/mocc_op_element.hh @@ -7,7 +7,7 @@ using std::cout; using std::endl; -template +template class ReadElement : public OpElement { public: using OpElement::OpElement; @@ -16,36 +16,36 @@ public: TupleBody body_; bool failed_verification_; - ReadElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body, Tidword tidword) - : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { + ReadElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + Tidword tidword) + : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { this->tidword_ = tidword; this->failed_verification_ = false; } - ReadElement(uint64_t key, T *rcdptr) : OpElement::OpElement(key, rcdptr) { + ReadElement(uint64_t key, T* rcdptr) : OpElement::OpElement(key, rcdptr) { failed_verification_ = true; } - bool operator<(const ReadElement &right) const { + bool operator<(const ReadElement& right) const { return this->rcdptr_ < right.rcdptr_; } }; -template +template class WriteElement : public OpElement { public: using OpElement::OpElement; TupleBody body_; - WriteElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, OpType op) - : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) { - } + WriteElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) {} WriteElement(Storage s, std::string_view key, T* rcdptr, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { - } + : OpElement::OpElement(s, key, rcdptr, op) {} - bool operator<(const WriteElement &right) const { + bool operator<(const WriteElement& right) const { return this->rcdptr_ < right.rcdptr_; } }; diff --git a/cc/mocc/include/result.hh b/cc/mocc/include/result.hh index 18de3cbc..bbf99f71 100644 --- a/cc/mocc/include/result.hh +++ b/cc/mocc/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector MoccResult; +extern std::vector MoccResult; extern void initResult(); diff --git a/cc/mocc/include/scan_callback.hh b/cc/mocc/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/mocc/include/scan_callback.hh +++ b/cc/mocc/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/mocc/include/transaction.hh b/cc/mocc/include/transaction.hh index 85bfd6ae..fda45481 100644 --- a/cc/mocc/include/transaction.hh +++ b/cc/mocc/include/transaction.hh @@ -28,19 +28,19 @@ class TxScanCallback; class TxExecutor { public: - vector > read_set_; - vector > write_set_; - vector pro_set_; + vector> read_set_; + vector> write_set_; + vector pro_set_; std::deque gc_records_; std::unordered_map node_map_; #ifdef RWLOCK vector> RLL_; vector> CLL_; -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK vector> RLL_; vector> CLL_; -#endif // MQLOCK +#endif // MQLOCK TransactionStatus status_; TxScanCallback callback_; @@ -49,7 +49,7 @@ public: Tidword max_rset_; Tidword max_wset_; Xoroshiro128Plus rnd_; - Result *result_; + Result* result_; uint64_t epoch_timer_start, epoch_timer_stop; Backoff backoff_; const bool& quit_; // for thread termination control @@ -58,21 +58,21 @@ public: bool is_batch_ = false; bool is_ronly_ = false; - TxExecutor(int thid, Result *res, const bool &quit) - : callback_(TxScanCallback(this)), thid_(thid), result_(res), - backoff_(FLAGS_clocks_per_us), quit_(quit) { + TxExecutor(int thid, Result* res, const bool& quit) + : callback_(TxScanCallback(this)), thid_(thid), result_(res), + backoff_(FLAGS_clocks_per_us), quit_(quit) { this->status_ = TransactionStatus::inflight; this->rnd_.init(); max_rset_.obj_ = 0; max_wset_.obj_ = 0; } - ReadElement *searchReadSet(Storage s, std::string_view key); + ReadElement* searchReadSet(Storage s, std::string_view key); - WriteElement *searchWriteSet(Storage s, std::string_view key); + WriteElement* searchWriteSet(Storage s, std::string_view key); - template - T *searchRLL(Tuple* key); + template + T* searchRLL(Tuple* key); void removeFromCLL(Tuple* key); @@ -84,23 +84,21 @@ public: Status update(Storage s, std::string_view key, TupleBody&& body); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); Status insert(Storage s, std::string_view key, TupleBody&& body); Status delete_record(Storage s, std::string_view key); - void lock(Tuple *tuple, bool mode); + void lock(Tuple* tuple, bool mode); - void construct_RLL(); // invoked on abort; + void construct_RLL(); // invoked on abort; void unlockCLL(); bool validation(); @@ -115,9 +113,9 @@ public: void leaderWork(); - void reconnoiter_begin(); + void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_end(); void gc_records(); @@ -127,7 +125,7 @@ public: void dispWS(); - Tuple *get_tuple(Tuple *table, uint64_t key) { return &table[key]; } + Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } }; static_assert(TxExecutorLike); diff --git a/cc/mocc/include/tuple.hh b/cc/mocc/include/tuple.hh index 2ca5407c..75ab1232 100644 --- a/cc/mocc/include/tuple.hh +++ b/cc/mocc/include/tuple.hh @@ -1,6 +1,6 @@ #pragma once -#include // memcpy +#include // memcpy #include #include @@ -15,19 +15,19 @@ struct Tidword { union { uint64_t obj_; struct { - bool absent: 1; - uint64_t tid: 31; - uint64_t epoch: 32; + bool absent : 1; + uint64_t tid : 31; + uint64_t epoch : 32; }; }; Tidword() { obj_ = 0; } - bool operator==(const Tidword &right) const { return obj_ == right.obj_; } + bool operator==(const Tidword& right) const { return obj_ == right.obj_; } - bool operator!=(const Tidword &right) const { return !operator==(right); } + bool operator!=(const Tidword& right) const { return !operator==(right); } - bool operator<(const Tidword &right) const { return this->obj_ < right.obj_; } + bool operator<(const Tidword& right) const { return this->obj_ < right.obj_; } }; // 32bit temprature, 32bit epoch @@ -35,8 +35,8 @@ struct Epotemp { union { alignas(CACHE_LINE_SIZE) uint64_t obj_; struct { - uint64_t temp: 32; - uint64_t epoch: 32; + uint64_t temp : 32; + uint64_t epoch : 32; }; }; @@ -44,9 +44,9 @@ struct Epotemp { Epotemp(uint64_t temp2, uint64_t epoch2) : temp(temp2), epoch(epoch2) {} - bool operator==(const Epotemp &right) const { return obj_ == right.obj_; } + bool operator==(const Epotemp& right) const { return obj_ == right.obj_; } - bool operator!=(const Epotemp &right) const { return !operator==(right); } + bool operator!=(const Epotemp& right) const { return !operator==(right); } bool eqEpoch(uint64_t epo) { if (epoch == epo) @@ -62,7 +62,7 @@ public: Epotemp epotemp_; TupleBody body_; #ifdef RWLOCK - ReaderWriterLock rwlock_; // 4byte + ReaderWriterLock rwlock_; // 4byte // size to here is 20 bytes #endif #ifdef MQLOCK @@ -71,7 +71,8 @@ public: Tuple() {} - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* p) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* p) { // for initializer tidword_.epoch = 1; tidword_.tid = 0; diff --git a/cc/mocc/include/util.hh b/cc/mocc/include/util.hh index 19c4f561..aa1cc8ab 100644 --- a/cc/mocc/include/util.hh +++ b/cc/mocc/include/util.hh @@ -10,7 +10,8 @@ extern void displayParameter(); extern void displayLockedTuple(); -extern void moccLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void moccLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); extern void makeDB(); diff --git a/cc/mocc/lock.cc b/cc/mocc/lock.cc index 86db251e..d59926e6 100644 --- a/cc/mocc/lock.cc +++ b/cc/mocc/lock.cc @@ -114,19 +114,19 @@ bool MQLMetaInfo::atomicCASNext(uint32_t oldnext, uint32_t newnext) { MQL_RESULT MQLock::acquire_reader_lock(uint32_t me, unsigned int key, bool trylock) { - MQLNode *qnode = &MQLNodeTable[me][key]; - qnode->init(LockMode::Reader, (uint32_t)SentinelValue::None, false, false, + MQLNode* qnode = &MQLNodeTable[me][key]; + qnode->init(LockMode::Reader, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); uint32_t p = tail.exchange(me); - if (p == (uint32_t)SentinelValue::None) { + if (p == (uint32_t) SentinelValue::None) { nreaders++; qnode->granted.store(true, std::memory_order_release); return finish_acquire_reader_lock(me, key); } - MQLNode *pred = &MQLNodeTable[p][key]; + MQLNode* pred = &MQLNodeTable[p][key]; // haven't set pred.next.id yet, safe to dereference pred if (pred->type.load(std::memory_order_acquire) == LockMode::Reader) return acquire_reader_lock_check_reader_pred(me, key, p, trylock); @@ -135,13 +135,13 @@ MQLock::acquire_reader_lock(uint32_t me, unsigned int key, bool trylock) { MQL_RESULT MQLock::finish_acquire_reader_lock(uint32_t me, unsigned int key) { - MQLNode *qnode = &MQLNodeTable[me][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; qnode->sucInfo.atomicStoreBusy(true); qnode->sucInfo.atomicStoreStatus(LockStatus::Granted); // spin until me.next is not SuccessorLeaving while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; // if the lock tail now still points to me, truly no one is there, we're done @@ -152,12 +152,12 @@ MQLock::finish_acquire_reader_lock(uint32_t me, unsigned int key) { } // note that the successor can't cancel now, ie me.next pointer is stable - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) ; uint32_t sucnum = qnode->sucInfo.atomicLoadNext(); - MQLNode *suc = &MQLNodeTable[sucnum][key]; - if (sucnum == (uint32_t)SentinelValue::None || + MQLNode* suc = &MQLNodeTable[sucnum][key]; + if (sucnum == (uint32_t) SentinelValue::None || suc->type.load(std::memory_order_acquire) == LockMode::Writer) { qnode->sucInfo.atomicStoreBusy(false); return MQL_RESULT::Acquired; @@ -173,7 +173,7 @@ MQLock::finish_acquire_reader_lock(uint32_t me, unsigned int key) { // // if not CAS(me.next, successor, None) // tanabe. ここに来るということは,successor は何かしらいて,Reader である - if (!qnode->sucInfo.atomicCASNext(sucnum, (uint32_t)SentinelValue::None)) { + if (!qnode->sucInfo.atomicCASNext(sucnum, (uint32_t) SentinelValue::None)) { // tanabe. CAS に失敗したら,以前認識した successor // はキャンセルして離脱した. qnode->sucInfo.atomicStoreBusy(false); @@ -186,23 +186,23 @@ MQLock::finish_acquire_reader_lock(uint32_t me, unsigned int key) { // register as a reader. ie successor was acquiring while (suc->prev.load(std::memory_order_acquire) != me) ; - if (suc->prev.compare_exchange_strong(me, (uint32_t)SentinelValue::Acquired, + if (suc->prev.compare_exchange_strong(me, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) { nreaders++; suc->granted.store(true, std::memory_order_release); // make sure I know when releasing no need to wait - qnode->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + qnode->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); } else if (qnode->sucInfo.atomicLoadStype() == LockMode::Reader) { for (;;) { while (suc->prev.load(std::memory_order_acquire) == me) ; if (suc->prev.compare_exchange_strong( - me, (uint32_t)SentinelValue::Acquired, std::memory_order_acq_rel, + me, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) { nreaders++; suc->granted.store(true, std::memory_order_release); - qnode->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + qnode->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); break; } } @@ -217,23 +217,23 @@ MQLock::acquire_reader_lock_check_reader_pred(uint32_t me, unsigned int key, uint32_t pred, bool trylock) { check_pred: uint32_t pretail; - MQLNode *qnode = &MQLNodeTable[me][key]; - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; + MQLNode* p = &MQLNodeTable[pred][key]; // wait for the previous canceling dude to leave - while (!(p->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None && + while (!(p->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None && p->sucInfo.atomicLoadStype() == LockMode::None)) ; MQLMetaInfo expected, desired; expected.init(false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); desired.init(false, LockMode::Reader, LockStatus::Waiting, me); __atomic_compare_exchange_n(&(p->sucInfo.obj), &expected.obj, desired.obj, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); if (p->sucInfo.atomicLoadBusy() == false && p->sucInfo.atomicLoadStype() == LockMode::Reader && - p->sucInfo.atomicLoadStatus() == LockStatus::Waiting) { // succeeded + p->sucInfo.atomicLoadStatus() == LockStatus::Waiting) { // succeeded // link_pred(pred, me) p->sucInfo.atomicStoreNext(me); @@ -264,8 +264,8 @@ MQLock::acquire_reader_lock_check_reader_pred(uint32_t me, unsigned int key, while (qnode->prev.load(std::memory_order_acquire) != pred) ; // consume it and retry - pretail = qnode->prev.exchange((uint32_t)SentinelValue::None); - if (pretail == (uint32_t)SentinelValue::Acquired) { + pretail = qnode->prev.exchange((uint32_t) SentinelValue::None); + if (pretail == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; return finish_acquire_reader_lock(me, key); @@ -274,7 +274,7 @@ MQLock::acquire_reader_lock_check_reader_pred(uint32_t me, unsigned int key, if (p->type.load(std::memory_order_acquire) == LockMode::Writer) return acquire_reader_lock_check_writer_pred(me, key, pretail, trylock); pred = pretail; - goto check_pred; // p must point to a valid predecessor; + goto check_pred; // p must point to a valid predecessor; } else { // pred is granted - might be a direct grant or grant in the leaving process // I didn't register, pred won't wake me up, but if pred is leaving_granted, @@ -283,7 +283,7 @@ MQLock::acquire_reader_lock_check_reader_pred(uint32_t me, unsigned int key, // also set its next.id to None so it knows that there's no need to wait and // examine successor upon release. This also covers the // case when pred.next.flags has Busy set. - p->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + p->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); nreaders++; qnode->granted.store(true, std::memory_order_release); return finish_acquire_reader_lock(me, key); @@ -293,11 +293,11 @@ MQLock::acquire_reader_lock_check_reader_pred(uint32_t me, unsigned int key, MQL_RESULT MQLock::cancel_reader_lock(uint32_t me, unsigned int key) { NNN; - MQLNode *qnode = &MQLNodeTable[me][key]; - uint32_t pred = qnode->prev.exchange((uint32_t)SentinelValue::None); + MQLNode* qnode = &MQLNodeTable[me][key]; + uint32_t pred = qnode->prev.exchange((uint32_t) SentinelValue::None); // prevent from cancelling - if (pred == (uint32_t)SentinelValue::Acquired) { + if (pred == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; return finish_acquire_reader_lock(me, key); @@ -306,7 +306,7 @@ MQLock::cancel_reader_lock(uint32_t me, unsigned int key) { // make sure successor can't leave, unless it tried to leave first qnode->sucInfo.atomicStoreStatus(LockStatus::Leaving); while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; // pred not equal qnode->prev. @@ -323,8 +323,8 @@ MQLock::cancel_reader_lock_with_writer_pred(uint32_t me, unsigned int key, uint32_t pred) { NNN; retry: - MQLNode *qnode = &MQLNodeTable[me][key]; - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; + MQLNode* p = &MQLNodeTable[pred][key]; // wait for the cancelling pred to finish relink // spin until pred.next is me and pred.stype is Reader // pred is a writer, so I can go as long as it's not also leaving (cancelling @@ -339,9 +339,9 @@ MQLock::cancel_reader_lock_with_writer_pred(uint32_t me, unsigned int key, qnode->prev.store(pred, std::memory_order_release); while (qnode->prev.load(std::memory_order_acquire) != pred) ; - pred = qnode->prev.exchange((uint32_t)SentinelValue::None); - if (pred == (uint32_t)SentinelValue::None || - pred == (uint32_t)SentinelValue::Acquired) { + pred = qnode->prev.exchange((uint32_t) SentinelValue::None); + if (pred == (uint32_t) SentinelValue::None || + pred == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; return finish_acquire_reader_lock(me, key); @@ -349,7 +349,7 @@ MQLock::cancel_reader_lock_with_writer_pred(uint32_t me, unsigned int key, // make sure successor can't leave, unless it tried to leave first qnode->sucInfo.atomicStoreStatus(LockStatus::Leaving); while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; // (tanabe) pred may be changed to new value at L:340 p = &MQLNodeTable[pred][key]; @@ -371,18 +371,18 @@ MQLock::cancel_reader_lock_with_writer_pred(uint32_t me, unsigned int key, expected = eflags; expected.next = me; desired = expected; - desired.next = (uint32_t)SentinelValue::SuccessorLeaving; + desired.next = (uint32_t) SentinelValue::SuccessorLeaving; if (p->atomicCASSucInfo(expected, desired)) break; } // pred now has SuccessorLeaving on its next.id, it won't try to wake me up // during release now link the new successor and pred - if (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None && + if (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None && tail.compare_exchange_strong(me, pred, std::memory_order_acq_rel, std::memory_order_acquire)) { p = &MQLNodeTable[pred][key]; p->sucInfo.atomicStoreStype(LockMode::None); - p->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + p->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } @@ -395,8 +395,8 @@ MQLock::cancel_reader_lock_with_reader_pred(uint32_t me, unsigned int key, uint32_t pred) { NNN; retry: - MQLNode *qnode = &MQLNodeTable[me][key]; - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; + MQLNode* p = &MQLNodeTable[pred][key]; // now successor can't attach to me assuming I'm waiting or has already done // so. CAS out of pred.next (including id and flags) wait for the canceling // pred to finish the relink spin until pred.stype is Reader and (pred.next is @@ -405,7 +405,7 @@ MQLock::cancel_reader_lock_with_reader_pred(uint32_t me, unsigned int key, MQLMetaInfo expected, desired; expected.init(false, LockMode::Reader, LockStatus::Waiting, me); desired.init(false, LockMode::Reader, LockStatus::Waiting, - (uint32_t)SentinelValue::SuccessorLeaving); + (uint32_t) SentinelValue::SuccessorLeaving); if (!p->atomicCASSucInfo(expected, desired)) { // Note: we once registered after pred as a reader successor (still are), so // if pred happens to get the lock, it will wake me up seeing its @@ -427,13 +427,13 @@ MQLock::cancel_reader_lock_with_reader_pred(uint32_t me, unsigned int key, while (qnode->prev.load(std::memory_order_acquire) != pred) ; // consume it and retry - pred = qnode->prev.exchange((uint32_t)SentinelValue::None); - if (pred == (uint32_t)SentinelValue::Acquired) { + pred = qnode->prev.exchange((uint32_t) SentinelValue::None); + if (pred == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; return finish_acquire_reader_lock(me, key); } - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* p = &MQLNodeTable[pred][key]; if (p->type.load(std::memory_order_acquire) == LockMode::Writer) return cancel_reader_lock_with_writer_pred(me, key, pred); goto retry; @@ -447,7 +447,7 @@ MQLock::cancel_reader_lock_with_reader_pred(uint32_t me, unsigned int key, // newly arriving successor for this pred will wait // for the SuccessorLeaving mark to go away before trying the CAS p->sucInfo.atomicStoreStype(LockMode::None); - p->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + p->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } cancel_reader_lock_relink(pred, me, key); @@ -459,11 +459,11 @@ MQL_RESULT MQLock::cancel_reader_lock_relink(uint32_t pred, uint32_t me, unsigned int key) { NNN; - MQLNode *qnode = &MQLNodeTable[me][key]; - MQLNode *p = &MQLNodeTable[pred][key]; - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) + MQLNode* qnode = &MQLNodeTable[me][key]; + MQLNode* p = &MQLNodeTable[pred][key]; + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) ; - for (;;) { // preserve pred.flags + for (;;) { // preserve pred.flags MQLMetaInfo expected, desired; expected = p->atomicLoadSucInfo(); desired = expected; @@ -476,7 +476,7 @@ MQLock::cancel_reader_lock_relink(uint32_t pred, uint32_t me, // I believe we should do this after setting pred.id, see the comment in // cancel_writer_lock. retry untill CAS(me,next.prev, me, pred) is True for (;;) { - MQLNode *suc = &MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key]; + MQLNode* suc = &MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key]; uint32_t expected = me; if (suc->prev.compare_exchange_strong(expected, pred, std::memory_order_acq_rel, @@ -492,11 +492,11 @@ MQLock::acquire_reader_lock_check_writer_pred(uint32_t me, unsigned int key, // wait for the previous canceling dude to leave spin // until pred.next is NULL and pred.stype is None // pred is a writer, we have to wait anyway, so register and wait with timeout - MQLNode *qnode = &MQLNodeTable[me][key]; - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; + MQLNode* p = &MQLNodeTable[pred][key]; p->sucInfo.atomicStoreStype(LockMode::Reader); p->sucInfo.atomicStoreNext(me); - if (qnode->prev.exchange(pred) == (uint32_t)SentinelValue::Acquired) { + if (qnode->prev.exchange(pred) == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; return finish_acquire_reader_lock(me, key); @@ -517,16 +517,16 @@ MQLock::acquire_reader_lock_check_writer_pred(uint32_t me, unsigned int key, void MQLock::release_reader_lock(uint32_t me, unsigned int key) { // make sure successor can't leave; readers, however, can still get the lock // as usual by seeing me.next.flags.granted set - MQLNode *qnode = &MQLNodeTable[me][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; qnode->sucInfo.atomicStoreBusy(true); while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; uint32_t expected; - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) { + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) { expected = me; - if (tail.compare_exchange_strong(expected, (uint32_t)SentinelValue::None, + if (tail.compare_exchange_strong(expected, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { return finish_release_reader_lock(me, key); @@ -535,15 +535,15 @@ void MQLock::release_reader_lock(uint32_t me, unsigned int key) { qnode->sucInfo.atomicLoadNext(), tail.load()); } - if (qnode->sucInfo.atomicLoadNext() != (uint32_t)SentinelValue::None && + if (qnode->sucInfo.atomicLoadNext() != (uint32_t) SentinelValue::None && qnode->sucInfo.atomicLoadStype() == LockMode::Writer) { // put it in next_writer - next_writer = (uint32_t)qnode->sucInfo.atomicLoadNext(); + next_writer = (uint32_t) qnode->sucInfo.atomicLoadNext(); // also tell successor it doesn't have pred any more - MQLNode *suc = &MQLNodeTable[next_writer][key]; + MQLNode* suc = &MQLNodeTable[next_writer][key]; expected = me; while (!suc->prev.compare_exchange_strong( - expected, (uint32_t)SentinelValue::None, std::memory_order_acq_rel, + expected, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { expected = me; } @@ -556,15 +556,15 @@ void MQLock::finish_release_reader_lock(uint32_t me, unsigned int key) { if (nreaders.fetch_sub(1) == 1) { // I'm the last reader, must handle the next writer. uint32_t nw = next_writer; - if (nw != (uint32_t)SentinelValue::None && + if (nw != (uint32_t) SentinelValue::None && nreaders.load(std::memory_order_acquire) == 0 && - next_writer.compare_exchange_strong(nw, (uint32_t)SentinelValue::None, + next_writer.compare_exchange_strong(nw, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { for (;;) { - uint32_t expected = (uint32_t)SentinelValue::None; + uint32_t expected = (uint32_t) SentinelValue::None; if (MQLNodeTable[nw][key].prev.compare_exchange_strong( - expected, (uint32_t)SentinelValue::Acquired, + expected, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) break; } @@ -575,17 +575,17 @@ void MQLock::finish_release_reader_lock(uint32_t me, unsigned int key) { MQL_RESULT MQLock::acquire_writer_lock(uint32_t me, unsigned int key, bool trylock) { - MQLNode *qnode = &MQLNodeTable[me][key]; - qnode->init(LockMode::Writer, (uint32_t)SentinelValue::None, false, false, + MQLNode* qnode = &MQLNodeTable[me][key]; + qnode->init(LockMode::Writer, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); uint32_t pred = tail.exchange(me); - MQLNode *p = &MQLNodeTable[pred][key]; - if (pred == (uint32_t)SentinelValue::None) { + MQLNode* p = &MQLNodeTable[pred][key]; + if (pred == (uint32_t) SentinelValue::None) { next_writer.store(me, std::memory_order_release); if (nreaders.load(std::memory_order_acquire) == 0 && - next_writer.exchange((uint32_t)SentinelValue::None) == me) { + next_writer.exchange((uint32_t) SentinelValue::None) == me) { qnode->granted.store(true, std::memory_order_release); return MQL_RESULT::Acquired; } @@ -593,9 +593,9 @@ MQLock::acquire_writer_lock(uint32_t me, unsigned int key, bool trylock) { // MQLNode *p = &MQLNodeTable[pred][key]; // spin until pred.stype is None and pred.next is NULL while (!(p->sucInfo.atomicLoadStype() == LockMode::None && - p->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None)) { + p->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None)) { printf("th %d : aq wl %d : p->stype %d p->next %d\n", me, key, - (int)p->sucInfo.atomicLoadStype(), p->sucInfo.atomicLoadNext()); + (int) p->sucInfo.atomicLoadStype(), p->sucInfo.atomicLoadNext()); } // printf("th %d : acquire wl %d\n", me, key); // register on pred.flags as a writer successor, @@ -607,7 +607,7 @@ MQLock::acquire_writer_lock(uint32_t me, unsigned int key, bool trylock) { p->sucInfo.atomicStoreStype(LockMode::Writer); p->sucInfo.atomicStoreNext(me); - if (qnode->prev.exchange(pred) == (uint32_t)SentinelValue::Acquired) { + if (qnode->prev.exchange(pred) == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; qnode->sucInfo.atomicStoreStatus(LockStatus::Granted); @@ -631,33 +631,33 @@ MQLock::acquire_writer_lock(uint32_t me, unsigned int key, bool trylock) { } void MQLock::release_writer_lock(uint32_t me, unsigned int key) { - MQLNode *qnode = &MQLNodeTable[me][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; qnode->sucInfo.atomicStoreBusy(true); // make sure successor can't leave while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) { + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) { // printf("th %d : release wl %d\n", me, key); uint32_t expected, desired; expected = me; - desired = (uint32_t)SentinelValue::None; + desired = (uint32_t) SentinelValue::None; if (tail.compare_exchange_strong(expected, desired, std::memory_order_acq_rel, std::memory_order_acquire)) { - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return; } printf("th %d : rl wl %d : next %d tail %d\n", me, key, qnode->sucInfo.atomicLoadNext(), tail.load()); } - MQLNode *suc; + MQLNode* suc; for (;;) { - uint32_t expected(me), desired((uint32_t)SentinelValue::Acquired); + uint32_t expected(me), desired((uint32_t) SentinelValue::Acquired); suc = &MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key]; if (suc->prev.compare_exchange_strong(expected, desired, std::memory_order_acq_rel, @@ -668,9 +668,9 @@ void MQLock::release_writer_lock(uint32_t me, unsigned int key) { if (suc->type.load(std::memory_order_acquire) == LockMode::Reader) nreaders++; suc->granted.store(true, std::memory_order_release); - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return; } @@ -678,14 +678,14 @@ MQL_RESULT MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { NNN; start_cancel: - MQLNode *qnode = &MQLNodeTable[me][key]; - uint32_t pred = qnode->prev.exchange((uint32_t)SentinelValue::None); - MQLNode *p = &MQLNodeTable[pred][key]; + MQLNode* qnode = &MQLNodeTable[me][key]; + uint32_t pred = qnode->prev.exchange((uint32_t) SentinelValue::None); + MQLNode* p = &MQLNodeTable[pred][key]; // if pred is a releasing writer and already dereference my id, it will CAS // me.pred.id to Acquired, so we do a final check here; there's no way back // after this point (unless pred is a reader and it's already gone). After my // xchg, pred will be waiting for me to give it a new successor. - if (pred == (uint32_t)SentinelValue::Acquired) { + if (pred == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; qnode->sucInfo.atomicStoreStatus(LockStatus::Granted); @@ -695,7 +695,7 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { // "freeze" the successor qnode->sucInfo.atomicStoreStatus(LockStatus::Leaving); while (qnode->sucInfo.atomicLoadNext() == - (uint32_t)SentinelValue::SuccessorLeaving) + (uint32_t) SentinelValue::SuccessorLeaving) ; // if I still have a pred, then deregister from it; @@ -704,7 +704,7 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { // Note that the reader should first reset me.pred.id, // then put me on lock.nw if (qnode->prev.load(std::memory_order_acquire) == - (uint32_t)SentinelValue::None) + (uint32_t) SentinelValue::None) return cancel_writer_lock_no_pred(me, key); for (;;) { @@ -737,21 +737,21 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { return MQL_RESULT::Acquired; } qnode->prev.store(pred, std::memory_order_release); - pred = qnode->prev.exchange((uint32_t)SentinelValue::None); - if (pred == (uint32_t)SentinelValue::None) + pred = qnode->prev.exchange((uint32_t) SentinelValue::None); + if (pred == (uint32_t) SentinelValue::None) return cancel_writer_lock_no_pred(me, key); - else if (pred == (uint32_t)SentinelValue::Acquired) { + else if (pred == (uint32_t) SentinelValue::Acquired) { while (qnode->granted.load(std::memory_order_acquire) != true) ; qnode->sucInfo.atomicStoreStatus(LockStatus::Granted); return MQL_RESULT::Acquired; } - continue; // retry if it's a reader + continue; // retry if it's a reader } MQLMetaInfo expected, desired; desired = pflags; - desired.next = (uint32_t)SentinelValue::SuccessorLeaving; + desired.next = (uint32_t) SentinelValue::SuccessorLeaving; expected = pflags; expected.next = me; if (p->atomicCASSucInfo(expected, desired)) break; @@ -760,24 +760,24 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { { // This scope means taht I want to use the name "expected", "desired" later. uint32_t expected(me), desired(pred); - if (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None && + if (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None && tail.compare_exchange_strong(expected, desired, std::memory_order_acq_rel, std::memory_order_acquire)) { p->sucInfo.atomicStoreStype(LockMode::None); - p->sucInfo.atomicStoreNext((uint32_t)SentinelValue::None); + p->sucInfo.atomicStoreNext((uint32_t) SentinelValue::None); // initialize MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key].prev.store( - (uint32_t)SentinelValue::None, std::memory_order_release); - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + (uint32_t) SentinelValue::None, std::memory_order_release); + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } } - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) ; MQLMetaInfo successor; successor.init(false, qnode->sucInfo.atomicLoadStype(), LockStatus::Waiting, @@ -797,7 +797,7 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { // block and ends before it releases. During this period my relink is // essentially invisible to pred. So we try to wake up the successor if this // the case. - successor.next = (uint32_t)SentinelValue::None; + successor.next = (uint32_t) SentinelValue::None; wakeup = true; } @@ -811,14 +811,14 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { // successor, we need to also set pred.next.id to NoSuccessor, which makes it // not safe for succ to spin on pred.next.id to wait for me finishing this // relink (pred might disappear any time because its next.id is NoSuccessor). - MQLNode *suc = &MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key]; + MQLNode* suc = &MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key]; if (wakeup) { nreaders++; suc->granted.store(true, std::memory_order_release); for (;;) { uint32_t localme = me; if (suc->prev.compare_exchange_strong( - localme, (uint32_t)SentinelValue::Acquired, + localme, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) break; } @@ -833,24 +833,24 @@ MQLock::cancel_writer_lock(uint32_t me, unsigned int key) { } MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key].prev.store( - (uint32_t)SentinelValue::None, std::memory_order_release); - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + (uint32_t) SentinelValue::None, std::memory_order_release); + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } MQL_RESULT MQLock::cancel_writer_lock_no_pred(uint32_t me, unsigned int key) { NNN; - MQLNode *qnode = &MQLNodeTable[me][key]; - while (!(next_writer != (uint32_t)SentinelValue::None || + MQLNode* qnode = &MQLNodeTable[me][key]; + while (!(next_writer != (uint32_t) SentinelValue::None || qnode->granted.load(std::memory_order_acquire) == true)) ; uint32_t localme(me); if (qnode->granted.load(std::memory_order_acquire) == true || !next_writer.compare_exchange_strong( - localme, (uint32_t)SentinelValue::None, std::memory_order_acq_rel, + localme, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { // reader picked me up... while (qnode->granted.load(std::memory_order_acquire) != true) @@ -861,33 +861,33 @@ MQLock::cancel_writer_lock_no_pred(uint32_t me, unsigned int key) { // so lock.next_writer is null now, try to fix the lock tail localme = me; - if (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None && - tail.compare_exchange_strong(localme, (uint32_t)SentinelValue::None, + if (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None && + tail.compare_exchange_strong(localme, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key].prev.store( - (uint32_t)SentinelValue::None, std::memory_order_release); - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + (uint32_t) SentinelValue::None, std::memory_order_release); + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } - while (qnode->sucInfo.atomicLoadNext() == (uint32_t)SentinelValue::None) + while (qnode->sucInfo.atomicLoadNext() == (uint32_t) SentinelValue::None) ; uint32_t localnext = qnode->sucInfo.atomicLoadNext(); // must copy first; // // because I don't have a pred, if next_id is a writer, I should put it in // lock.nw - MQLNode *suc = &MQLNodeTable[localnext][key]; + MQLNode* suc = &MQLNodeTable[localnext][key]; if (suc->type.load(std::memory_order_acquire) == LockMode::Writer) { // remaining readers will use CAS on lock.nw, so we blind write next_writer.store(localnext, std::memory_order_release); for (;;) { uint32_t forlocalme(me); if (suc->prev.compare_exchange_strong( - forlocalme, (uint32_t)SentinelValue::None, + forlocalme, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) break; } @@ -895,13 +895,13 @@ MQLock::cancel_writer_lock_no_pred(uint32_t me, unsigned int key) { uint32_t casnext(localnext); if (nreaders.load(std::memory_order_acquire) == 0 && next_writer.compare_exchange_strong( - casnext, (uint32_t)SentinelValue::None, std::memory_order_acq_rel, + casnext, (uint32_t) SentinelValue::None, std::memory_order_acq_rel, std::memory_order_acquire)) { // ok, I'm so nice, cancelled myself and woke up a successor for (;;) { - uint32_t forSentiNone = (uint32_t)SentinelValue::None; + uint32_t forSentiNone = (uint32_t) SentinelValue::None; if (suc->prev.compare_exchange_strong( - forSentiNone, (uint32_t)SentinelValue::Acquired, + forSentiNone, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) ; } @@ -912,7 +912,7 @@ MQLock::cancel_writer_lock_no_pred(uint32_t me, unsigned int key) { for (;;) { uint32_t forme(me); if (suc->prev.compare_exchange_strong( - forme, (uint32_t)SentinelValue::Acquired, + forme, (uint32_t) SentinelValue::Acquired, std::memory_order_acq_rel, std::memory_order_acquire)) break; } @@ -921,13 +921,13 @@ MQLock::cancel_writer_lock_no_pred(uint32_t me, unsigned int key) { } MQLNodeTable[qnode->sucInfo.atomicLoadNext()][key].prev.store( - (uint32_t)SentinelValue::None, std::memory_order_release); - qnode->init(LockMode::None, (uint32_t)SentinelValue::None, false, false, + (uint32_t) SentinelValue::None, std::memory_order_release); + qnode->init(LockMode::None, (uint32_t) SentinelValue::None, false, false, LockMode::None, LockStatus::Waiting, - (uint32_t)SentinelValue::None); + (uint32_t) SentinelValue::None); return MQL_RESULT::Cancelled; } -#endif // MQLOCK +#endif // MQLOCK #ifdef RWLOCK void ReaderWriterLock::r_lock() { @@ -999,4 +999,4 @@ bool ReaderWriterLock::upgrade() { return counter_.compare_exchange_weak(expected, -1, std::memory_order_acq_rel); } -#endif // RWLOCK +#endif // RWLOCK diff --git a/cc/mocc/mocc.cc b/cc/mocc/mocc.cc index 5639bae9..aeda9705 100644 --- a/cc/mocc/mocc.cc +++ b/cc/mocc/mocc.cc @@ -1,12 +1,12 @@ -#include // isdigit, +#include // isdigit, #include -#include // strlen, -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // strlen, +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // string +#include // string #define GLOBAL_VALUE_DEFINE @@ -28,14 +28,14 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Xoroshiro128Plus rnd; rnd.init(); - TxExecutor trans(thid, &rnd, (Result *) &MoccResult[thid]); + TxExecutor trans(thid, &rnd, (Result*) &MoccResult[thid]); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); uint64_t epoch_timer_start, epoch_timer_stop; Backoff backoff(FLAGS_clocks_per_us); - Result &myres = std::ref(MoccResult[thid]); + Result& myres = std::ref(MoccResult[thid]); #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); @@ -43,26 +43,24 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { #ifdef Linux setThreadAffinity(thid); -#endif // Linux +#endif // Linux uint64_t tuples = FLAGS_tuple_num; - if (FLAGS_batch_simple_rr) { - tuples = FLAGS_tuple_num - FLAGS_batch_tuples; - } + if (FLAGS_batch_simple_rr) { tuples = FLAGS_tuple_num - FLAGS_batch_tuples; } storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { auto r = rnd.next() % 100; - if ((FLAGS_thread_num && thid >= FLAGS_thread_num) - || (r < FLAGS_batch_ratio)) { + if ((FLAGS_thread_num && thid >= FLAGS_thread_num) || + (r < FLAGS_batch_ratio)) { trans.is_batch_ = true; - makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, - FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, - myres); - } else if (r >= FLAGS_batch_ratio - && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, + FLAGS_batch_tuples, FLAGS_batch_max_ope, + FLAGS_batch_rratio, FLAGS_rmw, myres); + } else if (r >= FLAGS_batch_ratio && + r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { trans.is_batch_ = false; makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, FLAGS_max_ope, myres); @@ -72,7 +70,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, thid, myres); } -RETRY: + RETRY: if (thid == 0) { leaderWork(epoch_timer_start, epoch_timer_stop, myres); leaderBackoffWork(backoff, MoccResult); @@ -112,9 +110,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } #ifdef INSERT_BATCH_DELAY_MS - if (trans.is_batch_) { - sleepMs(INSERT_BATCH_DELAY_MS); - } + if (trans.is_batch_) { sleepMs(INSERT_BATCH_DELAY_MS); } #endif if (!(trans.commit())) { @@ -137,17 +133,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { */ if (trans.is_batch_) { storeRelease(myres.local_batch_commit_counts_, - loadAcquire(myres.local_batch_commit_counts_) + 1); + loadAcquire(myres.local_batch_commit_counts_) + 1); } else { storeRelease(myres.local_commit_counts_, - loadAcquire(myres.local_commit_counts_) + 1); + loadAcquire(myres.local_commit_counts_) + 1); } } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("MOCC benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); @@ -164,15 +160,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MoccResult[0].addLocalAllResult(MoccResult[i]); @@ -180,10 +174,8 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/mocc/sbomb_mocc.cc b/cc/mocc/sbomb_mocc.cc index 7df7e91f..133b2d99 100644 --- a/cc/mocc/sbomb_mocc.cc +++ b/cc/mocc/sbomb_mocc.cc @@ -1,12 +1,12 @@ -#include // isdigit, +#include // isdigit, #include -#include // strlen, -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // strlen, +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // string +#include // string #define GLOBAL_VALUE_DEFINE @@ -30,10 +30,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(MoccResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(MoccResult[thid]); TxExecutor trans(thid, &myres, quit); - StaticBombWorkload workload; + StaticBombWorkload workload; workload.prepare(trans, nullptr); #if MASSTREE_USE @@ -42,24 +42,24 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { #ifdef Linux setThreadAffinity(thid); -#endif // Linux +#endif // Linux storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB MOCC benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); - StaticBombWorkload::makeDB(nullptr); + StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -72,15 +72,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MoccResult[0].addLocalAllResult(MoccResult[i]); @@ -88,11 +86,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; MoccResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mocc/tpcc_mocc.cc b/cc/mocc/tpcc_mocc.cc index 169a2e82..bc61ee10 100644 --- a/cc/mocc/tpcc_mocc.cc +++ b/cc/mocc/tpcc_mocc.cc @@ -1,12 +1,12 @@ -#include // isdigit, +#include // isdigit, #include -#include // strlen, -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // strlen, +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // string +#include // string #define GLOBAL_VALUE_DEFINE @@ -30,10 +30,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(MoccResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(MoccResult[thid]); TxExecutor trans(thid, &myres, quit); - TPCCWorkload workload; + TPCCWorkload workload; workload.prepare(trans, nullptr); #if MASSTREE_USE @@ -42,24 +42,24 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { #ifdef Linux setThreadAffinity(thid); -#endif // Linux +#endif // Linux storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C MOCC benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -72,15 +72,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MoccResult[0].addLocalAllResult(MoccResult[i]); @@ -88,11 +86,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; MoccResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mocc/transaction.cc b/cc/mocc/transaction.cc index c5abdc38..2e4874a7 100644 --- a/cc/mocc/transaction.cc +++ b/cc/mocc/transaction.cc @@ -13,7 +13,8 @@ using namespace std; extern std::vector MoccResult; -extern void moccLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void moccLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); /** * @brief Search xxx set @@ -23,8 +24,8 @@ extern void moccLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_st * @param Key [in] the key of key-value * @return Corresponding element of local set */ -ReadElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { +ReadElement* TxExecutor::searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -40,8 +41,9 @@ ReadElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { * @param Key [in] the key of key-value * @return Corresponding element of local set */ -WriteElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { +WriteElement* TxExecutor::searchWriteSet(Storage s, + std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -54,8 +56,8 @@ WriteElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) * @param key [in] The key of key-value * @return Corresponding element of retrospective lock list */ -template -T *TxExecutor::searchRLL(Tuple* key) { +template +T* TxExecutor::searchRLL(Tuple* key) { // will do : binary search for (auto itr = RLL_.begin(); itr != RLL_.end(); ++itr) { if ((*itr).key_ == key) return &(*itr); @@ -134,7 +136,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search record from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -152,7 +154,8 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { return Status::OK; } -Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Status TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { // Default constructor of these variable cause error (-fpermissive) // "crosses initialization of ..." // So it locate before first goto instruction. @@ -162,13 +165,13 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) // tuple doesn't exist in read/write set. #ifdef RWLOCK - LockElement *inRLL; + LockElement* inRLL; inRLL = searchRLL>(tuple); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK - LockElement *inRLL; + LockElement* inRLL; inRLL = searchRLL>(tuple); -#endif // MQLOCK +#endif // MQLOCK /** * Check corresponding temperature. @@ -234,7 +237,7 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) return Status::ERROR_LOCK_FAILED; } else { expected.obj_ = - __atomic_load_n(&(tuple->tidword_.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(tuple->tidword_.obj_), __ATOMIC_ACQUIRE); } } @@ -244,7 +247,8 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) } // read - b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), tuple->body_.get_val_align()); + b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), + tuple->body_.get_val_align()); desired.obj_ = __atomic_load_n(&(tuple->tidword_.obj_), __ATOMIC_ACQUIRE); if (expected == desired) @@ -257,35 +261,34 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) // So it can load payload atomically by one loading tidword. expected.obj_ = __atomic_load_n(&(tuple->tidword_.obj_), __ATOMIC_ACQUIRE); // read - b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), tuple->body_.get_val_align()); + b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), + tuple->body_.get_val_align()); } read_set_.emplace_back(s, key, tuple, std::move(b), expected); return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { ReadElement* re = searchReadSet(s, itr->body_.get_key()); if (re) { result.emplace_back(&(re->body_)); @@ -303,8 +306,8 @@ Status TxExecutor::scan(const Storage s, } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).body_)); } } @@ -329,8 +332,8 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { // tuple exists in write set. if (searchWriteSet(s, key)) goto FINISH_WRITE; - Tuple *tuple; - ReadElement *re; + Tuple* tuple; + ReadElement* re; re = searchReadSet(s, key); if (re) { /** @@ -360,17 +363,19 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * If it failed locking, it aborts. */ - if (this->status_ == TransactionStatus::aborted) return Status::WARN_NOT_FOUND; + if (this->status_ == TransactionStatus::aborted) + return Status::WARN_NOT_FOUND; #ifdef RWLOCK - LockElement *inRLL; + LockElement* inRLL; inRLL = searchRLL>(tuple); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK - LockElement *inRLL = searchRLL>(tuple); -#endif // MQLOCK + LockElement* inRLL = searchRLL>(tuple); +#endif // MQLOCK if (inRLL != nullptr) lock(tuple, true); - if (this->status_ == TransactionStatus::aborted) return Status::WARN_NOT_FOUND; + if (this->status_ == TransactionStatus::aborted) + return Status::WARN_NOT_FOUND; write_set_.emplace_back(s, key, tuple, std::move(body), OpType::UPDATE); @@ -392,22 +397,21 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(std::move(body)); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -438,9 +442,7 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple; @@ -451,7 +453,7 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { } else { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS - ++result_->local_tree_traversal_; + ++result_->local_tree_traversal_; #endif if (tuple == nullptr) return Status::WARN_NOT_FOUND; } @@ -472,12 +474,12 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; #ifdef RWLOCK - LockElement *inRLL; + LockElement* inRLL; inRLL = searchRLL>(tuple); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK - LockElement *inRLL = searchRLL>(tuple); -#endif // MQLOCK + LockElement* inRLL = searchRLL>(tuple); +#endif // MQLOCK if (inRLL != nullptr) lock(tuple, true); if (this->status_ == TransactionStatus::aborted) return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; @@ -618,19 +620,19 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // return; // } -void TxExecutor::lock(Tuple *tuple, bool mode) { +void TxExecutor::lock(Tuple* tuple, bool mode) { unsigned int vioctr = 0; // Sentinel "no violation found yet" (max pointer). The CLL_ scan // below overwrites this on the first violation; the explicit // `if (vioctr == 0) threshold = (Tuple*)-1` afterwards confirms the // default. Initializing here keeps GCC 13's -Wmaybe-uninitialized // happy without changing runtime semantics. - Tuple* threshold = (Tuple*)-1; + Tuple* threshold = (Tuple*) -1; bool upgrade = false; #ifdef RWLOCK - LockElement *le = nullptr; -#endif // RWLOCK + LockElement* le = nullptr; +#endif // RWLOCK // RWLOCK : アップグレードするとき,CLL_ ループで該当する // エレメントを記憶しておき,そのエレメントを更新するため. // MQLOCK : アップグレード機能が無いので,不要. @@ -648,7 +650,7 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { else { #ifdef RWLOCK le = &(*itr); -#endif // RWLOCK +#endif // RWLOCK upgrade = true; } } @@ -661,7 +663,7 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { } } - if (vioctr == 0) threshold = (Tuple*)-1; // max pointer address + if (vioctr == 0) threshold = (Tuple*) -1; // max pointer address // if too many violations // i set my condition of too many because the original paper of mocc didn't @@ -680,7 +682,8 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { return; } } else if (tuple->rwlock_.w_trylock()) { - CLL_.push_back(LockElement(tuple, &(tuple->rwlock_), true)); + CLL_.push_back( + LockElement(tuple, &(tuple->rwlock_), true)); return; } else { this->status_ = TransactionStatus::aborted; @@ -688,14 +691,15 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { } } else { if (tuple->rwlock_.r_trylock()) { - CLL_.push_back(LockElement(tuple, &(tuple->rwlock_), false)); + CLL_.push_back( + LockElement(tuple, &(tuple->rwlock_), false)); return; } else { this->status_ = TransactionStatus::aborted; return; } } -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK if (mode) { if (upgrade) { @@ -709,8 +713,8 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { this->status = TransactionStatus::aborted; return; } - } else if (tuple->mqlock.acquire_writer_lock(this->locknum, tuple, true) == - MQL_RESULT::Acquired) { + } else if (tuple->mqlock.acquire_writer_lock( + this->locknum, tuple, true) == MQL_RESULT::Acquired) { CLL_.push_back(LockElement(tuple, &(tuple->mqlock), true)); return; } else { @@ -727,7 +731,7 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { return; } } -#endif // MQLOCK +#endif // MQLOCK } if (vioctr != 0) { @@ -739,14 +743,14 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { (*itr).lock_->w_unlock(); else (*itr).lock_->r_unlock(); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK if ((*itr).mode_) (*itr).lock_->release_writer_lock(this->locknum, tuple); else (*itr).lock_->release_reader_lock(this->locknum, tuple); -#endif // MQLOCK +#endif // MQLOCK } // delete from CLL_ @@ -765,14 +769,14 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { (*itr).lock_->w_lock(); else (*itr).lock_->r_lock(); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK if ((*itr).mode_) (*itr).lock_->acquire_writer_lock(this->locknum, tuple); else (*itr).lock_->acquire_reader_lock(this->locknum, tuple); -#endif // MQLOCK +#endif // MQLOCK CLL_.emplace_back((*itr).key_, (*itr).lock_, (*itr).mode_); } else @@ -786,7 +790,7 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { tuple->rwlock_.r_lock(); CLL_.emplace_back(tuple, &(tuple->rwlock_), mode); return; -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK if (mode) @@ -795,7 +799,7 @@ void TxExecutor::lock(Tuple *tuple, bool mode) { tuple->mqlock.acquire_reader_lock(this->locknum, tuple, false); CLL_.push_back(LockElement(tuple, tuple->mqlock, mode)); return; -#endif // MQLOCK +#endif // MQLOCK } void TxExecutor::construct_RLL() { @@ -804,11 +808,11 @@ void TxExecutor::construct_RLL() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { #ifdef RWLOCK RLL_.emplace_back((*itr).rcdptr_, &((*itr).rcdptr_->rwlock_), true); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK - RLL_.push_back( - LockElement((*itr).rcdptr_, &(Table[(*itr).key_].mqlock), true)); -#endif // MQLOCK + RLL_.push_back(LockElement((*itr).rcdptr_, + &(Table[(*itr).key_].mqlock), true)); +#endif // MQLOCK } for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { @@ -854,11 +858,12 @@ void TxExecutor::construct_RLL() { // check whether itr exists in RLL_ #ifdef RWLOCK - if (searchRLL>((*itr).rcdptr_) != nullptr) continue; -#endif // RWLOCK + if (searchRLL>((*itr).rcdptr_) != nullptr) + continue; +#endif // RWLOCK #ifdef MQLOCK if (searchRLL>((*itr).rcdptr_) != nullptr) continue; -#endif // MQLOCK +#endif // MQLOCK // r not in RLL_ // if temprature >= threshold @@ -868,11 +873,11 @@ void TxExecutor::construct_RLL() { if (loadepot.temp >= FLAGS_temp_threshold || (*itr).failed_verification_) { #ifdef RWLOCK RLL_.emplace_back((*itr).rcdptr_, &((*itr).rcdptr_->rwlock_), false); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK - RLL_.push_back( - LockElement((*itr).rcdptr_, &((*itr).rcdptr_->mqlock_), false)); -#endif // MQLOCK + RLL_.push_back(LockElement((*itr).rcdptr_, + &((*itr).rcdptr_->mqlock_), false)); +#endif // MQLOCK } } @@ -889,8 +894,8 @@ bool TxExecutor::validation() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if (itr->op_ == OpType::INSERT) continue; lock((*itr).rcdptr_, true); - if (this->status_ == TransactionStatus::aborted - || (itr->op_ == OpType::UPDATE && itr->rcdptr_->tidword_.absent)) { + if (this->status_ == TransactionStatus::aborted || + (itr->op_ == OpType::UPDATE && itr->rcdptr_->tidword_.absent)) { this->status_ = TransactionStatus::aborted; return false; } @@ -898,15 +903,15 @@ bool TxExecutor::validation() { this->max_wset_ = max(this->max_wset_, (*itr).rcdptr_->tidword_); } - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); __atomic_store_n(&(ThLocalEpoch[thid_].obj_), (loadAcquireGE()).obj_, __ATOMIC_RELEASE); - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { Tidword check; check.obj_ = - __atomic_load_n(&((*itr).rcdptr_->tidword_.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&((*itr).rcdptr_->tidword_.obj_), __ATOMIC_ACQUIRE); if ((*itr).tidword_.epoch != check.epoch || (*itr).tidword_.tid != check.tid) { (*itr).failed_verification_ = true; @@ -921,24 +926,24 @@ bool TxExecutor::validation() { #ifdef RWLOCK if ((*itr).rcdptr_->rwlock_.ldAcqCounter() == W_LOCKED && searchWriteSet((*itr).storage_, (*itr).key_) == nullptr) { -#endif // RWLOCK - // if the rwlock is already acquired and the owner isn't me, abort. - (*itr).failed_verification_ = true; - this->status_ = TransactionStatus::aborted; +#endif // RWLOCK + // if the rwlock is already acquired and the owner isn't me, abort. + (*itr).failed_verification_ = true; + this->status_ = TransactionStatus::aborted; #if ADD_ANALYSIS - ++result_->local_validation_failure_by_writelock_; + ++result_->local_validation_failure_by_writelock_; #endif - return false; + return false; #ifdef RWLOCK } -#endif // RWLOCK +#endif // RWLOCK this->max_rset_ = max(this->max_rset_, (*itr).rcdptr_->tidword_); } // validate the node set for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { this->status_ = TransactionStatus::aborted; return false; @@ -998,7 +1003,7 @@ void TxExecutor::unlockCLL() { (*itr).lock_->w_unlock(); else (*itr).lock_->r_unlock(); -#endif // RWLOCK +#endif // RWLOCK #ifdef MQLOCK if ((*itr).mode_) { @@ -1035,8 +1040,8 @@ void TxExecutor::writePhase() { switch ((*itr).op_) { case OpType::UPDATE: { maxtid.absent = false; - memcpy((*itr).rcdptr_->body_.get_val_ptr(), - (*itr).body_.get_val_ptr(), (*itr).body_.get_val_size()); + memcpy((*itr).rcdptr_->body_.get_val_ptr(), (*itr).body_.get_val_ptr(), + (*itr).body_.get_val_size()); break; } case OpType::INSERT: { @@ -1047,14 +1052,16 @@ void TxExecutor::writePhase() { maxtid.absent = true; // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present( + (*itr).key_); gc_records_.push_back((*itr).rcdptr_); break; } default: ERR; } - __atomic_store_n(&((*itr).rcdptr_->tidword_.obj_), maxtid.obj_, __ATOMIC_RELEASE); + __atomic_store_n(&((*itr).rcdptr_->tidword_.obj_), maxtid.obj_, + __ATOMIC_RELEASE); } unlockCLL(); @@ -1074,9 +1081,7 @@ bool TxExecutor::commit() { } } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { moccLeaderWork(this->epoch_timer_start, this->epoch_timer_stop); @@ -1097,9 +1102,7 @@ void TxExecutor::gc_records() { } } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { unlockCLL(); @@ -1140,10 +1143,11 @@ void TxExecutor::dispWS() { cout << endl; } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/mocc/util.cc b/cc/mocc/util.cc index b1515981..608a808c 100644 --- a/cc/mocc/util.cc +++ b/cc/mocc/util.cc @@ -1,9 +1,9 @@ #include #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include #include @@ -51,7 +51,8 @@ void chkArg() { } if (FLAGS_per_xx_temp < sizeof(Tuple)) { - cout << "FLAGS_per_xx_temp's minimum is sizeof(Tuple) " << sizeof(Tuple) << endl; + cout << "FLAGS_per_xx_temp's minimum is sizeof(Tuple) " << sizeof(Tuple) + << endl; ERR; } @@ -60,22 +61,22 @@ void chkArg() { ERR; } - if (posix_memalign((void **) &Start, 64, + if (posix_memalign((void**) &Start, 64, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &Stop, 64, + if (posix_memalign((void**) &Stop, 64, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &ThLocalEpoch, 64, + if (posix_memalign((void**) &ThLocalEpoch, 64, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; #ifdef MQLOCK // if (posix_memalign((void**)&MQLNodeList, 64, (TotalThreadNum + 3) * // sizeof(MQLNode)) != 0) ERR; - MQLNodeTable = new MQLNode *[TotalThreadNum + 3]; + MQLNodeTable = new MQLNode*[TotalThreadNum + 3]; for (unsigned int i = 0; i < TotalThreadNum + 3; ++i) MQLNodeTable[i] = new MQLNode[TotalThreadNum]; -#endif // MQLOCK +#endif // MQLOCK for (unsigned int i = 0; i < TotalThreadNum; ++i) { ThLocalEpoch[i].obj_ = 0; @@ -192,7 +193,7 @@ bool chkEpochLoaded() { return true; } -void moccLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop) { +void moccLeaderWork(uint64_t& epoch_timer_start, uint64_t& epoch_timer_stop) { epoch_timer_stop = rdtscp(); // chkEpochLoaded は最新のグローバルエポックを //全てのワーカースレッドが読み込んだか確認する. @@ -206,7 +207,8 @@ void moccLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop) { #if TEMPERATURE_RESET_OPT #else - size_t epotemp_length = FLAGS_tuple_num * sizeof(Tuple) / FLAGS_per_xx_temp + 1; + size_t epotemp_length = + FLAGS_tuple_num * sizeof(Tuple) / FLAGS_per_xx_temp + 1; uint64_t nowepo = (loadAcquireGE()).obj_; for (uint64_t i = 0; i < epotemp_length; ++i) { Epotemp epotemp(0, nowepo); diff --git a/cc/mocc/ycsb_mocc.cc b/cc/mocc/ycsb_mocc.cc index 44971739..4f7801b4 100644 --- a/cc/mocc/ycsb_mocc.cc +++ b/cc/mocc/ycsb_mocc.cc @@ -1,12 +1,12 @@ -#include // isdigit, +#include // isdigit, #include -#include // strlen, -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // strlen, +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // string +#include // string #define GLOBAL_VALUE_DEFINE @@ -30,8 +30,8 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(MoccResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(MoccResult[thid]); TxExecutor trans(thid, &myres, quit); YcsbWorkload workload; @@ -41,24 +41,24 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { #ifdef Linux setThreadAffinity(thid); -#endif // Linux +#endif // Linux storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("YCSB MOCC benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -71,24 +71,21 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MoccResult[0].addLocalAllResult(MoccResult[i]); } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MoccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mvto/bomb_mvto.cc b/cc/mvto/bomb_mvto.cc index 3fa15be7..7f8eac50 100644 --- a/cc/mvto/bomb_mvto.cc +++ b/cc/mvto/bomb_mvto.cc @@ -27,10 +27,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &MvtoResult[thid], quit); - BombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &MvtoResult[thid], quit); + BombWorkload workload; workload.prepare(trans, new TupleInitParam()); #ifdef Linux @@ -38,13 +38,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -53,19 +53,19 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB MVTO benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); + BombWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - BombWorkload::makeDB(param); + BombWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -74,31 +74,28 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MvtoResult[0].addLocalAllResult(MvtoResult[i]); MvtoResult[0].addLocalPerTxResult(MvtoResult[i], TxTypes); } ShowOptParameters(); - MvtoResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MvtoResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; MvtoResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mvto/include/common.hh b/cc/mvto/include/common.hh index 9e492c7e..67011906 100644 --- a/cc/mvto/include/common.hh +++ b/cc/mvto/include/common.hh @@ -29,21 +29,25 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; alignas(CACHE_LINE_SIZE) GLOBAL std::atomic MinRts; alignas(CACHE_LINE_SIZE) GLOBAL std::atomic MinWts; alignas( -CACHE_LINE_SIZE) GLOBAL std::atomic FirstAllocateTimestamp; + CACHE_LINE_SIZE) GLOBAL std::atomic FirstAllocateTimestamp; #if MASSTREE_USE alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #endif #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint64(clocks_per_us, 2100, "CPU_MHz. Use this info for measuring time."); +DEFINE_uint64(clocks_per_us, 2100, + "CPU_MHz. Use this info for measuring time."); DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(gc_inter_us, 10, "GC interval[us]."); DEFINE_uint64(group_commit, 0, "Group commit number of transactions."); -DEFINE_uint64(group_commit_timeout_us, 2, "Timeout used for deadlock resolution when performing group commit[us]."); +DEFINE_uint64( + group_commit_timeout_us, 2, + "Timeout used for deadlock resolution when performing group commit[us]."); DEFINE_uint64(io_time_ns, 5, "Delay inserted instead of IO."); DEFINE_uint64(thread_num, 10, "Total number of worker threads."); -DEFINE_bool(preserve_write, false, "Install pending version in write operation"); +DEFINE_bool(preserve_write, false, + "Install pending version in write operation"); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(extime); @@ -55,25 +59,25 @@ DECLARE_bool(preserve_write); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThreadWtsArray; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThreadRtsArray; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte - *ThreadRtsArrayForGroup; // グループコミットをする時,これが必要である. +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThreadWtsArray; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThreadRtsArray; +alignas(CACHE_LINE_SIZE) GLOBAL + uint64_t_64byte* ThreadRtsArrayForGroup; // グループコミットをする時,これが必要である. -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GROUP_COMMIT_INDEX; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte - *GROUP_COMMIT_COUNTER; // s-walの時は[0]のみ使用。全スレッドで共有。 +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GROUP_COMMIT_INDEX; +alignas(CACHE_LINE_SIZE) GLOBAL + uint64_t_64byte* GROUP_COMMIT_COUNTER; // s-walの時は[0]のみ使用。全スレッドで共有。 alignas( -CACHE_LINE_SIZE) GLOBAL Version ***PLogSet; // [thID][index] pointer array -alignas(CACHE_LINE_SIZE) GLOBAL Version **SLogSet; // [index] pointer array + CACHE_LINE_SIZE) GLOBAL Version*** PLogSet; // [thID][index] pointer array +alignas(CACHE_LINE_SIZE) GLOBAL Version** SLogSet; // [index] pointer array GLOBAL RWLock SwalLock; GLOBAL RWLock CtrLock; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GCFlag; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *GCExecuteFlag; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GCFlag; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* GCExecuteFlag; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; alignas(CACHE_LINE_SIZE) GLOBAL uint64_t InitialWts; #define SPIN_WAIT_TIMEOUT_US 2 diff --git a/cc/mvto/include/lock.hh b/cc/mvto/include/lock.hh index 4553d945..dcc5a582 100644 --- a/cc/mvto/include/lock.hh +++ b/cc/mvto/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -40,7 +38,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -56,7 +54,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/cc/mvto/include/mvto_op_element.hh b/cc/mvto/include/mvto_op_element.hh index 62ebc589..d18eb9ef 100644 --- a/cc/mvto/include/mvto_op_element.hh +++ b/cc/mvto/include/mvto_op_element.hh @@ -4,26 +4,28 @@ #include "version.hh" -template +template class ReadElement : public OpElement { public: using OpElement::OpElement; Version *later_ver_, *ver_; - ReadElement(Storage s, std::string_view key, T *rcdptr, Version *later_ver, Version *ver) - : OpElement::OpElement(s, key, rcdptr) { + ReadElement(Storage s, std::string_view key, T* rcdptr, Version* later_ver, + Version* ver) + : OpElement::OpElement(s, key, rcdptr) { later_ver_ = later_ver; ver_ = ver; } - bool operator<(const ReadElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const ReadElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class WriteElement : public OpElement { public: using OpElement::OpElement; @@ -31,39 +33,46 @@ public: Version *later_ver_, *new_ver_; bool finish_version_install_; - WriteElement(Storage s, std::string_view key, T *rcdptr, Version *later_ver, Version *new_ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + WriteElement(Storage s, std::string_view key, T* rcdptr, Version* later_ver, + Version* new_ver, OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { later_ver_ = later_ver; new_ver_ = new_ver; finish_version_install_ = false; } - WriteElement(Storage s, std::string_view key, T *rcdptr, Version *new_ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + WriteElement(Storage s, std::string_view key, T* rcdptr, Version* new_ver, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { // for insert later_ver_ = nullptr; new_ver_ = new_ver; finish_version_install_ = true; } - bool operator<(const WriteElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const WriteElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class GCElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; uint64_t wts_; - GCElement() : ver_(nullptr), wts_(0) { this->s; this->key_ = ""; } + GCElement() : ver_(nullptr), wts_(0) { + this->s; + this->key_ = ""; + } - GCElement(Storage s, std::string_view key, T *rcdptr, Version *ver, uint64_t wts) - : OpElement::OpElement(s, key, rcdptr) { + GCElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + uint64_t wts) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; this->wts_ = wts; } diff --git a/cc/mvto/include/result.hh b/cc/mvto/include/result.hh index 3cb43112..bac1e4d8 100644 --- a/cc/mvto/include/result.hh +++ b/cc/mvto/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector MvtoResult; +extern std::vector MvtoResult; extern void initResult(); diff --git a/cc/mvto/include/time_stamp.hh b/cc/mvto/include/time_stamp.hh index df67c5f4..ab718c4b 100644 --- a/cc/mvto/include/time_stamp.hh +++ b/cc/mvto/include/time_stamp.hh @@ -14,7 +14,7 @@ public: inline uint64_t get_ts() { return ts_; } - inline void set_ts(uint64_t &ts) { this->ts_ = ts; } + inline void set_ts(uint64_t& ts) { this->ts_ = ts; } inline void generateTimeStampFirst(uint8_t tid) { localClock_ = rdtscp(); diff --git a/cc/mvto/include/transaction.hh b/cc/mvto/include/transaction.hh index 9aff2844..56752d58 100644 --- a/cc/mvto/include/transaction.hh +++ b/cc/mvto/include/transaction.hh @@ -39,7 +39,7 @@ public: std::deque gc_records_; // for records std::deque> gcq_; // for versions std::vector pro_set_; - Result *result_ = nullptr; + Result* result_ = nullptr; const bool& quit_; // for thread termination control Backoff& backoff_; @@ -50,15 +50,16 @@ public: uint8_t thid_ = 0; uint64_t rts_; - uint64_t start_, stop_; // for one-sided synchronization - uint64_t grpcmt_start_, grpcmt_stop_; // for group commit - uint64_t gcstart_, gcstop_; // for garbage collection + uint64_t start_, stop_; // for one-sided synchronization + uint64_t grpcmt_start_, grpcmt_stop_; // for group commit + uint64_t gcstart_, gcstop_; // for garbage collection - TxExecutor(uint8_t thid, Backoff& backoff, Result *res, const bool &quit) - : result_(res), quit_(quit), backoff_(backoff), thid_(thid) { + TxExecutor(uint8_t thid, Backoff& backoff, Result* res, const bool& quit) + : result_(res), quit_(quit), backoff_(backoff), thid_(thid) { // wait to initialize MinWts - while (MinWts.load(memory_order_acquire) == 0); + while (MinWts.load(memory_order_acquire) == 0) + ; rts_ = MinWts.load(memory_order_acquire) - 1; wts_.generateTimeStampFirst(thid_); @@ -94,15 +95,13 @@ public: Status delete_record(Storage s, std::string_view key); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); bool validation(); @@ -138,20 +137,21 @@ public: #endif } - void gcAfterThisVersion([[maybe_unused]] Tuple *tuple, Version *delTarget) { + void gcAfterThisVersion([[maybe_unused]] Tuple* tuple, Version* delTarget) { while (delTarget != nullptr) { // escape next pointer - Version *tmp = delTarget->next_.load(std::memory_order_acquire); + Version* tmp = delTarget->next_.load(std::memory_order_acquire); delete delTarget; -[[maybe_unused]] gcAfterThisVersion_NEXT_LOOP : + [[maybe_unused]] gcAfterThisVersion_NEXT_LOOP : #if ADD_ANALYSIS - ++result_->local_gc_version_counts_; + ++result_->local_gc_version_counts_; #endif delTarget = tmp; } } - Version *newVersionGeneration([[maybe_unused]] Tuple *tuple, TupleBody&& body) { + Version* newVersionGeneration([[maybe_unused]] Tuple* tuple, + TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_version_malloc_; #endif @@ -164,7 +164,7 @@ public: expected = tuple->ldAcqLatest(); version->strRelNext(expected); if (tuple->latest_.compare_exchange_strong( - expected, version, memory_order_acq_rel, memory_order_acquire)) { + expected, version, memory_order_acq_rel, memory_order_acquire)) { break; } } @@ -175,34 +175,34 @@ public: return get_latest_previous_version(this->wts_.ts_, version, &after); } - Version* get_latest_previous_version( - uint64_t base_timestamp, Version* version, [[maybe_unused]] Version** after) { + Version* get_latest_previous_version(uint64_t base_timestamp, + Version* version, + [[maybe_unused]] Version** after) { while (version->ldAcqWts() >= base_timestamp) { *after = version; version = version->ldAcqNext(); - if (version == nullptr) { - return nullptr; - } + if (version == nullptr) { return nullptr; } } - while (version->ldAcqStatus() == VersionStatus::pending); + while (version->ldAcqStatus() == VersionStatus::pending) + ; while (version->ldAcqStatus() == VersionStatus::aborted) { version = version->ldAcqNext(); - if (version == nullptr) { - return nullptr; - } - while (version->ldAcqStatus() == VersionStatus::pending); + if (version == nullptr) { return nullptr; } + while (version->ldAcqStatus() == VersionStatus::pending) + ; } return version; } void update_rts(Version* version) { - uint64_t expected = version->ldAcqRts(); - while (true) { - if (expected > this->wts_.ts_) break; - if (version->rts_.compare_exchange_strong( - expected, this->wts_.ts_, memory_order_acq_rel, memory_order_acquire)) - break; - } + uint64_t expected = version->ldAcqRts(); + while (true) { + if (expected > this->wts_.ts_) break; + if (version->rts_.compare_exchange_strong(expected, this->wts_.ts_, + memory_order_acq_rel, + memory_order_acquire)) + break; + } } /** @@ -213,8 +213,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline ReadElement *searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { + inline ReadElement* searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -230,8 +230,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline WriteElement *searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { + inline WriteElement* searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -240,19 +240,20 @@ public: } void clean_up_read_write_set() { - for (auto &we: write_set_) { + for (auto& we : write_set_) { if (we.op_ == OpType::INSERT) { Masstrees[get_storage(we.storage_)].remove_value(we.key_); delete we.rcdptr_; } else { - we.new_ver_->status_.store(VersionStatus::aborted, std::memory_order_release); + we.new_ver_->status_.store(VersionStatus::aborted, + std::memory_order_release); } } write_set_.clear(); read_set_.clear(); } - static INLINE Tuple *get_tuple(Tuple *table, uint64_t key) { + static INLINE Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } }; diff --git a/cc/mvto/include/tuple.hh b/cc/mvto/include/tuple.hh index bc1c8617..e35f0c4a 100644 --- a/cc/mvto/include/tuple.hh +++ b/cc/mvto/include/tuple.hh @@ -17,21 +17,20 @@ public: TupleInitParam() { tstmp.generateTimeStampFirst(0); - initial_wts = tstmp.ts_; + initial_wts = tstmp.ts_; } }; class Tuple { public: - alignas(CACHE_LINE_SIZE) - atomic latest_; - atomic min_wts_; - atomic gc_lock_; + alignas(CACHE_LINE_SIZE) atomic latest_; + atomic min_wts_; + atomic gc_lock_; TupleBody body_; // only used for index tuple as single version Tuple() : latest_(nullptr), gc_lock_(0) {} - Version *ldAcqLatest() { return latest_.load(std::memory_order_acquire); } + Version* ldAcqLatest() { return latest_.load(std::memory_order_acquire); } bool getGCRight(uint8_t thid) { uint8_t expected, desired(thid); @@ -47,13 +46,14 @@ public: void returnGCRight() { this->gc_lock_.store(0, std::memory_order_release); } - void init([[maybe_unused]] size_t thid, TupleBody&& body, TupleInitParam* param) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + TupleInitParam* param) { // for initializer min_wts_ = param->initial_wts; gc_lock_.store(0, std::memory_order_release); latest_.store(new Version(), std::memory_order_release); (latest_.load(std::memory_order_acquire)) - ->set(0, param->initial_wts, nullptr, VersionStatus::committed); + ->set(0, param->initial_wts, nullptr, VersionStatus::committed); (latest_.load(std::memory_order_acquire))->body_ = std::move(body); body_ = std::ref((latest_.load(std::memory_order_acquire))->body_); } diff --git a/cc/mvto/include/version.hh b/cc/mvto/include/version.hh index aa3d908a..4561e303 100644 --- a/cc/mvto/include/version.hh +++ b/cc/mvto/include/version.hh @@ -1,7 +1,7 @@ #pragma once #include -#include // memcpy +#include // memcpy #include #include @@ -21,10 +21,10 @@ enum class VersionStatus : uint8_t { class Version { public: - alignas(CACHE_LINE_SIZE) atomic rts_; - atomic wts_; - atomic next_; - atomic status_; // commit record + alignas(CACHE_LINE_SIZE) atomic rts_; + atomic wts_; + atomic next_; + atomic status_; // commit record TupleBody body_; @@ -41,14 +41,14 @@ public: } Version(const uint64_t rts, const uint64_t wts, TupleBody&& body) - : body_(body) { + : body_(body) { rts_.store(rts, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); status_.store(VersionStatus::pending, memory_order_release); next_.store(nullptr, memory_order_release); } - Version(const uint64_t wts) { + Version(const uint64_t wts) { rts_.store(0, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); status_.store(VersionStatus::pending, memory_order_release); @@ -56,21 +56,20 @@ public: } void displayInfo() { - printf( - "Version::displayInfo(): this: %p rts_: %lu: wts_: %lu: next_: %p: " - "status_: " - "%u\n", - this, ldAcqRts(), ldAcqWts(), ldAcqNext(), (uint8_t) ldAcqStatus()); + printf("Version::displayInfo(): this: %p rts_: %lu: wts_: %lu: next_: %p: " + "status_: " + "%u\n", + this, ldAcqRts(), ldAcqWts(), ldAcqNext(), (uint8_t) ldAcqStatus()); } - Version *latestCommittedVersionAfterThis() { - Version *version = this; + Version* latestCommittedVersionAfterThis() { + Version* version = this; while (version->ldAcqStatus() != VersionStatus::committed) version = version->ldAcqNext(); return version; } - Version *ldAcqNext() { return next_.load(std::memory_order_acquire); } + Version* ldAcqNext() { return next_.load(std::memory_order_acquire); } uint64_t ldAcqRts() { return rts_.load(std::memory_order_acquire); } @@ -88,7 +87,7 @@ public: body_ = std::move(body); } - void set(const uint64_t rts, const uint64_t wts, Version *next, + void set(const uint64_t rts, const uint64_t wts, Version* next, const VersionStatus status) { rts_.store(rts, memory_order_relaxed); wts_.store(wts, memory_order_relaxed); @@ -96,9 +95,9 @@ public: next_.store(next, memory_order_release); } - Version *skipTheStatusVersionAfterThis(const VersionStatus status, + Version* skipTheStatusVersionAfterThis(const VersionStatus status, const bool pendingWait) { - Version *ver = this; + Version* ver = this; VersionStatus local_status = ver->ldAcqStatus(); if (pendingWait) while (local_status == VersionStatus::pending) { @@ -115,20 +114,22 @@ public: return ver; } - Version *skipNotTheStatusVersionAfterThis(const VersionStatus status, + Version* skipNotTheStatusVersionAfterThis(const VersionStatus status, const bool pendingWait) { - Version *ver = this; + Version* ver = this; if (pendingWait) - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; while (ver->ldAcqStatus() != status) { ver = ver->ldAcqNext(); if (pendingWait) - while (ver->ldAcqStatus() == VersionStatus::pending); + while (ver->ldAcqStatus() == VersionStatus::pending) + ; } return ver; } - void strRelNext(Version *next) { // store release next = strRelNext + void strRelNext(Version* next) { // store release next = strRelNext next_.store(next, std::memory_order_release); } }; diff --git a/cc/mvto/tpcc_mvto.cc b/cc/mvto/tpcc_mvto.cc index 7c07b811..605fd42a 100644 --- a/cc/mvto/tpcc_mvto.cc +++ b/cc/mvto/tpcc_mvto.cc @@ -27,10 +27,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &MvtoResult[thid], quit); - TPCCWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &MvtoResult[thid], quit); + TPCCWorkload workload; workload.prepare(trans, new TupleInitParam()); #ifdef Linux @@ -44,19 +44,19 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C MVTO benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::displayWorkloadParameter(); TupleInitParam* param = new TupleInitParam(); - TPCCWorkload::makeDB(param); + TPCCWorkload::makeDB(param); MinWts.store(param->initial_wts + 2, memory_order_release); alignas(CACHE_LINE_SIZE) bool start = false; @@ -70,15 +70,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { MvtoResult[0].addLocalAllResult(MvtoResult[i]); @@ -86,11 +84,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - MvtoResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + MvtoResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; MvtoResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/mvto/transaction.cc b/cc/mvto/transaction.cc index 7bc0a6bb..a909cf77 100644 --- a/cc/mvto/transaction.cc +++ b/cc/mvto/transaction.cc @@ -10,7 +10,8 @@ #include "include/transaction.hh" #include "include/version.hh" -extern bool chkClkSpan(const uint64_t start, const uint64_t stop, const uint64_t threshold); +extern bool chkClkSpan(const uint64_t start, const uint64_t stop, + const uint64_t threshold); extern void displaySLogSet(); extern void displayDB(); extern void mvtoLeaderWork(); @@ -31,12 +32,14 @@ void TxExecutor::begin() { */ this->status_ = TransactionStatus::inflight; this->wts_.generateTimeStamp(thid_); - __atomic_store_n(&(ThreadWtsArray[thid_].obj_), this->wts_.ts_, __ATOMIC_RELEASE); + __atomic_store_n(&(ThreadWtsArray[thid_].obj_), this->wts_.ts_, + __ATOMIC_RELEASE); this->rts_ = MinWts.load(std::memory_order_acquire) - 1; __atomic_store_n(&(ThreadRtsArray[thid_].obj_), this->rts_, __ATOMIC_RELEASE); } -Version *TxExecutor::read_internal(Storage s, std::string_view key, Tuple *tuple) { +Version* TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { Version *ver, *later_ver; later_ver = nullptr; @@ -50,9 +53,7 @@ Version *TxExecutor::read_internal(Storage s, std::string_view key, Tuple *tuple update_rts(ver); } - if (ver->ldAcqStatus() == VersionStatus::deleted) { - return nullptr; - } + if (ver->ldAcqStatus() == VersionStatus::deleted) { return nullptr; } read_set_.emplace_back(s, key, tuple, later_ver, ver); return ver; @@ -62,14 +63,14 @@ Version *TxExecutor::read_internal(Storage s, std::string_view key, Tuple *tuple * @brief Transaction read function. * @param [in] key The key of key-value */ -Status TxExecutor::read(Storage s, std::string_view key, TupleBody **body) { +Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS - Version *ver; - ReadElement *re; - WriteElement *we; + Version* ver; + ReadElement* re; + WriteElement* we; /** * read-own-writes or re-read from local read set. @@ -88,11 +89,11 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody **body) { /** * Search versions from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; ver = read_internal(s, key, tuple); @@ -103,7 +104,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody **body) { */ *body = &(ver->body_); - FINISH_READ: +FINISH_READ: #if ADD_ANALYSIS result_->local_read_latency_ += rdtscp() - start; #endif @@ -114,16 +115,16 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody **body) { * @brief Transaction write function. * @param [in] key The key of key-value */ -Status TxExecutor::update(Storage s, std::string_view key, TupleBody &&body) { +Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (searchWriteSet(s, key)) goto FINISH_WRITE; - Tuple *tuple; + Tuple* tuple; bool rmw; rmw = false; - ReadElement *re; + ReadElement* re; re = searchReadSet(s, key); if (re) { rmw = true; @@ -132,44 +133,40 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody &&body) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } // Install new version with pending state - Version *new_ver; + Version* new_ver; new_ver = newVersionGeneration(tuple, std::move(body)); - if (FLAGS_preserve_write) { - install_version(tuple, new_ver); - } + if (FLAGS_preserve_write) { install_version(tuple, new_ver); } - write_set_.emplace_back( - s, key, tuple, nullptr, new_ver, rmw ? OpType::RMW : OpType::UPDATE); + write_set_.emplace_back(s, key, tuple, nullptr, new_ver, + rmw ? OpType::RMW : OpType::UPDATE); - FINISH_WRITE: +FINISH_WRITE: #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } -Status TxExecutor::insert(Storage s, std::string_view key, TupleBody &&body) { +Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; - Tuple *tuple = Masstrees[get_storage(s)].get_value(key); + Tuple* tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); - Version *new_ver = newVersionGeneration(tuple, std::move(body)); + Version* new_ver = newVersionGeneration(tuple, std::move(body)); tuple->init(this->thid_, new_ver, this->wts_.ts_, std::move(body)); Status stat = Masstrees[get_storage(s)].insert_value(key, tuple); @@ -182,25 +179,23 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody &&body) { #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } Status TxExecutor::delete_record(Storage s, std::string_view key) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } - Tuple *tuple; - ReadElement *re; + Tuple* tuple; + ReadElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -208,56 +203,53 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } // Install delete version with pending state - Version *new_ver; + Version* new_ver; new_ver = new Version(this->wts_.ts_); - if (FLAGS_preserve_write) { - install_version(tuple, new_ver); - } + if (FLAGS_preserve_write) { install_version(tuple, new_ver); } write_set_.emplace_back(s, key, tuple, nullptr, new_ver, OpType::DELETE); #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector &result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector &result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); - std::vector scan_res; + std::vector scan_res; Masstrees[get_storage(s)].scan( left_key.empty() ? nullptr : left_key.data(), left_key.size(), l_exclusive, right_key.empty() ? nullptr : right_key.data(), right_key.size(), r_exclusive, &scan_res, limit); - for (auto &&itr: scan_res) { + for (auto&& itr : scan_res) { // TODO: Tuple should have key? Accessing key through the latest ver is ugly // Must be a copy to avoid buffer overflow when changing the latest std::string key(itr->latest_.load(memory_order_acquire)->body_.get_key()); - ReadElement *re = searchReadSet(s, key); + ReadElement* re = searchReadSet(s, key); if (re) { result.emplace_back(&(re->ver_->body_)); continue; } - WriteElement *we = searchWriteSet(s, std::string_view(key)); + WriteElement* we = searchWriteSet(s, std::string_view(key)); if (we) { result.emplace_back(&(we->new_ver_->body_)); continue; @@ -266,14 +258,14 @@ Status TxExecutor::scan(const Storage s, // read_internal pushes the visible version into read_set_ on success; // the caller appends from read_set_ at the bottom of scan(). The return // value is only useful for in-place reads, which scan() does not need. - (void)read_internal(s, key, itr); + (void) read_internal(s, key, itr); if (this->status_ == TransactionStatus::aborted) return Status::ERROR_PREEMPTIVE_ABORT; } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).ver_->body_)); } } @@ -284,15 +276,13 @@ Status TxExecutor::scan(const Storage s, bool TxExecutor::validation() { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS bool result(true); // Install versions if (!FLAGS_preserve_write) { - for (auto &we : write_set_) { - if (we.op_ == OpType::INSERT) { - continue; - } + for (auto& we : write_set_) { + if (we.op_ == OpType::INSERT) { continue; } install_version(we.rcdptr_, we.new_ver_); } } @@ -302,8 +292,8 @@ bool TxExecutor::validation() { *(a) every previously visible version v of the records in the read set is the * currently visible version to the transaction. */ - for (auto &re : read_set_) { - Version *ver = re.later_ver_ ? re.later_ver_ : re.rcdptr_->ldAcqLatest(); + for (auto& re : read_set_) { + Version* ver = re.later_ver_ ? re.later_ver_ : re.rcdptr_->ldAcqLatest(); ver = get_latest_previous_version(ver); /** * This part is different from the original. @@ -320,36 +310,36 @@ bool TxExecutor::validation() { * (b) every currently visible version v of the records in the write set * satisfies (v.rts) <= (tx.ts) */ - for (auto &we : write_set_) { - if (we.op_ == OpType::INSERT) { - continue; - } - Version *ver = get_latest_previous_version(we.new_ver_); - if (ver->ldAcqRts() > this->wts_.ts_ || ver->ldAcqStatus() == VersionStatus::deleted) { + for (auto& we : write_set_) { + if (we.op_ == OpType::INSERT) { continue; } + Version* ver = get_latest_previous_version(we.new_ver_); + if (ver->ldAcqRts() > this->wts_.ts_ || + ver->ldAcqStatus() == VersionStatus::deleted) { result = false; goto FINISH_VALIDATION; } } - FINISH_VALIDATION: +FINISH_VALIDATION: #if ADD_ANALYSIS result_->local_vali_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return result; } inline void TxExecutor::commit_pending_versions() { - for (auto &we : write_set_) { + for (auto& we : write_set_) { if (we.op_ == OpType::DELETE) { Masstrees[get_storage(we.storage_)].remove_value(we.key_); - we.new_ver_->status_.store(VersionStatus::deleted, std::memory_order_release); + we.new_ver_->status_.store(VersionStatus::deleted, + std::memory_order_release); gc_records_.push_back(we.rcdptr_); } else { - we.new_ver_->status_.store(VersionStatus::committed, std::memory_order_release); + we.new_ver_->status_.store(VersionStatus::committed, + std::memory_order_release); } - gcq_.emplace_back( - GCElement( - we.storage_, we.key_, we.rcdptr_, we.new_ver_, this->wts_.ts_)); + gcq_.emplace_back(GCElement(we.storage_, we.key_, we.rcdptr_, we.new_ver_, + this->wts_.ts_)); } } @@ -381,7 +371,7 @@ void TxExecutor::gc_versions() { continue; } - Tuple *tuple = gcq_.front().rcdptr_; + Tuple* tuple = gcq_.front().rcdptr_; // (b) v.wts > record.min_wts if (gcq_.front().wts_ <= tuple->min_wts_) { // releases the lock @@ -391,7 +381,7 @@ void TxExecutor::gc_versions() { } // this pointer may be dangling. - Version *delTarget = + Version* delTarget = gcq_.front().ver_->next_.load(std::memory_order_acquire); // the thread detaches the rest of the version list from v @@ -410,8 +400,8 @@ void TxExecutor::gc_records() { // for records while (!gc_records_.empty()) { - Tuple *rec = gc_records_.front(); - Version *latest = rec->ldAcqLatest(); + Tuple* rec = gc_records_.front(); + Version* latest = rec->ldAcqLatest(); if (latest->ldAcqWts() >= MinRts.load(memory_order_acquire)) break; if (latest->ldAcqStatus() != VersionStatus::deleted) ERR; delete rec; @@ -443,7 +433,8 @@ void TxExecutor::maintenance() { } this->gcstop_ = rdtscp(); - if (chkClkSpan(this->gcstart_, this->gcstop_, FLAGS_gc_inter_us * FLAGS_clocks_per_us) && + if (chkClkSpan(this->gcstart_, this->gcstop_, + FLAGS_gc_inter_us * FLAGS_clocks_per_us) && (loadAcquire(GCFlag[thid_].obj_) == 0)) { storeRelease(GCFlag[thid_].obj_, 1); this->gcstart_ = this->gcstop_; @@ -479,9 +470,7 @@ bool TxExecutor::commit() { /** * Validation phase */ - if (!validation()) { - return false; - } + if (!validation()) { return false; } /** * Write phase @@ -496,9 +485,7 @@ bool TxExecutor::commit() { } } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { mvtoLeaderWork(); @@ -507,9 +494,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); diff --git a/cc/mvto/util.cc b/cc/mvto/util.cc index 49e66bc4..751bfb74 100644 --- a/cc/mvto/util.cc +++ b/cc/mvto/util.cc @@ -21,25 +21,25 @@ void chkArg() { exit(0); } - if (posix_memalign((void **) &ThreadRtsArrayForGroup, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadRtsArrayForGroup, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &ThreadWtsArray, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadWtsArray, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &ThreadRtsArray, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThreadRtsArray, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GROUP_COMMIT_INDEX, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GROUP_COMMIT_INDEX, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GROUP_COMMIT_COUNTER, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GROUP_COMMIT_COUNTER, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GCFlag, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GCFlag, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &GCExecuteFlag, CACHE_LINE_SIZE, + if (posix_memalign((void**) &GCExecuteFlag, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; @@ -92,13 +92,13 @@ void mvtoLeaderWork() { } if (gc_update) { uint64_t minw = - __atomic_load_n(&(ThreadWtsArray[0].obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(ThreadWtsArray[0].obj_), __ATOMIC_ACQUIRE); uint64_t minr; minr = __atomic_load_n(&(ThreadRtsArray[0].obj_), __ATOMIC_ACQUIRE); for (unsigned int i = 1; i < TotalThreadNum; ++i) { uint64_t tmp = - __atomic_load_n(&(ThreadWtsArray[i].obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(ThreadWtsArray[i].obj_), __ATOMIC_ACQUIRE); if (minw > tmp) minw = tmp; tmp = __atomic_load_n(&(ThreadRtsArray[i].obj_), __ATOMIC_ACQUIRE); if (minr > tmp) minr = tmp; @@ -117,10 +117,7 @@ void mvtoLeaderWork() { void ShowOptParameters() { cout << "#ShowOptParameters()" - << ": ADD_ANALYSIS " << ADD_ANALYSIS - << ": BACK_OFF " << BACK_OFF - << ": MASSTREE_USE " << MASSTREE_USE - << ": KEY_SIZE " << KEY_SIZE - << ": VAL_SIZE " << VAL_SIZE - << endl; + << ": ADD_ANALYSIS " << ADD_ANALYSIS << ": BACK_OFF " << BACK_OFF + << ": MASSTREE_USE " << MASSTREE_USE << ": KEY_SIZE " << KEY_SIZE + << ": VAL_SIZE " << VAL_SIZE << endl; } diff --git a/cc/occ/include/common.hh b/cc/occ/include/common.hh index 1994482f..ec635b83 100644 --- a/cc/occ/include/common.hh +++ b/cc/occ/include/common.hh @@ -55,7 +55,7 @@ DECLARE_bool(ycsb); DECLARE_double(zipf_skew); #endif -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThLocalEpoch; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *CTIDW; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThLocalEpoch; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* CTIDW; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; diff --git a/cc/occ/include/log.hh b/cc/occ/include/log.hh index d38e2e42..fc82ab77 100644 --- a/cc/occ/include/log.hh +++ b/cc/occ/include/log.hh @@ -6,7 +6,7 @@ #include class LogHeader { - public: +public: int chkSum_ = 0; unsigned int logRecNum_ = 0; const std::size_t len_val_ = VAL_SIZE; @@ -23,21 +23,21 @@ class LogHeader { }; class LogRecord { - public: +public: uint64_t tid_; unsigned int key_; char val_[VAL_SIZE]; LogRecord() : tid_(0), key_(0) {} - LogRecord(uint64_t tid, unsigned int key, char *val) : tid_(tid), key_(key) { + LogRecord(uint64_t tid, unsigned int key, char* val) : tid_(tid), key_(key) { memcpy(this->val_, val, VAL_SIZE); } int computeChkSum() { // compute checksum int chkSum = 0; - int *itr = (int *)this; + int* itr = (int*) this; for (unsigned int i = 0; i < sizeof(LogRecord) / sizeof(int); ++i) { chkSum += (*itr); ++itr; @@ -48,7 +48,7 @@ class LogRecord { }; class LogPackage { - public: +public: LogHeader header_; std::unique_ptr log_records_; }; diff --git a/cc/occ/include/occ_op_element.hh b/cc/occ/include/occ_op_element.hh index 1f117dad..f2336a72 100644 --- a/cc/occ/include/occ_op_element.hh +++ b/cc/occ/include/occ_op_element.hh @@ -4,7 +4,7 @@ template class ReadElement : public OpElement { - public: +public: using OpElement::OpElement; char val_[VAL_SIZE]; @@ -21,7 +21,7 @@ class ReadElement : public OpElement { template class WriteElement : public OpElement { - public: +public: using OpElement::OpElement; WriteElement(uint64_t key, T* rcdptr) diff --git a/cc/occ/include/transaction.hh b/cc/occ/include/transaction.hh index c6e3118f..352077e7 100644 --- a/cc/occ/include/transaction.hh +++ b/cc/occ/include/transaction.hh @@ -27,7 +27,7 @@ enum class TransactionStatus : uint8_t { }; class TxnExecutor { - public: +public: ReadSet read_set_; WriteSet write_set_; ProcedureSet pro_set_; diff --git a/cc/occ/include/tuple.hh b/cc/occ/include/tuple.hh index ae7244a1..8745e06f 100644 --- a/cc/occ/include/tuple.hh +++ b/cc/occ/include/tuple.hh @@ -9,6 +9,6 @@ #include "../../../include/cache_line_size.hh" class Tuple { - public: +public: char val_[VAL_SIZE]; }; diff --git a/cc/occ/include/util.hh b/cc/occ/include/util.hh index ff32a386..5d38a43a 100644 --- a/cc/occ/include/util.hh +++ b/cc/occ/include/util.hh @@ -8,7 +8,7 @@ extern void displayDB(); extern void displayParameter(); -extern void genLogFile(std::string &logpath, const int thid); +extern void genLogFile(std::string& logpath, const int thid); extern void leaderWork(); diff --git a/cc/occ/occ.cc b/cc/occ/occ.cc index 585fd66c..67061268 100644 --- a/cc/occ/occ.cc +++ b/cc/occ/occ.cc @@ -41,7 +41,7 @@ void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Result& myres = std::ref(OccResult[thid]); Xoroshiro128Plus rnd; rnd.init(); - TxnExecutor trans(thid, (Result*)&myres); + TxnExecutor trans(thid, (Result*) &myres); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -158,9 +158,7 @@ int main(int argc, char* argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); for (auto& th : thv) th.join(); @@ -169,9 +167,7 @@ int main(int argc, char* argv[]) try { } ShowOptParameters(); OccResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - FLAGS_thread_num); + FLAGS_thread_num); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/occ/transaction.cc b/cc/occ/transaction.cc index 7f550710..bcfc86f1 100644 --- a/cc/occ/transaction.cc +++ b/cc/occ/transaction.cc @@ -30,7 +30,7 @@ vector ws_list; uint64_t deletedTxId = -1; vector progress; -TxnExecutor::TxnExecutor(int thid, Result *sres) : thid_(thid), sres_(sres) { +TxnExecutor::TxnExecutor(int thid, Result* sres) : thid_(thid), sres_(sres) { read_set_.reserve(FLAGS_max_ope); write_set_.reserve(FLAGS_max_ope); pro_set_.reserve(FLAGS_max_ope); @@ -38,7 +38,7 @@ TxnExecutor::TxnExecutor(int thid, Result *sres) : thid_(thid), sres_(sres) { genStringRepeatedNumber(write_val_, VAL_SIZE, thid); } -ReadElement *TxnExecutor::searchReadSet(uint64_t key) { +ReadElement* TxnExecutor::searchReadSet(uint64_t key) { for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { if ((*itr).key_ == key) return &(*itr); } @@ -46,7 +46,7 @@ ReadElement *TxnExecutor::searchReadSet(uint64_t key) { return nullptr; } -WriteElement *TxnExecutor::searchWriteSet(uint64_t key) { +WriteElement* TxnExecutor::searchWriteSet(uint64_t key) { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).key_ == key) return &(*itr); } @@ -54,14 +54,12 @@ WriteElement *TxnExecutor::searchWriteSet(uint64_t key) { return nullptr; } -void TxnExecutor::begin() { - startTxId = loadAcquire(txId); -} +void TxnExecutor::begin() { startTxId = loadAcquire(txId); } void TxnExecutor::read(uint64_t key) { if (searchReadSet(key) || searchWriteSet(key)) goto FINISH_READ; - Tuple *tuple; + Tuple* tuple; #if MASSTREE_USE tuple = MT.get_value(key); #else @@ -76,8 +74,8 @@ void TxnExecutor::read(uint64_t key) { void TxnExecutor::write(uint64_t key) { if (searchWriteSet(key)) goto FINISH_WRITE; - Tuple *tuple; - ReadElement *re; + Tuple* tuple; + ReadElement* re; re = searchReadSet(key); if (re) { tuple = re->rcdptr_; @@ -100,9 +98,7 @@ bool TxnExecutor::validationPhase() { for (int i = begin; i < end; i++) { for (auto rItr = read_set_.begin(); rItr != read_set_.end(); ++rItr) { for (auto wItr = ws_list[i].begin(); wItr != ws_list[i].end(); ++wItr) { - if ((*rItr).key_ == (*wItr).key_) { - return false; - } + if ((*rItr).key_ == (*wItr).key_) { return false; } } } } @@ -150,12 +146,12 @@ void TxnExecutor::wal(uint64_t ctid) { latest_log_header_.convertChkSumIntoComplementOnTwo(); // write header - logfile_.write((void *)&latest_log_header_, sizeof(LogHeader)); + logfile_.write((void*) &latest_log_header_, sizeof(LogHeader)); // write log record // for (auto itr = log_set_.begin(); itr != log_set_.end(); ++itr) // logfile_.write((void *)&(*itr), sizeof(LogRecord)); - logfile_.write((void *)&(log_set_[0]), + logfile_.write((void*) &(log_set_[0]), sizeof(LogRecord) * latest_log_header_.logRecNum_); // logfile_.fdatasync(); diff --git a/cc/occ/util.cc b/cc/occ/util.cc index ef08e77b..ca329a5a 100644 --- a/cc/occ/util.cc +++ b/cc/occ/util.cc @@ -1,8 +1,8 @@ #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include @@ -32,19 +32,17 @@ void chkArg() { displayParameter(); - if (FLAGS_rratio > 100) { - ERR; - } + if (FLAGS_rratio > 100) { ERR; } if (FLAGS_zipf_skew >= 1) { cout << "FLAGS_zipf_skew must be 0 ~ 0.999..." << endl; ERR; } - if (posix_memalign((void **)&ThLocalEpoch, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThLocalEpoch, CACHE_LINE_SIZE, FLAGS_thread_num * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **)&CTIDW, CACHE_LINE_SIZE, + if (posix_memalign((void**) &CTIDW, CACHE_LINE_SIZE, FLAGS_thread_num * sizeof(uint64_t_64byte)) != 0) ERR; @@ -67,10 +65,10 @@ bool chkEpochLoaded() { } void displayDB() { - Tuple *tuple; + Tuple* tuple; for (unsigned int i = 0; i < FLAGS_tuple_num; ++i) { tuple = &Table[i]; - cout << "------------------------------" << endl; //-は30個 + cout << "------------------------------" << endl; //-は30個 cout << "key: " << i << endl; cout << "val: " << tuple->val_ << endl; cout << endl; @@ -89,7 +87,7 @@ void displayParameter() { cout << "#FLAGS_zipf_skew:\t" << FLAGS_zipf_skew << endl; } -void genLogFile(std::string &logpath, const int thid) { +void genLogFile(std::string& logpath, const int thid) { genLogFileName(logpath, thid); createEmptyFile(logpath); } @@ -100,7 +98,7 @@ void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end) { #endif for (auto i = start; i <= end; ++i) { - Tuple *tmp; + Tuple* tmp; tmp = &Table[i]; tmp->val_[0] = 'a'; tmp->val_[1] = '\0'; @@ -112,11 +110,11 @@ void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end) { } void makeDB() { - if (posix_memalign((void **)&Table, PAGE_SIZE, + if (posix_memalign((void**) &Table, PAGE_SIZE, (FLAGS_tuple_num) * sizeof(Tuple)) != 0) ERR; #if dbs11 - if (madvise((void *)Table, (FLAGS_tuple_num) * sizeof(Tuple), + if (madvise((void*) Table, (FLAGS_tuple_num) * sizeof(Tuple), MADV_HUGEPAGE) != 0) ERR; #endif @@ -127,7 +125,7 @@ void makeDB() { for (size_t i = 0; i < maxthread; ++i) thv.emplace_back(partTableInit, i, i * (FLAGS_tuple_num / maxthread), (i + 1) * (FLAGS_tuple_num / maxthread) - 1); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); } void leaderWork() { diff --git a/cc/oze/bomb_oze.cc b/cc/oze/bomb_oze.cc index 4488a11c..8da875b3 100644 --- a/cc/oze/bomb_oze.cc +++ b/cc/oze/bomb_oze.cc @@ -36,10 +36,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &OzeResult[thid], quit); - BombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &OzeResult[thid], quit); + BombWorkload workload; workload.prepare(trans, nullptr); #ifdef Linux @@ -47,13 +47,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -63,21 +63,21 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start_ = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); gflags::SetUsageMessage("BOMB Oze benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); - init(BombWorkload::getTableNum()); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + init(BombWorkload::getTableNum()); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -85,25 +85,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { OzeResult[0].addLocalAllResult(OzeResult[i]); @@ -111,11 +109,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; OzeResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/oze/debug.cc b/cc/oze/debug.cc index fb4f28f7..f9b3ea5a 100644 --- a/cc/oze/debug.cc +++ b/cc/oze/debug.cc @@ -6,23 +6,23 @@ #include "include/debug.hh" std::vector my_backtrace() { - auto trace_size = 10; - void* trace[trace_size]; - auto size = backtrace(trace, trace_size); - auto symbols = backtrace_symbols(trace, size); - std::vector result(symbols, symbols + size); - free(symbols); - return result; + auto trace_size = 10; + void* trace[trace_size]; + auto size = backtrace(trace, trace_size); + auto symbols = backtrace_symbols(trace, size); + std::vector result(symbols, symbols + size); + free(symbols); + return result; } void my_assert(bool expr) { - if (unlikely(!expr)) { - auto vec = my_backtrace(); - int count = vec.size(); - for (auto v : vec) { - count--; - std::cout << "backtrace [" << count << "] " << v << std::endl; - } - abort(); + if (unlikely(!expr)) { + auto vec = my_backtrace(); + int count = vec.size(); + for (auto v : vec) { + count--; + std::cout << "backtrace [" << count << "] " << v << std::endl; } + abort(); + } } diff --git a/cc/oze/include/atomic_tool.hh b/cc/oze/include/atomic_tool.hh index b4586544..4c3ae78d 100644 --- a/cc/oze/include/atomic_tool.hh +++ b/cc/oze/include/atomic_tool.hh @@ -20,7 +20,7 @@ INLINE void atomicAddGE() { INLINE uint64_t atomicLoadGE() { uint64_t_64byte result = - __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); return result.obj_; } diff --git a/cc/oze/include/cc_mode.hh b/cc/oze/include/cc_mode.hh index 5feb430f..7cb1a0ee 100644 --- a/cc/oze/include/cc_mode.hh +++ b/cc/oze/include/cc_mode.hh @@ -2,41 +2,36 @@ #include "thread_management.hh" -#define OCC_MODE 1 -#define OZE_MODE 2 +#define OCC_MODE 1 +#define OZE_MODE 2 #define TO_OCC_MODE 4 #define TO_OZE_MODE 8 #define DEFAULT_CC_MODE OZE_MODE -#define IS_OCC(mode) (mode & (OCC_MODE|TO_OCC_MODE)) -#define IS_OZE(mode) (mode & (OZE_MODE|TO_OZE_MODE)) +#define IS_OCC(mode) (mode & (OCC_MODE | TO_OCC_MODE)) +#define IS_OZE(mode) (mode & (OZE_MODE | TO_OZE_MODE)) extern uint64_t TotalThreadNum; -extern ThreadManagementEntry **ThManagementTable; +extern ThreadManagementEntry** ThManagementTable; -inline bool all_threads_in(uint8_t mode, uint8_t *mode_array) { +inline bool all_threads_in(uint8_t mode, uint8_t* mode_array) { for (unsigned int i = 0; i < TotalThreadNum; ++i) { - if ((mode & mode_array[i]) == 0) { - return false; - } + if ((mode & mode_array[i]) == 0) { return false; } } return true; } -inline bool all_other_threads_in(uint8_t mode, uint8_t *mode_array, uint8_t thread_id) { +inline bool all_other_threads_in(uint8_t mode, uint8_t* mode_array, + uint8_t thread_id) { for (unsigned int i = 0; i < TotalThreadNum; ++i) { if (thread_id == i) continue; - if ((mode & mode_array[i]) == 0) { - return false; - } + if ((mode & mode_array[i]) == 0) { return false; } } return true; } -inline bool some_threads_in(uint8_t mode, uint8_t *mode_array) { +inline bool some_threads_in(uint8_t mode, uint8_t* mode_array) { for (unsigned int i = 0; i < TotalThreadNum; ++i) { - if (mode & mode_array[i]) { - return true; - } + if (mode & mode_array[i]) { return true; } } return false; } @@ -49,12 +44,11 @@ inline bool some_threads_in(uint8_t mode) { return some_threads_in(mode, mode_array); } -inline bool some_other_threads_in(uint8_t mode, uint8_t *mode_array, uint8_t thread_id) { +inline bool some_other_threads_in(uint8_t mode, uint8_t* mode_array, + uint8_t thread_id) { for (unsigned int i = 0; i < TotalThreadNum; ++i) { if (thread_id == i) continue; - if (mode & mode_array[i]) { - return true; - } + if (mode & mode_array[i]) { return true; } } return false; } diff --git a/cc/oze/include/common.hh b/cc/oze/include/common.hh index 6b088534..0eeba2ec 100644 --- a/cc/oze/include/common.hh +++ b/cc/oze/include/common.hh @@ -35,19 +35,24 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint64(clocks_per_us, 2100, "CPU_MHz. Use this info for measuring time."); +DEFINE_uint64(clocks_per_us, 2100, + "CPU_MHz. Use this info for measuring time."); DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(epoch_time, 40, "Epoch interval[msec]."); DEFINE_uint64(gc_inter_us, 10, "GC interval[us]."); DEFINE_uint64(group_commit, 0, "Group commit number of transactions."); -DEFINE_uint64(group_commit_timeout_us, 2, "Timeout used for deadlock resolution when performing group commit[us]."); +DEFINE_uint64( + group_commit_timeout_us, 2, + "Timeout used for deadlock resolution when performing group commit[us]."); DEFINE_uint64(io_time_ns, 5, "Delay inserted instead of IO."); -DEFINE_uint64(pre_reserve_version, 10000, "Pre-allocating memory for the version."); +DEFINE_uint64(pre_reserve_version, 10000, + "Pre-allocating memory for the version."); DEFINE_bool(p_wal, false, "Parallel write-ahead logging."); DEFINE_bool(s_wal, false, "Normal write-ahead logging."); DEFINE_uint64(thread_num, 10, "Number of regular worker threads."); DEFINE_bool(forwarding, true, "Enable order forwarding."); -DEFINE_uint64(validation_threshold, 100, "Threshold of pages for parallel validation."); +DEFINE_uint64(validation_threshold, 100, + "Threshold of pages for parallel validation."); DEFINE_uint64(validation_th_num, 1, "Number of validation threads."); DEFINE_uint64(cc_mode, DEFAULT_CC_MODE, "Initial concurrency control mode."); #else @@ -70,9 +75,9 @@ DECLARE_uint64(cc_mode); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; -alignas(CACHE_LINE_SIZE) GLOBAL ThreadManagementEntry **ThManagementTable; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; +alignas(CACHE_LINE_SIZE) GLOBAL ThreadManagementEntry** ThManagementTable; -#define SCAN_HISTORY_INDEX(storage, epoch) 2 * (uint32_t)storage + epoch % 2 -alignas(CACHE_LINE_SIZE) GLOBAL atomic *ScanHistory; -alignas(CACHE_LINE_SIZE) GLOBAL atomic *ScanRange; +#define SCAN_HISTORY_INDEX(storage, epoch) 2 * (uint32_t) storage + epoch % 2 +alignas(CACHE_LINE_SIZE) GLOBAL atomic* ScanHistory; +alignas(CACHE_LINE_SIZE) GLOBAL atomic* ScanRange; diff --git a/cc/oze/include/debug.hh b/cc/oze/include/debug.hh index 737b2af1..83af4c03 100644 --- a/cc/oze/include/debug.hh +++ b/cc/oze/include/debug.hh @@ -8,12 +8,12 @@ #define DOT_COMMAND "/usr/bin/dot" #ifdef MY_DEBUG - #define ASSERT(expr) my_assert(expr) +#define ASSERT(expr) my_assert(expr) #else - #define ASSERT(ignore) ((void)0) +#define ASSERT(ignore) ((void) 0) #endif -#define likely(x) __builtin_expect(!!(x), 1) +#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) extern std::vector my_backtrace(); diff --git a/cc/oze/include/lock.hh b/cc/oze/include/lock.hh index 4553d945..dcc5a582 100644 --- a/cc/oze/include/lock.hh +++ b/cc/oze/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -40,7 +38,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -56,7 +54,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/cc/oze/include/oze.hh b/cc/oze/include/oze.hh index 9e8fa886..7ba28b0a 100644 --- a/cc/oze/include/oze.hh +++ b/cc/oze/include/oze.hh @@ -15,61 +15,53 @@ class Tuple; typedef Tuple* Key; #ifndef ORDERED_MAPSET -typedef std::map ReadSet; +typedef std::map ReadSet; typedef std::set WriteSet; typedef std::set KeySet; typedef std::set TxSet; #else // Some test case will be fail due to the order of propagation? -typedef std::unordered_map ReadSet; +typedef std::unordered_map ReadSet; typedef std::unordered_set WriteSet; typedef std::unordered_set KeySet; typedef std::unordered_set TxSet; #endif class TxNode { - public: - TxID id_; - TransactionStatus status_; - bool is_aborted; - ReadSet readSet_; - WriteSet writeSet_; - TxSet readBy_; // outgoing edges - TxSet writtenBy_; // outgoing edges - TxSet from_; // incoming edges - TxNode(TxID id) : - id_(id), - status_(TransactionStatus::inflight), - is_aborted(false) - {}; - TxNode(TxID id, TransactionStatus status) : - id_(id), - status_(status), - is_aborted(false) - {}; +public: + TxID id_; + TransactionStatus status_; + bool is_aborted; + ReadSet readSet_; + WriteSet writeSet_; + TxSet readBy_; // outgoing edges + TxSet writtenBy_; // outgoing edges + TxSet from_; // incoming edges + TxNode(TxID id) + : id_(id), status_(TransactionStatus::inflight), is_aborted(false){}; + TxNode(TxID id, TransactionStatus status) + : id_(id), status_(status), is_aborted(false){}; }; #ifndef ORDERED_MAPSET -typedef std::map Graph; +typedef std::map Graph; #else -typedef std::unordered_map Graph; +typedef std::unordered_map Graph; #endif class AbortTx { - public: - TxID id_; - atomic next_; +public: + TxID id_; + atomic next_; - AbortTx(const TxID txid) { - id_ = txid; - next_.store(nullptr, memory_order_release); - } + AbortTx(const TxID txid) { + id_ = txid; + next_.store(nullptr, memory_order_release); + } - AbortTx* ldAcqNext() { - return next_.load(std::memory_order_acquire); - } + AbortTx* ldAcqNext() { return next_.load(std::memory_order_acquire); } - void strRelNext(AbortTx* next) { // store release next = strRelNext - next_.store(next, std::memory_order_release); - } + void strRelNext(AbortTx* next) { // store release next = strRelNext + next_.store(next, std::memory_order_release); + } }; diff --git a/cc/oze/include/oze_op_element.hh b/cc/oze/include/oze_op_element.hh index 064f13fd..a5f012d3 100644 --- a/cc/oze/include/oze_op_element.hh +++ b/cc/oze/include/oze_op_element.hh @@ -5,44 +5,48 @@ #include "txid.hh" #include "version.hh" -template +template class ReadElement : public OpElement { public: using OpElement::OpElement; TxID txid_; TupleId tuple_id_; - Version *ver_; + Version* ver_; - ReadElement(Storage s, std::string_view key, T *rcdptr, Version *ver, TxID txid, TupleId tid) + ReadElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + TxID txid, TupleId tid) : OpElement::OpElement(s, key, rcdptr) { ver_ = ver; txid_ = txid; tuple_id_ = tid; } - bool operator<(const ReadElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const ReadElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class WriteElement : public OpElement { public: using OpElement::OpElement; - Version *new_ver_; + Version* new_ver_; bool finish_version_install_; - WriteElement(Storage s, std::string_view key, T *rcdptr, Version *new_ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + WriteElement(Storage s, std::string_view key, T* rcdptr, Version* new_ver, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { new_ver_ = new_ver; finish_version_install_ = false; } - bool operator<(const WriteElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const WriteElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; diff --git a/cc/oze/include/result.hh b/cc/oze/include/result.hh index b7eda677..595342d2 100644 --- a/cc/oze/include/result.hh +++ b/cc/oze/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector OzeResult; +extern std::vector OzeResult; extern void initResult(); diff --git a/cc/oze/include/scan.hh b/cc/oze/include/scan.hh index ab2b6442..bcc0fff9 100644 --- a/cc/oze/include/scan.hh +++ b/cc/oze/include/scan.hh @@ -11,25 +11,24 @@ class ScanEntry { public: TxID txid_; std::string_view left_key_; - std::string_view right_key_; + std::string_view right_key_; bool l_exclusive_; bool r_exclusive_; std::atomic next_; - ScanEntry(const TxID txid, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, ScanEntry*next) { + ScanEntry(const TxID txid, std::string_view left_key, bool l_exclusive, + std::string_view right_key, bool r_exclusive, ScanEntry* next) { txid_ = txid; left_key_ = left_key; - right_key_ = right_key; + right_key_ = right_key; l_exclusive_ = l_exclusive; r_exclusive_ = r_exclusive; next_.store(next, std::memory_order_release); } - ScanEntry *ldAcqNext() { return next_.load(std::memory_order_acquire); } + ScanEntry* ldAcqNext() { return next_.load(std::memory_order_acquire); } - void strRelNext(ScanEntry *next) { // store release next = strRelNext + void strRelNext(ScanEntry* next) { // store release next = strRelNext next_.store(next, std::memory_order_release); } @@ -41,25 +40,15 @@ public: int left = key.compare(left_key_); // > 0 if left_key < key int right = key.compare(right_key_); // < 0 if key < right_key - if (left_key_.empty()) { - return r_exclusive_ ? right < 0 : right <= 0; - } + if (left_key_.empty()) { return r_exclusive_ ? right < 0 : right <= 0; } - if (right_key_.empty()) { - return l_exclusive_ ? left > 0 : left >= 0; - } + if (right_key_.empty()) { return l_exclusive_ ? left > 0 : left >= 0; } - if (l_exclusive_ && r_exclusive_) { - return right < 0 && left > 0; - } + if (l_exclusive_ && r_exclusive_) { return right < 0 && left > 0; } - if (l_exclusive_) { - return right <= 0 && left > 0; - } + if (l_exclusive_) { return right <= 0 && left > 0; } - if (r_exclusive_) { - return right < 0 && left >= 0; - } + if (r_exclusive_) { return right < 0 && left >= 0; } return right <= 0 && left >= 0; } diff --git a/cc/oze/include/scan_callback.hh b/cc/oze/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/oze/include/scan_callback.hh +++ b/cc/oze/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/oze/include/test.hh b/cc/oze/include/test.hh index 120b32e9..6415032a 100644 --- a/cc/oze/include/test.hh +++ b/cc/oze/include/test.hh @@ -16,136 +16,134 @@ enum class Storage : std::uint32_t { }; struct Data { - alignas(CACHE_LINE_SIZE) - std::uint64_t id_; + alignas(CACHE_LINE_SIZE) std::uint64_t id_; char val_[1]; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint64_t id, char *out) { + static void CreateKey(uint64_t id, char* out) { assign_as_bigendian(id, &out[0]); } - void createKey(char *out) const { return CreateKey(id_, out); } + void createKey(char* out) const { return CreateKey(id_, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; class TestCase : public ::testing::Test { protected: - virtual void SetUp() { - TotalThreadNum = NumVirtualThreads; - ThManagementTable = new ThreadManagementEntry *[TotalThreadNum]; - ScanHistory = (atomic*)calloc(2, sizeof(atomic)); - for (int i = 0; i < TotalThreadNum; ++i) { - txmap.emplace(i, new TxExecutor(i, backoff_, &res_[i], std::ref(quit_))); - ThManagementTable[i] = new ThreadManagementEntry(1, FLAGS_cc_mode); - } - for (uint64_t i = (uint64_t)'a'; i <= (uint64_t)'z'; ++i) { - std::string s{(char)i}; - table.emplace(s, new Tuple()); - } - TxID txid = TxID(); - txid.thid = 0; - for (auto& [key, tuple] : table) { - HeapObject obj; - obj.allocate(); - tuple->init(0, TupleBody(key, std::move(obj)), nullptr); - for (auto& [k, t] : table) { - tuple->graph_.at(txid).writeSet_.emplace(t); - } - Masstrees[get_storage(Storage::TestTable)].insert_value(key, tuple); - } - GlobalEpoch.obj_ = 1; + virtual void SetUp() { + TotalThreadNum = NumVirtualThreads; + ThManagementTable = new ThreadManagementEntry*[TotalThreadNum]; + ScanHistory = (atomic*) calloc(2, sizeof(atomic)); + for (int i = 0; i < TotalThreadNum; ++i) { + txmap.emplace(i, new TxExecutor(i, backoff_, &res_[i], std::ref(quit_))); + ThManagementTable[i] = new ThreadManagementEntry(1, FLAGS_cc_mode); } - - virtual void TearDown() { - txmap.clear(); - table.clear(); - Masstrees[get_storage(Storage::TestTable)].table_init(); + for (uint64_t i = (uint64_t) 'a'; i <= (uint64_t) 'z'; ++i) { + std::string s{(char) i}; + table.emplace(s, new Tuple()); } - - void clear() { - TearDown(); - SetUp(); + TxID txid = TxID(); + txid.thid = 0; + for (auto& [key, tuple] : table) { + HeapObject obj; + obj.allocate(); + tuple->init(0, TupleBody(key, std::move(obj)), nullptr); + for (auto& [k, t] : table) { + tuple->graph_.at(txid).writeSet_.emplace(t); + } + Masstrees[get_storage(Storage::TestTable)].insert_value(key, tuple); } + GlobalEpoch.obj_ = 1; + } - // wrappers for old test iterface in mock - void begin(std::string txid) { - txmap[std::stoi(txid)]->begin(); - } + virtual void TearDown() { + txmap.clear(); + table.clear(); + Masstrees[get_storage(Storage::TestTable)].table_init(); + } - bool read(std::string key, std::string txid) { - auto tx = txmap[std::stoi(txid)]; - tx->read(Storage::TestTable, key, &dummy_); - if (tx->status_ == TransactionStatus::aborted) - return false; - else - return true; - } + void clear() { + TearDown(); + SetUp(); + } - bool scan(std::string left_key, bool l_exclusive, - std::string right_key, bool r_exclusive, std::string txid) { - auto tx = txmap[std::stoi(txid)]; - std::vector results; - tx->scan(Storage::TestTable, left_key, l_exclusive, right_key, r_exclusive, results); - if (tx->status_ == TransactionStatus::aborted) - return false; - else - return true; - } + // wrappers for old test iterface in mock + void begin(std::string txid) { txmap[std::stoi(txid)]->begin(); } - bool write(std::string key, std::string txid) { - auto tx = txmap[std::stoi(txid)]; - HeapObject obj; - obj.allocate(); - tx->write(Storage::TestTable, key, TupleBody(key, std::move(obj))); - if (tx->status_ == TransactionStatus::aborted) - return false; - else - return true; - } + bool read(std::string key, std::string txid) { + auto tx = txmap[std::stoi(txid)]; + tx->read(Storage::TestTable, key, &dummy_); + if (tx->status_ == TransactionStatus::aborted) + return false; + else + return true; + } - Status insert(std::string key, std::string txid) { - auto tx = txmap[std::stoi(txid)]; - HeapObject obj; - obj.allocate(); - return tx->insert(Storage::TestTable, key, TupleBody(key, std::move(obj))); - } + bool scan(std::string left_key, bool l_exclusive, std::string right_key, + bool r_exclusive, std::string txid) { + auto tx = txmap[std::stoi(txid)]; + std::vector results; + tx->scan(Storage::TestTable, left_key, l_exclusive, right_key, r_exclusive, + results); + if (tx->status_ == TransactionStatus::aborted) + return false; + else + return true; + } - bool commit(std::string txid) { - TxExecutor* tx = txmap[std::stoi(txid)]; - if (!tx->commit()) { - tx->abort(); - return false; - } - return true; - } + bool write(std::string key, std::string txid) { + auto tx = txmap[std::stoi(txid)]; + HeapObject obj; + obj.allocate(); + tx->write(Storage::TestTable, key, TupleBody(key, std::move(obj))); + if (tx->status_ == TransactionStatus::aborted) + return false; + else + return true; + } - bool exists_in_read_set(std::string txid, std::string key) { - TxExecutor* tx = txmap[std::stoi(txid)]; - if (tx->searchReadSet(Storage::TestTable, key)) - return true; - else - return false; - } + Status insert(std::string key, std::string txid) { + auto tx = txmap[std::stoi(txid)]; + HeapObject obj; + obj.allocate(); + return tx->insert(Storage::TestTable, key, TupleBody(key, std::move(obj))); + } - std::string get_read_version(std::string txid, std::string key) { - TxExecutor* tx = txmap[std::stoi(txid)]; - TxID version = tx->get_read_version(table[key]); - return std::to_string(version.thid); + bool commit(std::string txid) { + TxExecutor* tx = txmap[std::stoi(txid)]; + if (!tx->commit()) { + tx->abort(); + return false; } + return true; + } - void set_latest_version_state(std::string key, VersionStatus status) { - Tuple* tuple = Masstrees[get_storage(Storage::TestTable)].get_value(key); - Version* v = tuple->ldAcqLatest(); - v->status_ = status; - } + bool exists_in_read_set(std::string txid, std::string key) { + TxExecutor* tx = txmap[std::stoi(txid)]; + if (tx->searchReadSet(Storage::TestTable, key)) + return true; + else + return false; + } + + std::string get_read_version(std::string txid, std::string key) { + TxExecutor* tx = txmap[std::stoi(txid)]; + TxID version = tx->get_read_version(table[key]); + return std::to_string(version.thid); + } + + void set_latest_version_state(std::string key, VersionStatus status) { + Tuple* tuple = Masstrees[get_storage(Storage::TestTable)].get_value(key); + Version* v = tuple->ldAcqLatest(); + v->status_ = status; + } - std::map txmap; - std::map table; - TupleBody* dummy_; - Backoff backoff_ = Backoff(ClocksPerUsec); - Result res_[NumVirtualThreads]; - bool quit_ = false; + std::map txmap; + std::map table; + TupleBody* dummy_; + Backoff backoff_ = Backoff(ClocksPerUsec); + Result res_[NumVirtualThreads]; + bool quit_ = false; }; diff --git a/cc/oze/include/thread_management.hh b/cc/oze/include/thread_management.hh index 3b91752c..69a08946 100644 --- a/cc/oze/include/thread_management.hh +++ b/cc/oze/include/thread_management.hh @@ -7,7 +7,7 @@ #include "transaction_status.hh" class ThreadManagementEntry { - public: +public: ThreadManagementEntry(uint64_t epoch, uint8_t mode) { this->epoch_.store(epoch, std::memory_order_relaxed); this->mode_.store(mode, std::memory_order_relaxed); @@ -30,7 +30,7 @@ class ThreadManagementEntry { return this->mode_.load(std::memory_order_acquire); } - private: +private: alignas(CACHE_LINE_SIZE) std::atomic epoch_; std::atomic mode_; std::atomic last_long_tx_epoch_; diff --git a/cc/oze/include/time_stamp.hh b/cc/oze/include/time_stamp.hh index 52538215..cd4c8c04 100644 --- a/cc/oze/include/time_stamp.hh +++ b/cc/oze/include/time_stamp.hh @@ -14,7 +14,7 @@ public: inline uint64_t get_ts() { return ts_; } - inline void set_ts(uint64_t &ts) { this->ts_ = ts; } + inline void set_ts(uint64_t& ts) { this->ts_ = ts; } inline void set_clockBoost(unsigned int CLOCK_PER_US) { // set 0 or some value equivalent to 1 us. diff --git a/cc/oze/include/transaction.hh b/cc/oze/include/transaction.hh index c1b45ec9..19a693fd 100644 --- a/cc/oze/include/transaction.hh +++ b/cc/oze/include/transaction.hh @@ -34,135 +34,138 @@ class TxScanCallback; class TxExecutor { public: - TransactionStatus status_ = TransactionStatus::invalid; - std::vector> read_set_; - std::vector> write_set_; - std::vector pro_set_; - std::deque gc_records_; - Result *result_ = nullptr; - Backoff& backoff_; - uint64_t epoch_timer_start_, epoch_timer_stop_; - - uint8_t cc_mode_; - ReadSet readSet_; - WriteSet writeSet_; - Graph graph_; - TxSet following_; - TxSet followers_; - uint64_t reclamation_epoch_; - - // for OCC - TupleId max_tid_rset_, max_tid_wset_, most_recent_tid_; - TxScanCallback callback_; - std::unordered_map node_map_; - - TxID txid_; - bool reconnoitering_ = false; - bool is_ronly_ = false; - bool is_batch_ = false; - bool is_forwarded_; - bool has_write_ = false; - bool has_insert_ = false; - bool occ_guard_required_ = false; - uint8_t thid_ = 0; - - // for parallel validation - RWLock lock_; - - const bool& quit_; // for thread termination control - - TxExecutor(uint8_t thid, Backoff& backoff, Result *res, const bool &quit) - : result_(res), backoff_(backoff), callback_(TxScanCallback(this)), thid_(thid), quit_(quit) { - txid_.thid = thid_; - txid_.tid = 0; - - is_batch_ = false; - is_forwarded_ = false; - } + TransactionStatus status_ = TransactionStatus::invalid; + std::vector> read_set_; + std::vector> write_set_; + std::vector pro_set_; + std::deque gc_records_; + Result* result_ = nullptr; + Backoff& backoff_; + uint64_t epoch_timer_start_, epoch_timer_stop_; - ~TxExecutor() { - read_set_.clear(); - write_set_.clear(); - pro_set_.clear(); - } + uint8_t cc_mode_; + ReadSet readSet_; + WriteSet writeSet_; + Graph graph_; + TxSet following_; + TxSet followers_; + uint64_t reclamation_epoch_; + + // for OCC + TupleId max_tid_rset_, max_tid_wset_, most_recent_tid_; + TxScanCallback callback_; + std::unordered_map node_map_; + + TxID txid_; + bool reconnoitering_ = false; + bool is_ronly_ = false; + bool is_batch_ = false; + bool is_forwarded_; + bool has_write_ = false; + bool has_insert_ = false; + bool occ_guard_required_ = false; + uint8_t thid_ = 0; + + // for parallel validation + RWLock lock_; + + const bool& quit_; // for thread termination control + + TxExecutor(uint8_t thid, Backoff& backoff, Result* res, const bool& quit) + : result_(res), backoff_(backoff), callback_(TxScanCallback(this)), + thid_(thid), quit_(quit) { + txid_.thid = thid_; + txid_.tid = 0; + + is_batch_ = false; + is_forwarded_ = false; + } + + ~TxExecutor() { + read_set_.clear(); + write_set_.clear(); + pro_set_.clear(); + } - void abort(); + void abort(); - void displayWriteSet(); + void displayWriteSet(); - void mainte(); // maintenance + void mainte(); // maintenance - void begin(); + void begin(); - Status read(Storage s, std::string_view key, TupleBody** body); - Status read_internal(Storage s, std::string_view key, Tuple* tuple, Version** return_ver); - Status read_internal_occ(Storage s, std::string_view key, Tuple* tuple, Version** return_ver); + Status read(Storage s, std::string_view key, TupleBody** body); + Status read_internal(Storage s, std::string_view key, Tuple* tuple, + Version** return_ver); + Status read_internal_occ(Storage s, std::string_view key, Tuple* tuple, + Version** return_ver); - Status update(Storage s, std::string_view key, TupleBody&& body); + Status update(Storage s, std::string_view key, TupleBody&& body); - Status insert(Storage s, std::string_view key, TupleBody&& body); + Status insert(Storage s, std::string_view key, TupleBody&& body); - Status delete_record(Storage s, std::string_view key); + Status delete_record(Storage s, std::string_view key); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector&result); + Status scan(Storage s, std::string_view left_key, bool l_exclusive, + std::string_view right_key, bool r_exclusive, + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + Status scan(Storage s, std::string_view left_key, bool l_exclusive, + std::string_view right_key, bool r_exclusive, + std::vector& result, int64_t limit); - bool read_validation(KeySet &target_set, KeySet &finished_set); - bool write_validation(WriteElement element, KeySet &finished_set, KeySet &propagate_set); - bool insert_validation(WriteElement element); - bool validation(); - bool validation_occ(); - void validation_worker(size_t worker_id, KeySet &propagate_set, - size_t offset, size_t assignment, - KeySet &propagate_subset, Graph &graph, TransactionStatus &result); + bool read_validation(KeySet& target_set, KeySet& finished_set); + bool write_validation(WriteElement element, KeySet& finished_set, + KeySet& propagate_set); + bool insert_validation(WriteElement element); + bool validation(); + bool validation_occ(); + void validation_worker(size_t worker_id, KeySet& propagate_set, size_t offset, + size_t assignment, KeySet& propagate_subset, + Graph& graph, TransactionStatus& result); - void writePhase(); + void writePhase(); - bool commit(); + bool commit(); - void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_begin(); + void reconnoiter_end(); - bool isLeader(); + bool isLeader(); - void leaderWork(); + void leaderWork(); - void gc_records(); + void gc_records(); - void backoff() { + void backoff() { #if ADD_ANALYSIS - uint64_t start = rdtscp(); + uint64_t start = rdtscp(); #endif - Backoff::backoff(FLAGS_clocks_per_us); + Backoff::backoff(FLAGS_clocks_per_us); #if ADD_ANALYSIS - result_->local_backoff_latency_ += rdtscp() - start; + result_->local_backoff_latency_ += rdtscp() - start; #endif - } + } - Version *newVersionGeneration([[maybe_unused]] Tuple *tuple) { + Version* newVersionGeneration([[maybe_unused]] Tuple* tuple) { #if ADD_ANALYSIS - ++result_->local_version_malloc_; + ++result_->local_version_malloc_; #endif - return new Version(this->txid_); - } + return new Version(this->txid_); + } - Version *newVersionGeneration([[maybe_unused]] Tuple *tuple, TupleBody&& body) { + Version* newVersionGeneration([[maybe_unused]] Tuple* tuple, + TupleBody&& body) { #if ADD_ANALYSIS - ++result_->local_version_malloc_; + ++result_->local_version_malloc_; #endif - return new Version(this->txid_, std::move(body)); - } + return new Version(this->txid_, std::move(body)); + } - /** + /** * @brief Search xxx set * @detail Search element of local set corresponding to given key. * In this prototype system, the value to be updated for each worker thread @@ -170,15 +173,15 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline ReadElement *searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { - if (re.storage_ != s) continue; - if (re.key_ == key) return &re; - } - return nullptr; + inline ReadElement* searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { + if (re.storage_ != s) continue; + if (re.key_ == key) return &re; } + return nullptr; + } - /** + /** * @brief Search xxx set * @detail Search element of local set corresponding to given key. * In this prototype system, the value to be updated for each worker thread @@ -186,1079 +189,1086 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline WriteElement *searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { - if (we.storage_ != s) continue; - if (we.key_ == key) return &we; - } - - return nullptr; + inline WriteElement* searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { + if (we.storage_ != s) continue; + if (we.key_ == key) return &we; } - inline WriteElement *searchWriteSet(Tuple* tuple) { - for (auto &we : write_set_) { - if (we.rcdptr_ == tuple) return &we; - } + return nullptr; + } - return nullptr; + inline WriteElement* searchWriteSet(Tuple* tuple) { + for (auto& we : write_set_) { + if (we.rcdptr_ == tuple) return &we; } - void writeSetClean() { - for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - (*itr).new_ver_->status_.store(VersionStatus::aborted, std::memory_order_release); - if ((*itr).op_ == OpType::INSERT) { - Masstrees[get_storage((*itr).storage_)].remove_value((*itr).key_); - delete (*itr).new_ver_; - delete (*itr).rcdptr_; - } - } - write_set_.clear(); + return nullptr; + } + + void writeSetClean() { + for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { + (*itr).new_ver_->status_.store(VersionStatus::aborted, + std::memory_order_release); + if ((*itr).op_ == OpType::INSERT) { + Masstrees[get_storage((*itr).storage_)].remove_value((*itr).key_); + delete (*itr).new_ver_; + delete (*itr).rcdptr_; + } } - - void addScanEntry(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive) { - auto index = SCAN_HISTORY_INDEX(s, this->txid_.epoch); - while(true) { - uint64_t expected = ScanRange[index].load(std::memory_order_acquire); - uint32_t min = expected >> 32; - uint32_t max = expected & 0xffffffff; - uint32_t left = *reinterpret_cast(left_key.data()); - uint32_t right = *reinterpret_cast(right_key.data()); - // Must start at 0: the |= branches below only write half the - // word each (upper 32b in one, lower 32b in the other), so - // any uninitialized garbage would leak into the result. - uint64_t updated = 0; - if (max < right) { - updated |= static_cast(right) & 0xffffffff; - } else { - updated |= static_cast(max) & 0xffffffff; - } - if (left < min) { - updated |= static_cast(left) << 32; - } else { - updated |= static_cast(min) << 32; - } - if (expected != updated) { - if (ScanRange[index].compare_exchange_strong( - expected, updated, memory_order_acq_rel, memory_order_acquire)) - break; - } else { - break; - } - } - while(true) { - ScanEntry* expected = ScanHistory[index].load(std::memory_order_acquire); - ScanEntry* new_entry = new ScanEntry(txid_, left_key, l_exclusive, - right_key, r_exclusive, expected); - if (ScanHistory[index].compare_exchange_strong(expected, new_entry, - memory_order_acq_rel, memory_order_acquire)) - break; - } + write_set_.clear(); + } + + void addScanEntry(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive) { + auto index = SCAN_HISTORY_INDEX(s, this->txid_.epoch); + while (true) { + uint64_t expected = ScanRange[index].load(std::memory_order_acquire); + uint32_t min = expected >> 32; + uint32_t max = expected & 0xffffffff; + uint32_t left = *reinterpret_cast(left_key.data()); + uint32_t right = *reinterpret_cast(right_key.data()); + // Must start at 0: the |= branches below only write half the + // word each (upper 32b in one, lower 32b in the other), so + // any uninitialized garbage would leak into the result. + uint64_t updated = 0; + if (max < right) { + updated |= static_cast(right) & 0xffffffff; + } else { + updated |= static_cast(max) & 0xffffffff; + } + if (left < min) { + updated |= static_cast(left) << 32; + } else { + updated |= static_cast(min) << 32; + } + if (expected != updated) { + if (ScanRange[index].compare_exchange_strong( + expected, updated, memory_order_acq_rel, memory_order_acquire)) + break; + } else { + break; + } } - - static INLINE Tuple *get_tuple(Tuple *table, uint64_t key) { - return &table[key]; + while (true) { + ScanEntry* expected = ScanHistory[index].load(std::memory_order_acquire); + ScanEntry* new_entry = new ScanEntry(txid_, left_key, l_exclusive, + right_key, r_exclusive, expected); + if (ScanHistory[index].compare_exchange_strong( + expected, new_entry, memory_order_acq_rel, memory_order_acquire)) + break; } + } + + static INLINE Tuple* get_tuple(Tuple* table, uint64_t key) { + return &table[key]; + } - /** + /** * Oze specific helper functions */ - bool has_rw_conflict(const ReadSet &rset, const WriteSet &wset) { - for (const auto& [key, _] : rset) { - if (auto it = wset.find(key); it != wset.end()) - return true; - } - return false; + bool has_rw_conflict(const ReadSet& rset, const WriteSet& wset) { + for (const auto& [key, _] : rset) { + if (auto it = wset.find(key); it != wset.end()) return true; } - - bool has_any_conflict(const ReadSet &my_read_set, const WriteSet &my_write_set, - const ReadSet &your_read_set, const WriteSet &your_write_set) { - for (auto& [key, _] : my_read_set) { - auto it = your_write_set.find(key); - if (it != your_write_set.end()) { - return true; - } - } - for (auto& key : my_write_set) { - auto rit = your_read_set.find(key); - if (rit != your_read_set.end()) { - return true; - } - auto wit = your_write_set.find(key); - if (wit != your_write_set.end()) { - return true; - } - } - return false; + return false; + } + + bool has_any_conflict(const ReadSet& my_read_set, + const WriteSet& my_write_set, + const ReadSet& your_read_set, + const WriteSet& your_write_set) { + for (auto& [key, _] : my_read_set) { + auto it = your_write_set.find(key); + if (it != your_write_set.end()) { return true; } } - - void find_readers(const Graph &g, const Key key, TxSet &readers) { - for (const auto& [txid, node] : g) { - if (txid == this->txid_) continue; // to avoid including me in the RMW case - if (g.at(txid).is_aborted) continue; - if (auto it = g.at(txid).readSet_.find(key); - it !=g.at(txid).readSet_.end()) { - readers.insert(txid); - } - } + for (auto& key : my_write_set) { + auto rit = your_read_set.find(key); + if (rit != your_read_set.end()) { return true; } + auto wit = your_write_set.find(key); + if (wit != your_write_set.end()) { return true; } } - - void find_followers(const Graph &g, const Key key, TxSet &readers, TxSet &followers) { - for (const auto& reader : readers) { - followers.insert(g.at(reader).readSet_.at(key)); - } + return false; + } + + void find_readers(const Graph& g, const Key key, TxSet& readers) { + for (const auto& [txid, node] : g) { + if (txid == this->txid_) + continue; // to avoid including me in the RMW case + if (g.at(txid).is_aborted) continue; + if (auto it = g.at(txid).readSet_.find(key); + it != g.at(txid).readSet_.end()) { + readers.insert(txid); + } } + } - void find_reachable_to_dfs(const Graph &g, std::map &seen, const TxID txID) { - seen.emplace(txID, true); - TxSet edges(g.at(txID).readBy_); - edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); - - for (const auto& next : edges) { - if (auto it = seen.find(next); it != seen.end() && seen[next]) continue; - if (auto it = g.find(next); it != g.end()) - find_reachable_to_dfs(g, seen, next); - } + void find_followers(const Graph& g, const Key key, TxSet& readers, + TxSet& followers) { + for (const auto& reader : readers) { + followers.insert(g.at(reader).readSet_.at(key)); } - - void find_reachable_to(const TxID start, const Graph &g, TxSet &txns) { - // find transactions that can be visited from start transaction - std::map seen; - for (const auto& next : g.at(start).readBy_) { - // TODO: This kind of checking might be skipped if merge/GC works well-mannered - if (auto it = g.find(next); it != g.end()) - find_reachable_to_dfs(g, seen, next); - } - for (const auto& next : g.at(start).writtenBy_) { - if (auto it = g.find(next); it != g.end()) - find_reachable_to_dfs(g, seen, next); - } - for (const auto& [id, _] : seen) - txns.insert(id); + } + + void find_reachable_to_dfs(const Graph& g, std::map& seen, + const TxID txID) { + seen.emplace(txID, true); + TxSet edges(g.at(txID).readBy_); + edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); + + for (const auto& next : edges) { + if (auto it = seen.find(next); it != seen.end() && seen[next]) continue; + if (auto it = g.find(next); it != g.end()) + find_reachable_to_dfs(g, seen, next); } - - void find_reachable_from_dfs(const Graph &g, std::map &seen, const TxID txID) { - seen.emplace(txID, true); - TxSet edges(g.at(txID).from_); - - for (const auto& from : edges) { - if (auto it = seen.find(from); it != seen.end() && seen[from]) continue; - if (auto it = g.find(from); it == g.end()) // TODO: why is this check necessary? - continue; - find_reachable_from_dfs(g, seen, from); - } + } + + void find_reachable_to(const TxID start, const Graph& g, TxSet& txns) { + // find transactions that can be visited from start transaction + std::map seen; + for (const auto& next : g.at(start).readBy_) { + // TODO: This kind of checking might be skipped if merge/GC works well-mannered + if (auto it = g.find(next); it != g.end()) + find_reachable_to_dfs(g, seen, next); } - - void find_reachable_from(const TxID target, const Graph &g, TxSet &txns) { - // find transactions that can visit the target transaction - std::map seen; - find_reachable_from_dfs(g, seen, target); - for (const auto& [id, _] : seen) - txns.insert(id); + for (const auto& next : g.at(start).writtenBy_) { + if (auto it = g.find(next); it != g.end()) + find_reachable_to_dfs(g, seen, next); } - - bool is_invisible_dfs(Key key, TxID version, TxID myTxID, Graph &g, TxID txID, bool invisible, - std::map &seen, std::map &finished, std::vector &stack) { + for (const auto& [id, _] : seen) txns.insert(id); + } + + void find_reachable_from_dfs(const Graph& g, std::map& seen, + const TxID txID) { + seen.emplace(txID, true); + TxSet edges(g.at(txID).from_); + + for (const auto& from : edges) { + if (auto it = seen.find(from); it != seen.end() && seen[from]) continue; + if (auto it = g.find(from); + it == g.end()) // TODO: why is this check necessary? + continue; + find_reachable_from_dfs(g, seen, from); + } + } + + void find_reachable_from(const TxID target, const Graph& g, TxSet& txns) { + // find transactions that can visit the target transaction + std::map seen; + find_reachable_from_dfs(g, seen, target); + for (const auto& [id, _] : seen) txns.insert(id); + } + + bool is_invisible_dfs(Key key, TxID version, TxID myTxID, Graph& g, TxID txID, + bool invisible, std::map& seen, + std::map& finished, + std::vector& stack) { #if DEBUG_MSG - std::cout << " Checking TxID " << txID << " currently : " << invisible << std::endl; + std::cout << " Checking TxID " << txID << " currently : " << invisible + << std::endl; #endif - seen[txID] = true; - if (myTxID == txID) { - finished[txID] = true; - return invisible ? true : false; - } + seen[txID] = true; + if (myTxID == txID) { + finished[txID] = true; + return invisible ? true : false; + } - if (g.at(txID).is_aborted) { - finished[txID] = true; - return false; - } + if (g.at(txID).is_aborted) { + finished[txID] = true; + return false; + } - TxSet edges(g.at(txID).readBy_); - edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); + TxSet edges(g.at(txID).readBy_); + edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); #if DEBUG_MSG - std::cout << " Next: "; - for (const auto& next : edges) - std::cout << next << " "; - std::cout << std::endl; + std::cout << " Next: "; + for (const auto& next : edges) std::cout << next << " "; + std::cout << std::endl; #endif - bool overwrites; // whether if this tx overwrites target key - if (auto it = g.at(txID).writeSet_.find(key); it != g.at(txID).writeSet_.end() - && txID != version) // note that we can read it if txID == version - overwrites = true; - else - overwrites = invisible || false; - - for (const auto& next : edges) { - if (auto it = g.find(next); it == g.end()) // TODO: why is this check necessary? - continue; - auto f = finished.find(next); - if (f != finished.end()) { - continue; - } - auto s = seen.find(next); - if (s != seen.end() && seen[next] - && (f == finished.end() || !finished[next])) continue; // cycle - // stack.push_back(txID); - auto ret = is_invisible_dfs(key, version, myTxID, g, next, overwrites, seen, finished, stack); - // stack.pop_back(); - if (ret) { - finished[txID] = true; - return ret; - } - } -#if DEBUG_MSG - std::cout << " Checking TxID " << txID << " done with false" << std::endl; -#endif + bool overwrites; // whether if this tx overwrites target key + if (auto it = g.at(txID).writeSet_.find(key); + it != g.at(txID).writeSet_.end() && + txID != version) // note that we can read it if txID == version + overwrites = true; + else + overwrites = invisible || false; + + for (const auto& next : edges) { + if (auto it = g.find(next); + it == g.end()) // TODO: why is this check necessary? + continue; + auto f = finished.find(next); + if (f != finished.end()) { continue; } + auto s = seen.find(next); + if (s != seen.end() && seen[next] && + (f == finished.end() || !finished[next])) + continue; // cycle + // stack.push_back(txID); + auto ret = is_invisible_dfs(key, version, myTxID, g, next, overwrites, + seen, finished, stack); + // stack.pop_back(); + if (ret) { finished[txID] = true; - return false; - } - - bool is_invisible(Key key, TxID version, TxID myTxID, Graph &g) { - // check if a key:version pair is visible to me (myTxID) - TxID start = version; - std::map seen, finished; - std::vector stack; // for debug use - return is_invisible_dfs(key, version, myTxID, g, start, false, seen, finished, stack); + return ret; + } } - - Version* get_a_version(Version* ver, std::vector& followers) { - while (ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { - if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { #if DEBUG_MSG - std::cout << " Skip aborted version: " << ver->txid_ << std::endl; + std::cout << " Checking TxID " << txID << " done with false" + << std::endl; #endif - ver = ver->ldAcqNext(); - } else if (ver->status_.load(memory_order_acquire) == VersionStatus::pending - || ver->status_.load(memory_order_acquire) == VersionStatus::deleting) { + finished[txID] = true; + return false; + } + + bool is_invisible(Key key, TxID version, TxID myTxID, Graph& g) { + // check if a key:version pair is visible to me (myTxID) + TxID start = version; + std::map seen, finished; + std::vector stack; // for debug use + return is_invisible_dfs(key, version, myTxID, g, start, false, seen, + finished, stack); + } + + Version* get_a_version(Version* ver, std::vector& followers) { + while (ver->status_.load(memory_order_acquire) != + VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { + if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { #if DEBUG_MSG - std::cout << " Skip pending version: " << ver->txid_ << std::endl; + std::cout << " Skip aborted version: " << ver->txid_ << std::endl; #endif - followers.push_back(ver); - ver = ver->ldAcqNext(); - } - if (ver == VERSION_TERMINATION) { + ver = ver->ldAcqNext(); + } else if (ver->status_.load(memory_order_acquire) == + VersionStatus::pending || + ver->status_.load(memory_order_acquire) == + VersionStatus::deleting) { #if DEBUG_MSG - std::cout << " Version does not exists" << std::endl; + std::cout << " Skip pending version: " << ver->txid_ << std::endl; #endif - return ver; - } - if (ver == nullptr) { + followers.push_back(ver); + ver = ver->ldAcqNext(); + } + if (ver == VERSION_TERMINATION) { #if DEBUG_MSG - std::cout << " No readable version" << std::endl; + std::cout << " Version does not exists" << std::endl; +#endif + return ver; + } + if (ver == nullptr) { +#if DEBUG_MSG + std::cout << " No readable version" << std::endl; #endif - return ver; - } - } return ver; + } } + return ver; + } - void update_read_from(Tuple* tuple, Version* ver) { - // TODO: do not remove TxNode if the version still alive? - if (auto it = tuple->graph_.find(ver->txid_); it == tuple->graph_.end()) { + void update_read_from(Tuple* tuple, Version* ver) { + // TODO: do not remove TxNode if the version still alive? + if (auto it = tuple->graph_.find(ver->txid_); it == tuple->graph_.end()) { #if DEBUG_MSG - std::cout << " TxNode for version " << ver->txid_ << " not found" << std::endl; + std::cout << " TxNode for version " << ver->txid_ << " not found" + << std::endl; #endif - tuple->graph_.emplace(ver->txid_, TxNode(ver->txid_)); - } - // add candidate edge - tuple->graph_.at(ver->txid_).readBy_.emplace(this->txid_); + tuple->graph_.emplace(ver->txid_, TxNode(ver->txid_)); } - - bool has_inflight_reader(Tuple* tuple, TxID txid) { - if (auto itr1 = tuple->graph_.find(txid); itr1 != tuple->graph_.end()) { - for (auto& t : tuple->graph_.at(txid).readBy_) { - if (t == this->txid_) continue; - if (auto itr2 = tuple->graph_.find(t); itr2 != tuple->graph_.end()) { - if (tuple->graph_.at(t).status_ == TransactionStatus::inflight) { - if (auto itr3 = tuple->graph_.at(t).readSet_.find(tuple); - itr3 != tuple->graph_.at(t).readSet_.end()) { + // add candidate edge + tuple->graph_.at(ver->txid_).readBy_.emplace(this->txid_); + } + + bool has_inflight_reader(Tuple* tuple, TxID txid) { + if (auto itr1 = tuple->graph_.find(txid); itr1 != tuple->graph_.end()) { + for (auto& t : tuple->graph_.at(txid).readBy_) { + if (t == this->txid_) continue; + if (auto itr2 = tuple->graph_.find(t); itr2 != tuple->graph_.end()) { + if (tuple->graph_.at(t).status_ == TransactionStatus::inflight) { + if (auto itr3 = tuple->graph_.at(t).readSet_.find(tuple); + itr3 != tuple->graph_.at(t).readSet_.end()) { #if DEBUG_MSG - std::cout << " Inflight reader: " << t << std::endl; + std::cout << " Inflight reader: " << t << std::endl; #endif - return true; - } - } - } + return true; } + } } - return false; + } } - - Status __get_visible_version(Tuple *tuple, Version **return_ver, bool aligned_read=false) { - Status stat = Status::OK; - Version* ver = nullptr; - Version* prev_ver = nullptr; - std::vector followers; - ver = tuple->ldAcqLatest(); -RETRY: - followers.clear(); + return false; + } + + Status __get_visible_version(Tuple* tuple, Version** return_ver, + bool aligned_read = false) { + Status stat = Status::OK; + Version* ver = nullptr; + Version* prev_ver = nullptr; + std::vector followers; + ver = tuple->ldAcqLatest(); + RETRY: + followers.clear(); #if DEBUG_MSG - std::cout << " Selecting read targets" << std::endl; + std::cout << " Selecting read targets" << std::endl; #endif #if WAIT_PENDING_VERSION - // TODO: to wait or not to wait - while (ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { - while (ver->status_.load(memory_order_acquire) == VersionStatus::pending - || ver->status_.load(memory_order_acquire) == VersionStatus::deleting) { - // To proceed other's commit we have to release lock of this page once - tuple->lock_.w_unlock(); - sleepTics(100); - tuple->lock_.w_lock(); - } - if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { - ver = ver->ldAcqNext(); - } - if (ver == nullptr) { - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } - } + // TODO: to wait or not to wait + while (ver->status_.load(memory_order_acquire) != + VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { + while ( + ver->status_.load(memory_order_acquire) == VersionStatus::pending || + ver->status_.load(memory_order_acquire) == VersionStatus::deleting) { + // To proceed other's commit we have to release lock of this page once + tuple->lock_.w_unlock(); + sleepTics(100); + tuple->lock_.w_lock(); + } + if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { + ver = ver->ldAcqNext(); + } + if (ver == nullptr) { + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } + } #else - ver = get_a_version(ver, followers); - if (ver == VERSION_TERMINATION) { - // versions exist but no committed ones - stat = Status::WARN_NOT_FOUND; - goto OUT; - } - if (ver == nullptr) { - // committed versions exist but no visible ones - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } + ver = get_a_version(ver, followers); + if (ver == VERSION_TERMINATION) { + // versions exist but no committed ones + stat = Status::WARN_NOT_FOUND; + goto OUT; + } + if (ver == nullptr) { + // committed versions exist but no visible ones + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } #endif - if (aligned_read) { - prev_ver = ver->ldAcqNext(); - if (prev_ver && has_inflight_reader(tuple, prev_ver->txid_)) { + if (aligned_read) { + prev_ver = ver->ldAcqNext(); + if (prev_ver && has_inflight_reader(tuple, prev_ver->txid_)) { #if DEBUG_MSG - std::cout << " Inflight reader found, drop " << ver->txid_ << std::endl; + std::cout << " Inflight reader found, drop " << ver->txid_ + << std::endl; #endif - followers.push_back(ver); - ver = prev_ver; - } else { - aligned_read = false; - } - } + followers.push_back(ver); + ver = prev_ver; + } else { + aligned_read = false; + } + } #if DEBUG_MSG - std::cout << " Version " << ver->txid_ - << " found, followers size is " << followers.size() << std::endl; + std::cout << " Version " << ver->txid_ << " found, followers size is " + << followers.size() << std::endl; #endif - if (reconnoitering_) { - goto OUT; - } + if (reconnoitering_) { goto OUT; } - // add anti-dependency edges found when skipping versions - for (auto& follower : followers) { - if (follower->txid_.epoch < this->txid_.epoch) { - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } - tuple->graph_.at(this->txid_).writtenBy_.emplace(follower->txid_); - } + // add anti-dependency edges found when skipping versions + for (auto& follower : followers) { + if (follower->txid_.epoch < this->txid_.epoch) { + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } + tuple->graph_.at(this->txid_).writtenBy_.emplace(follower->txid_); + } - update_read_from(tuple, ver); + update_read_from(tuple, ver); - if (has_cycle(tuple->graph_, this->txid_)) { + if (has_cycle(tuple->graph_, this->txid_)) { #if DEBUG_MSG - std::cout << " Version " << ver->txid_ << " is invisible" << std::endl; + std::cout << " Version " << ver->txid_ << " is invisible" << std::endl; #endif - // remove candidate edge and try next candidate - tuple->graph_.at(ver->txid_).readBy_.erase(this->txid_); - - if (aligned_read) { - // retry just once to check if the latest is visible - followers.clear(); - ver = get_a_version(tuple->ldAcqLatest(), followers); - if (ver == nullptr) { - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } - update_read_from(tuple, ver); - if (is_invisible(tuple, ver->txid_, this->txid_, tuple->graph_)) { - stat = Status::ERROR_NO_VISIBLE_VERSION; - } - goto OUT; - } + // remove candidate edge and try next candidate + tuple->graph_.at(ver->txid_).readBy_.erase(this->txid_); - if (ver->txid_.epoch < this->txid_.epoch) { - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } + if (aligned_read) { + // retry just once to check if the latest is visible + followers.clear(); + ver = get_a_version(tuple->ldAcqLatest(), followers); + if (ver == nullptr) { + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } + update_read_from(tuple, ver); + if (is_invisible(tuple, ver->txid_, this->txid_, tuple->graph_)) { + stat = Status::ERROR_NO_VISIBLE_VERSION; + } + goto OUT; + } + + if (ver->txid_.epoch < this->txid_.epoch) { + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } - // add anti-dependency edge before retry - tuple->graph_.at(this->txid_).writtenBy_.emplace(ver->txid_); - ver = ver->ldAcqNext(); - if (ver == VERSION_TERMINATION) { + // add anti-dependency edge before retry + tuple->graph_.at(this->txid_).writtenBy_.emplace(ver->txid_); + ver = ver->ldAcqNext(); + if (ver == VERSION_TERMINATION) { #if DEBUG_MSG - std::cout << " Version does not exists" << std::endl; + std::cout << " Version does not exists" << std::endl; #endif - stat = Status::WARN_NOT_FOUND; - goto OUT; - } - if (ver == nullptr) { + stat = Status::WARN_NOT_FOUND; + goto OUT; + } + if (ver == nullptr) { #if DEBUG_MSG - std::cout << " No readable version" << std::endl; + std::cout << " No readable version" << std::endl; #endif - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } else { + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; + } else { #if DEBUG_MSG - std::cout << " Retry to check next version" << std::endl; + std::cout << " Retry to check next version" << std::endl; #endif - goto RETRY; - } - } -OUT: - *return_ver = ver; - return stat; - } - - uint64_t get_read_version_cardinality() { - // only for statistics - TxSet txns; - for (auto re : read_set_) { - txns.emplace(re.txid_); - } - return txns.size(); + goto RETRY; + } } - - uint64_t get_first_read_epoch() { - auto itr = read_set_.begin(); - if (itr != read_set_.end()) { - TxID txid = (*itr).txid_; - return txid.epoch; - } - return -1; + OUT: + *return_ver = ver; + return stat; + } + + uint64_t get_read_version_cardinality() { + // only for statistics + TxSet txns; + for (auto re : read_set_) { txns.emplace(re.txid_); } + return txns.size(); + } + + uint64_t get_first_read_epoch() { + auto itr = read_set_.begin(); + if (itr != read_set_.end()) { + TxID txid = (*itr).txid_; + return txid.epoch; } + return -1; + } - Status get_visible_version(Tuple *tuple, Version **return_ver) { + Status get_visible_version(Tuple* tuple, Version** return_ver) { #ifdef USE_FIRST_READ_EPOCH - uint64_t epoch = get_first_read_epoch(); - if (epoch >= 0) { - auto itr1 = tuple->version_index_.find(epoch); - if (itr1 != tuple->version_index_.end()) { - for (auto& ver : tuple->version_index_.at(epoch)) { - if (ver->status_.load(memory_order_acquire) == VersionStatus::committed - || ver->status_.load(memory_order_acquire) == VersionStatus::deleted) { - if (auto itr2 = tuple->graph_.find(ver->txid_); itr2 == tuple->graph_.end()) { - tuple->graph_.emplace(ver->txid_, TxNode(ver->txid_)); - } - // add candidate edge - tuple->graph_.at(ver->txid_).readBy_.emplace(this->txid_); - if (!is_invisible(tuple, ver->txid_, this->txid_, tuple->graph_)) { - *return_ver = ver; - return Status::OK; - } else { - tuple->graph_.at(ver->txid_).readBy_.erase(this->txid_); - } - } - } + uint64_t epoch = get_first_read_epoch(); + if (epoch >= 0) { + auto itr1 = tuple->version_index_.find(epoch); + if (itr1 != tuple->version_index_.end()) { + for (auto& ver : tuple->version_index_.at(epoch)) { + if (ver->status_.load(memory_order_acquire) == + VersionStatus::committed || + ver->status_.load(memory_order_acquire) == + VersionStatus::deleted) { + if (auto itr2 = tuple->graph_.find(ver->txid_); + itr2 == tuple->graph_.end()) { + tuple->graph_.emplace(ver->txid_, TxNode(ver->txid_)); + } + // add candidate edge + tuple->graph_.at(ver->txid_).readBy_.emplace(this->txid_); + if (!is_invisible(tuple, ver->txid_, this->txid_, tuple->graph_)) { + *return_ver = ver; + return Status::OK; + } else { + tuple->graph_.at(ver->txid_).readBy_.erase(this->txid_); } + } } - // fall back if committed visible version not found using index -#endif - return __get_visible_version(tuple, return_ver); - } - - Status get_aligned_visible_version(Tuple* tuple, Version** return_ver) { - return __get_visible_version(tuple, return_ver, true); + } } - - Status get_visible_version_occ(Tuple* tuple, Version** return_ver) { - Version *ver; - Status stat = Status::OK; - - ver = tuple->ldAcqLatest(); - while (ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { - /** + // fall back if committed visible version not found using index +#endif + return __get_visible_version(tuple, return_ver); + } + + Status get_aligned_visible_version(Tuple* tuple, Version** return_ver) { + return __get_visible_version(tuple, return_ver, true); + } + + Status get_visible_version_occ(Tuple* tuple, Version** return_ver) { + Version* ver; + Status stat = Status::OK; + + ver = tuple->ldAcqLatest(); + while (ver->status_.load(memory_order_acquire) != + VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) { + /** * Wait for the result of the pending version in the view. */ - while (ver->status_.load(memory_order_acquire) == VersionStatus::pending) { - } - if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { - ver = ver->ldAcqNext(); - } - if (ver->status_ == VersionStatus::deleted) { - stat = Status::WARN_NOT_FOUND; - goto OUT; - } - if (ver == VERSION_TERMINATION) { - // versions exist but no committed ones - stat = Status::WARN_NOT_FOUND; - goto OUT; - } - if (ver == nullptr) { - // committed versions exist but no visible ones - stat = Status::ERROR_NO_VISIBLE_VERSION; - goto OUT; - } + while (ver->status_.load(memory_order_acquire) == + VersionStatus::pending) {} + if (ver->status_.load(memory_order_acquire) == VersionStatus::aborted) { + ver = ver->ldAcqNext(); + } + if (ver->status_ == VersionStatus::deleted) { + stat = Status::WARN_NOT_FOUND; + goto OUT; + } + if (ver == VERSION_TERMINATION) { + // versions exist but no committed ones + stat = Status::WARN_NOT_FOUND; + goto OUT; + } + if (ver == nullptr) { + // committed versions exist but no visible ones + stat = Status::ERROR_NO_VISIBLE_VERSION; + goto OUT; } - *return_ver = ver; - -OUT: - return stat; - } - - void add_related_read_keys(const TxNode *tx, KeySet &keys) { - for (const auto& [key, id] : tx->readSet_) - keys.insert(key); - } - - void add_related_all_keys(const TxNode *tx, KeySet &keys) { - for (const auto& [key, id] : tx->readSet_) - keys.insert(key); - for (const auto& key : tx->writeSet_) - keys.insert(key); } - - void push_candidate_keys(std::vector &targets, std::vector &done, KeySet &keys) { - for (const auto& key : keys) { - auto result1 = std::find(targets.begin(), targets.end(), key); - auto result2 = std::find(done.begin(), done.end(), key); - if (result1 == targets.end() && result2 == done.end()) - targets.push_back(key); - } + *return_ver = ver; + + OUT: + return stat; + } + + void add_related_read_keys(const TxNode* tx, KeySet& keys) { + for (const auto& [key, id] : tx->readSet_) keys.insert(key); + } + + void add_related_all_keys(const TxNode* tx, KeySet& keys) { + for (const auto& [key, id] : tx->readSet_) keys.insert(key); + for (const auto& key : tx->writeSet_) keys.insert(key); + } + + void push_candidate_keys(std::vector& targets, std::vector& done, + KeySet& keys) { + for (const auto& key : keys) { + auto result1 = std::find(targets.begin(), targets.end(), key); + auto result2 = std::find(done.begin(), done.end(), key); + if (result1 == targets.end() && result2 == done.end()) + targets.push_back(key); } - - void push_candidate_keys(KeySet &targets, KeySet &done, KeySet &keys) { - for (const auto& key : keys) { - auto result1 = targets.find(key); - auto result2 = done.find(key); - if (result1 == targets.end() && result2 == done.end()) - targets.insert(key); - } + } + + void push_candidate_keys(KeySet& targets, KeySet& done, KeySet& keys) { + for (const auto& key : keys) { + auto result1 = targets.find(key); + auto result2 = done.find(key); + if (result1 == targets.end() && result2 == done.end()) + targets.insert(key); } + } - bool check_rf_cycle_dfs(Graph &g, TxSet &readsfrom, std::map &seen, TxID txID) { - seen.emplace(txID, true); - TxSet edges(g.at(txID).readBy_); - edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); + bool check_rf_cycle_dfs(Graph& g, TxSet& readsfrom, + std::map& seen, TxID txID) { + seen.emplace(txID, true); + TxSet edges(g.at(txID).readBy_); + edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); - if (auto it = readsfrom.find(txID); it != readsfrom.end()) - return true; + if (auto it = readsfrom.find(txID); it != readsfrom.end()) return true; - for (const auto& next : edges) { - if (auto it = seen.find(next); it != seen.end() && seen[next]) continue; - auto ret = check_rf_cycle_dfs(g, readsfrom, seen, next); - if (ret) - return ret; - } - return false; + for (const auto& next : edges) { + if (auto it = seen.find(next); it != seen.end() && seen[next]) continue; + auto ret = check_rf_cycle_dfs(g, readsfrom, seen, next); + if (ret) return ret; } - - bool has_reads_from_cycle(TxID start, Graph &g, ReadSet &readSet) { - std::map seen; - TxSet readsfrom; - for (const auto& [k, id] : readSet) { - readsfrom.insert(id); - } - for (const auto& next : g.at(start).writtenBy_) { - auto ret = check_rf_cycle_dfs(g, readsfrom, seen, next); - if (ret) return true; - } - return false; + return false; + } + + bool has_reads_from_cycle(TxID start, Graph& g, ReadSet& readSet) { + std::map seen; + TxSet readsfrom; + for (const auto& [k, id] : readSet) { readsfrom.insert(id); } + for (const auto& next : g.at(start).writtenBy_) { + auto ret = check_rf_cycle_dfs(g, readsfrom, seen, next); + if (ret) return true; } - - bool check_cycle_dfs(const Graph &g, std::map &seen, std::map &finished, const TxID txID) { - if (quit_) { - dump(thid_, "WARN: Quit cycle check because benchmark has finished."); - status_ = TransactionStatus::invalid; - return true; // TODO: should return with INVALID - } - seen.emplace(txID, true); - TxSet edges(g.at(txID).readBy_); - edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); - - for (const auto& next : edges) { - auto f = finished.find(next); - if (f != finished.end() && finished[next]) continue; - auto s = seen.find(next); - if (s != seen.end() && seen[next] && f == finished.end()) - return true; - if (auto it = g.find(next); it != g.end()) { - auto ret = check_cycle_dfs(g, seen, finished, next); - if (ret) - return ret; - } - } - finished[txID] = true; - return false; + return false; + } + + bool check_cycle_dfs(const Graph& g, std::map& seen, + std::map& finished, const TxID txID) { + if (quit_) { + dump(thid_, "WARN: Quit cycle check because benchmark has finished."); + status_ = TransactionStatus::invalid; + return true; // TODO: should return with INVALID } + seen.emplace(txID, true); + TxSet edges(g.at(txID).readBy_); + edges.insert(g.at(txID).writtenBy_.begin(), g.at(txID).writtenBy_.end()); + + for (const auto& next : edges) { + auto f = finished.find(next); + if (f != finished.end() && finished[next]) continue; + auto s = seen.find(next); + if (s != seen.end() && seen[next] && f == finished.end()) return true; + if (auto it = g.find(next); it != g.end()) { + auto ret = check_cycle_dfs(g, seen, finished, next); + if (ret) return ret; + } + } + finished[txID] = true; + return false; + } - bool has_cycle(const Graph &g, const TxID start) { + bool has_cycle(const Graph& g, const TxID start) { #if ADD_ANALYSIS - result_->local_graph_size_ += g.size(); - ++result_->local_cycle_check_count_; -#endif // if ADD_ANALYSIS - std::map seen, finished; - TxSet edges(g.at(start).readBy_); - edges.insert(g.at(start).writtenBy_.begin(), g.at(start).writtenBy_.end()); - - for (const auto& next : edges) { - if (auto it = g.find(next); it != g.end()) { - auto ret = check_cycle_dfs(g, seen, finished, next); - if (ret) return true; - } - } - return false; + result_->local_graph_size_ += g.size(); + ++result_->local_cycle_check_count_; +#endif // if ADD_ANALYSIS + std::map seen, finished; + TxSet edges(g.at(start).readBy_); + edges.insert(g.at(start).writtenBy_.begin(), g.at(start).writtenBy_.end()); + + for (const auto& next : edges) { + if (auto it = g.find(next); it != g.end()) { + auto ret = check_cycle_dfs(g, seen, finished, next); + if (ret) return true; + } } - - // probably only debug-use - bool has_cycle(Graph &g) { - std::map seen, finished; - for (const auto& [txid, node] : g) { - TxSet edges(g.at(txid).readBy_); - edges.insert(g.at(txid).writtenBy_.begin(), g.at(txid).writtenBy_.end()); - for (const auto& next : edges) { - auto ret = check_cycle_dfs(g, seen, finished, next); - if (ret) return true; - } - } - return false; + return false; + } + + // probably only debug-use + bool has_cycle(Graph& g) { + std::map seen, finished; + for (const auto& [txid, node] : g) { + TxSet edges(g.at(txid).readBy_); + edges.insert(g.at(txid).writtenBy_.begin(), g.at(txid).writtenBy_.end()); + for (const auto& next : edges) { + auto ret = check_cycle_dfs(g, seen, finished, next); + if (ret) return true; + } } - - void merge(Graph &target, Graph &source) { - for (const auto& [tid, sourceTxNode] : source) { - TxNode *targetTxNode; - if (auto it = target.find(tid); it != target.end()) { - targetTxNode = &target.at(tid); - } else { - target.emplace(tid, TxNode(tid)); - targetTxNode = &target.at(tid); - } - if (targetTxNode->is_aborted) { - clean_up_node_edges(target, tid); - continue; - } - targetTxNode->readSet_.insert(sourceTxNode.readSet_.begin(), sourceTxNode.readSet_.end()); - targetTxNode->writeSet_.insert(sourceTxNode.writeSet_.begin(), sourceTxNode.writeSet_.end()); - for (const auto& to : sourceTxNode.readBy_) - targetTxNode->readBy_.insert(to); - for (const auto& to : sourceTxNode.writtenBy_) - targetTxNode->writtenBy_.insert(to); - for (const auto& from : sourceTxNode.from_) - targetTxNode->from_.insert(from); - // Update status if the transaction in source graph is validating - if (targetTxNode->status_ == TransactionStatus::inflight - && sourceTxNode.status_ == TransactionStatus::validating) - targetTxNode->status_ = TransactionStatus::validating; - } + return false; + } + + void merge(Graph& target, Graph& source) { + for (const auto& [tid, sourceTxNode] : source) { + TxNode* targetTxNode; + if (auto it = target.find(tid); it != target.end()) { + targetTxNode = &target.at(tid); + } else { + target.emplace(tid, TxNode(tid)); + targetTxNode = &target.at(tid); + } + if (targetTxNode->is_aborted) { + clean_up_node_edges(target, tid); + continue; + } + targetTxNode->readSet_.insert(sourceTxNode.readSet_.begin(), + sourceTxNode.readSet_.end()); + targetTxNode->writeSet_.insert(sourceTxNode.writeSet_.begin(), + sourceTxNode.writeSet_.end()); + for (const auto& to : sourceTxNode.readBy_) + targetTxNode->readBy_.insert(to); + for (const auto& to : sourceTxNode.writtenBy_) + targetTxNode->writtenBy_.insert(to); + for (const auto& from : sourceTxNode.from_) + targetTxNode->from_.insert(from); + // Update status if the transaction in source graph is validating + if (targetTxNode->status_ == TransactionStatus::inflight && + sourceTxNode.status_ == TransactionStatus::validating) + targetTxNode->status_ = TransactionStatus::validating; } + } - uint64_t get_min_epoch() { - uint64_t min = UINT64_MAX; - for (unsigned int i = 0; i < TotalThreadNum; ++i) { - auto e = ThManagementTable[i]->atomicLoadEpoch(); - if (e < min) - min = e; - } - return min; + uint64_t get_min_epoch() { + uint64_t min = UINT64_MAX; + for (unsigned int i = 0; i < TotalThreadNum; ++i) { + auto e = ThManagementTable[i]->atomicLoadEpoch(); + if (e < min) min = e; } - - void erase_following_edges(Graph &g, const TxID txid) { - for (auto& reader : g.at(txid).readBy_) { - if (auto it = g.find(reader); it != g.end()) // TODO: why is this check necessary? - g.at(reader).from_.erase(txid); - } - for (auto& writer : g.at(txid).writtenBy_) { - if (auto it = g.find(writer); it != g.end()) // TODO: why is this check necessary? - g.at(writer).from_.erase(txid); - } + return min; + } + + void erase_following_edges(Graph& g, const TxID txid) { + for (auto& reader : g.at(txid).readBy_) { + if (auto it = g.find(reader); + it != g.end()) // TODO: why is this check necessary? + g.at(reader).from_.erase(txid); } - - void gc(Graph &g, uint64_t epoch) { - bool assert = false; - int non = 0; - int incoming = 0; - int read = 0; - int write = 0; - // if (g.size() > 50) { - // generate_dot_graph("gc1", g); - // assert = true; - // } + for (auto& writer : g.at(txid).writtenBy_) { + if (auto it = g.find(writer); + it != g.end()) // TODO: why is this check necessary? + g.at(writer).from_.erase(txid); + } + } + + void gc(Graph& g, uint64_t epoch) { + bool assert = false; + int non = 0; + int incoming = 0; + int read = 0; + int write = 0; + // if (g.size() > 50) { + // generate_dot_graph("gc1", g); + // assert = true; + // } #if DEBUG_MSG - std::cout << " GC check start, reclamation epoch = " << epoch << std::endl; + std::cout << " GC check start, reclamation epoch = " << epoch << std::endl; #endif - for (auto it = g.begin(); it != g.end();) { - auto txid = (*it).first; - auto txNode = &(*it).second; + for (auto it = g.begin(); it != g.end();) { + auto txid = (*it).first; + auto txNode = &(*it).second; #ifdef GC_ABORTED_TX - if (is_aborted(txid)) { - // std::cout << " Aborted TxNode: " << txid << " removed in GC" << std::endl; - clean_up_node_edges(g, txid); - it = g.erase(it); - continue; - } + if (is_aborted(txid)) { + // std::cout << " Aborted TxNode: " << txid << " removed in GC" << std::endl; + clean_up_node_edges(g, txid); + it = g.erase(it); + continue; + } #endif - if (txid.epoch <= epoch) { - // std::cout << "TxID: " << txid << std::endl; - bool keep = false; - for (auto i = txNode->readBy_.begin(); i != txNode->readBy_.end();) { - auto reader = (*i); - if (reader.epoch <= epoch) { - // std::cout << " R " << reader << std::endl; - if (auto it = g.find(reader); it != g.end()) // TODO: why is this check necessary? - g.at(reader).from_.erase(txid); - i = txNode->readBy_.erase(i); - } else { - keep = true; - read++; - ++i; - } - } - for (auto i = txNode->writtenBy_.begin(); i != txNode->writtenBy_.end();) { - auto writer = (*i); - if (writer.epoch <= epoch) { - // std::cout << " W " << writer << std::endl; - if (auto it = g.find(writer); it != g.end()) // TODO: why is this check necessary? - g.at(writer).from_.erase(txid); - i = txNode->writtenBy_.erase(i); - } else { - keep = true; - write++; - ++i; - } - } - for (auto i = txNode->from_.begin(); i != txNode->from_.end();) { - auto from = (*i); - if (from.epoch > epoch) { - keep = true; - break; - } - ++i; - } - - // std::cout << " -> R: "; - // for (const auto& id : txNode->readBy_) std::cout << id << " "; std::cout << std::endl; - // std::cout << " -> W: "; - // for (const auto& id : txNode->writtenBy_) std::cout << id << " "; std::cout << std::endl; - if (keep) { - ++it; - continue; - } - if (txNode->from_.size() > 0) { - ++it; - incoming++; - continue; - } - // std::cout << " Reclaim TxID = " << txid - // << ", Reclaimation epoch = " << epoch - // << ", Local epoch = " << ThLocalEpoch[thid_].obj_ - // << ")" << std::endl; - erase_following_edges(g, txid); - it = g.erase(it); - } - else { - non++; - ++it; - } + if (txid.epoch <= epoch) { + // std::cout << "TxID: " << txid << std::endl; + bool keep = false; + for (auto i = txNode->readBy_.begin(); i != txNode->readBy_.end();) { + auto reader = (*i); + if (reader.epoch <= epoch) { + // std::cout << " R " << reader << std::endl; + if (auto it = g.find(reader); + it != g.end()) // TODO: why is this check necessary? + g.at(reader).from_.erase(txid); + i = txNode->readBy_.erase(i); + } else { + keep = true; + read++; + ++i; + } } - if (assert) { - std::cout << "GC done" << std::endl; - std::cout << "Reclaimation epoch: " << epoch << std::endl; - std::cout << "Local epoch: " << ThManagementTable[thid_]->atomicLoadEpoch() << std::endl; - std::cout << "Non: " << non << std::endl; - std::cout << "Incoming: " << incoming << std::endl; - std::cout << "Read: " << read << std::endl; - std::cout << "Write: " << write << std::endl; - generate_dot_graph("gc2", g); - my_assert(false); + for (auto i = txNode->writtenBy_.begin(); + i != txNode->writtenBy_.end();) { + auto writer = (*i); + if (writer.epoch <= epoch) { + // std::cout << " W " << writer << std::endl; + if (auto it = g.find(writer); + it != g.end()) // TODO: why is this check necessary? + g.at(writer).from_.erase(txid); + i = txNode->writtenBy_.erase(i); + } else { + keep = true; + write++; + ++i; + } } - } - - void remove_indifferent_nodes(Graph &g) { - auto n = 0; - auto m = 0; - TxSet reachable_from; - TxSet reachable_to; - find_reachable_from(this->txid_, g, reachable_from); - find_reachable_to(this->txid_, g, reachable_to); - for (auto it = g.begin(); it != g.end();) { - auto txid = (*it).first; - auto txnode = (*it).second; - auto conflict = has_any_conflict( - this->readSet_, this->writeSet_, - g.at(txid).readSet_, - g.at(txid).writeSet_); - if (!conflict) { - n++; - auto it1 = reachable_from.find(txid); - auto it2 = reachable_to.find(txid); - if (it1 == reachable_from.end() && it2 == reachable_to.end()) { - for (auto& from : g.at(txid).from_) { - g.at(from).readBy_.erase(txid); - g.at(from).writtenBy_.erase(txid); - } - erase_following_edges(g, txid); - it = g.erase(it); - m++; - continue; - } - } - ++it; + for (auto i = txNode->from_.begin(); i != txNode->from_.end();) { + auto from = (*i); + if (from.epoch > epoch) { + keep = true; + break; + } + ++i; } - // std::cout << "Non-conflict nodes: " << n << std::endl; - // std::cout << "Indifferent nodes: " << m << std::endl; - } - - TxID get_read_version(Key key) { - auto it = readSet_.find(key); - if (it != readSet_.end()) - return it->second; - else - return TxID(); - } - - Status insert_version(WriteElement we) { - // For insert record, followers set is always empty due to post-ordering only - TxSet s; - return insert_version(we, s); - } - Status insert_version(WriteElement we, TxSet& followers) { - Tuple* tuple = we.rcdptr_; - if (we.op_ == OpType::DELETE) { - we.new_ver_->status_ = VersionStatus::deleting; - } else { - we.new_ver_->status_ = VersionStatus::pending; + // std::cout << " -> R: "; + // for (const auto& id : txNode->readBy_) std::cout << id << " "; std::cout << std::endl; + // std::cout << " -> W: "; + // for (const auto& id : txNode->writtenBy_) std::cout << id << " "; std::cout << std::endl; + if (keep) { + ++it; + continue; } - Version* v = tuple->latest_; - if (v->status_ == VersionStatus::deleting || v->status_ == VersionStatus::deleted) { - return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; + if (txNode->from_.size() > 0) { + ++it; + incoming++; + continue; } - if (followers.size() == 0) { - we.new_ver_->next_ = v; - tuple->latest_ = we.new_ver_; - } else { - Version* prev = v; - while (followers.size() > 0) { - followers.erase(v->txid_); - prev = v; - v = v->next_; - } - prev->next_ = we.new_ver_; - we.new_ver_->next_ = v; - } - return Status::OK; + // std::cout << " Reclaim TxID = " << txid + // << ", Reclaimation epoch = " << epoch + // << ", Local epoch = " << ThLocalEpoch[thid_].obj_ + // << ")" << std::endl; + erase_following_edges(g, txid); + it = g.erase(it); + } else { + non++; + ++it; + } } - - void clean_up_node_edges(Graph &g, const TxID txid) { - // TODO: can be sophisticated? - for (const auto& to : g.at(txid).writtenBy_) { - if (auto it = g.find(to); it != g.end()) // TODO: can be checkless? - g.at(to).from_.erase(txid); - } - for (const auto& from : g.at(txid).from_) { - if (auto it = g.find(from); it != g.end()) { // TODO: can be checkless? - g.at(from).readBy_.erase(txid); - g.at(from).writtenBy_.erase(txid); - } - } - // We want to just remove this aborted node, - // but some other worker may have seen this node - // (that is still inflight at that time), and try to merge - // without knowing it has already aborted. - // So, just mark it aborted and prevent it from adding edges - g.at(txid).readBy_.clear(); - g.at(txid).writtenBy_.clear(); - g.at(txid).from_.clear(); - g.at(txid).is_aborted = true; + if (assert) { + std::cout << "GC done" << std::endl; + std::cout << "Reclaimation epoch: " << epoch << std::endl; + std::cout << "Local epoch: " + << ThManagementTable[thid_]->atomicLoadEpoch() << std::endl; + std::cout << "Non: " << non << std::endl; + std::cout << "Incoming: " << incoming << std::endl; + std::cout << "Read: " << read << std::endl; + std::cout << "Write: " << write << std::endl; + generate_dot_graph("gc2", g); + my_assert(false); } - - void lock_write_set() { - for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - if (itr->op_ == OpType::INSERT) continue; - itr->rcdptr_->lock_.w_lock(); - if (IS_OCC(cc_mode_) && itr->op_ == OpType::UPDATE) { - // in Oze mode, we already inserted a version with concurrent deletion check, - // so we can skip the check below - Version* ver; - Status stat = get_visible_version_occ(itr->rcdptr_, &ver); - if (stat != Status::OK || ver->status_ == VersionStatus::deleted) { - unlock_write_set(itr); - this->status_ = TransactionStatus::aborted; - return; + } + + void remove_indifferent_nodes(Graph& g) { + auto n = 0; + auto m = 0; + TxSet reachable_from; + TxSet reachable_to; + find_reachable_from(this->txid_, g, reachable_from); + find_reachable_to(this->txid_, g, reachable_to); + for (auto it = g.begin(); it != g.end();) { + auto txid = (*it).first; + auto txnode = (*it).second; + auto conflict = + has_any_conflict(this->readSet_, this->writeSet_, g.at(txid).readSet_, + g.at(txid).writeSet_); + if (!conflict) { + n++; + auto it1 = reachable_from.find(txid); + auto it2 = reachable_to.find(txid); + if (it1 == reachable_from.end() && it2 == reachable_to.end()) { + for (auto& from : g.at(txid).from_) { + g.at(from).readBy_.erase(txid); + g.at(from).writtenBy_.erase(txid); } + erase_following_edges(g, txid); + it = g.erase(it); + m++; + continue; } - - this->max_tid_wset_ = max(this->max_tid_wset_, (*itr).rcdptr_->tuple_id_); } + ++it; } - - void unlock_write_set() { - for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - if ((*itr).op_ == OpType::INSERT) continue; - (*itr).rcdptr_->lock_.w_unlock(); - } + // std::cout << "Non-conflict nodes: " << n << std::endl; + // std::cout << "Indifferent nodes: " << m << std::endl; + } + + TxID get_read_version(Key key) { + auto it = readSet_.find(key); + if (it != readSet_.end()) + return it->second; + else + return TxID(); + } + + Status insert_version(WriteElement we) { + // For insert record, followers set is always empty due to post-ordering only + TxSet s; + return insert_version(we, s); + } + + Status insert_version(WriteElement we, TxSet& followers) { + Tuple* tuple = we.rcdptr_; + if (we.op_ == OpType::DELETE) { + we.new_ver_->status_ = VersionStatus::deleting; + } else { + we.new_ver_->status_ = VersionStatus::pending; } - - void unlock_write_set(std::vector>::iterator end) { - for (auto itr = write_set_.begin(); itr != end; ++itr) { - if ((*itr).op_ == OpType::INSERT) continue; - (*itr).rcdptr_->lock_.w_unlock(); + Version* v = tuple->latest_; + if (v->status_ == VersionStatus::deleting || + v->status_ == VersionStatus::deleted) { + return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; + } + if (followers.size() == 0) { + we.new_ver_->next_ = v; + tuple->latest_ = we.new_ver_; + } else { + Version* prev = v; + while (followers.size() > 0) { + followers.erase(v->txid_); + prev = v; + v = v->next_; } + prev->next_ = we.new_ver_; + we.new_ver_->next_ = v; } - - TupleId decide_tuple_id() { - TupleId tid_a, tid_b, tid_c; - - // calculates (a) - // about read_set_ - tid_a = std::max(max_tid_wset_, max_tid_rset_); - tid_a.tid++; - - // calculates (b) - // larger than the worker's most recently chosen TID, - tid_b = most_recent_tid_; - tid_b.tid++; - - // calculates (c) - tid_c.epoch = txid_.epoch; - - // compare a, b, c - return std::max({tid_a, tid_b, tid_c}); + return Status::OK; + } + + void clean_up_node_edges(Graph& g, const TxID txid) { + // TODO: can be sophisticated? + for (const auto& to : g.at(txid).writtenBy_) { + if (auto it = g.find(to); it != g.end()) // TODO: can be checkless? + g.at(to).from_.erase(txid); } - - void commit_version(WriteElement we) { - if (we.op_ == OpType::DELETE) { - Masstrees[get_storage(we.storage_)].remove_value(we.key_); - we.new_ver_->status_.store(VersionStatus::deleted, std::memory_order_release); - gc_records_.push_back(we.rcdptr_); - } else { - we.new_ver_->status_.store(VersionStatus::committed, std::memory_order_release); + for (const auto& from : g.at(txid).from_) { + if (auto it = g.find(from); it != g.end()) { // TODO: can be checkless? + g.at(from).readBy_.erase(txid); + g.at(from).writtenBy_.erase(txid); } } + // We want to just remove this aborted node, + // but some other worker may have seen this node + // (that is still inflight at that time), and try to merge + // without knowing it has already aborted. + // So, just mark it aborted and prevent it from adding edges + g.at(txid).readBy_.clear(); + g.at(txid).writtenBy_.clear(); + g.at(txid).from_.clear(); + g.at(txid).is_aborted = true; + } + + void lock_write_set() { + for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { + if (itr->op_ == OpType::INSERT) continue; + itr->rcdptr_->lock_.w_lock(); + if (IS_OCC(cc_mode_) && itr->op_ == OpType::UPDATE) { + // in Oze mode, we already inserted a version with concurrent deletion check, + // so we can skip the check below + Version* ver; + Status stat = get_visible_version_occ(itr->rcdptr_, &ver); + if (stat != Status::OK || ver->status_ == VersionStatus::deleted) { + unlock_write_set(itr); + this->status_ = TransactionStatus::aborted; + return; + } + } - bool should_switch_to_occ() { - // TODO: implement - // if (result_->local_commit_counts_ > 100) { - // return true; - // } - return false; + this->max_tid_wset_ = max(this->max_tid_wset_, (*itr).rcdptr_->tuple_id_); } + } - bool should_switch_to_oze() { - // TODO: implement - // if (result_->local_commit_counts_ > 5000) { - // return true; - // } - return false; + void unlock_write_set() { + for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { + if ((*itr).op_ == OpType::INSERT) continue; + (*itr).rcdptr_->lock_.w_unlock(); } + } - uint8_t get_next_cc_mode() { - uint8_t mode_array[TotalThreadNum]; - for (unsigned int i = 0; i < TotalThreadNum; ++i) { - mode_array[i] = ThManagementTable[i]->atomicLoadMode(); - } - if (all_threads_in(OCC_MODE, mode_array)) { - return should_switch_to_oze() ? TO_OZE_MODE : OCC_MODE; - } - if (all_threads_in(OZE_MODE, mode_array)) { - return should_switch_to_occ() ? TO_OCC_MODE : OZE_MODE; - } - if (cc_mode_ == TO_OCC_MODE - && some_other_threads_in(OZE_MODE, mode_array, thid_)) { - return TO_OCC_MODE; - } - if (cc_mode_ == TO_OZE_MODE - && some_other_threads_in(OCC_MODE, mode_array, thid_)) { - return TO_OZE_MODE; - } - if (some_threads_in(TO_OCC_MODE, mode_array)) { - return OCC_MODE; - } - if (some_threads_in(TO_OZE_MODE, mode_array)) { - return OZE_MODE; - } - ERR; + void unlock_write_set(std::vector>::iterator end) { + for (auto itr = write_set_.begin(); itr != end; ++itr) { + if ((*itr).op_ == OpType::INSERT) continue; + (*itr).rcdptr_->lock_.w_unlock(); } - - void print_read_write_set(ReadSet rset, WriteSet wset) { - std::cout << " ReadSet: "; - for (const auto& [key, id] : rset) - std::cout << key << "-" << id << " "; - std::cout << std::endl; - std::cout << " WriteSet: "; - for (auto& key : wset) - std::cout << key << " "; - std::cout << std::endl; + } + + TupleId decide_tuple_id() { + TupleId tid_a, tid_b, tid_c; + + // calculates (a) + // about read_set_ + tid_a = std::max(max_tid_wset_, max_tid_rset_); + tid_a.tid++; + + // calculates (b) + // larger than the worker's most recently chosen TID, + tid_b = most_recent_tid_; + tid_b.tid++; + + // calculates (c) + tid_c.epoch = txid_.epoch; + + // compare a, b, c + return std::max({tid_a, tid_b, tid_c}); + } + + void commit_version(WriteElement we) { + if (we.op_ == OpType::DELETE) { + Masstrees[get_storage(we.storage_)].remove_value(we.key_); + we.new_ver_->status_.store(VersionStatus::deleted, + std::memory_order_release); + gc_records_.push_back(we.rcdptr_); + } else { + we.new_ver_->status_.store(VersionStatus::committed, + std::memory_order_release); } - - void print_graph(Graph g) { - std::cout << " Graph: " << std::endl; - for (const auto& [txid, node] : g) { - std::cout << " TxID: " << txid; - if (node.is_aborted) { - std::cout << " (a)" << std::endl; - } else { - std::cout << std::endl; - } - print_read_write_set(node.readSet_, node.writeSet_); - std::cout << " Read by: "; - for (const auto& id : node.readBy_) - std::cout << id << " "; - std::cout << std::endl; - std::cout << " Written by: "; - for (const auto& id : node.writtenBy_) - std::cout << id << " "; - std::cout << std::endl; - std::cout << " From: "; - for (const auto& id : node.from_) - std::cout << id << " "; - std::cout << std::endl; - } + } + + bool should_switch_to_occ() { + // TODO: implement + // if (result_->local_commit_counts_ > 100) { + // return true; + // } + return false; + } + + bool should_switch_to_oze() { + // TODO: implement + // if (result_->local_commit_counts_ > 5000) { + // return true; + // } + return false; + } + + uint8_t get_next_cc_mode() { + uint8_t mode_array[TotalThreadNum]; + for (unsigned int i = 0; i < TotalThreadNum; ++i) { + mode_array[i] = ThManagementTable[i]->atomicLoadMode(); } - - void generate_dot_graph(std::string name, Graph &g) { - std::string thid = "th" + std::to_string(thid_); - std::string dotfile = DEBUG_OUT_DIR + thid + name + ".dot"; - std::string pngfile = DEBUG_OUT_DIR + thid + name + ".png"; - std::ofstream ofs(dotfile); - ofs << "digraph " << name << " {" << std::endl; - ofs << " graph [rankdir=LR];" << std::endl; - ofs << " node [shape=circle];" << std::endl; - for (const auto& [txid, node] : g) { - for (const auto& id : node.readBy_) { - ofs << " \"" << txid << "\" -> \"" << id << "\";" << std::endl; - } - for (const auto& id : node.writtenBy_) { - ofs << " \"" << txid << "\" -> \"" << id << "\"[color=red];" << std::endl; - } - } - ofs << "}" << std::endl; - ofs.close(); - // std::string options = " -T png -o " + pngfile + " " + dotfile; - // std::string command = DOT_COMMAND + options; - // auto result = system(command.c_str()); + if (all_threads_in(OCC_MODE, mode_array)) { + return should_switch_to_oze() ? TO_OZE_MODE : OCC_MODE; } - - void print_record(Tuple* tuple) { - if (!tuple) { - std::cout << "No such record." << std::endl; - return; - } - std::string key(tuple->latest_.load(memory_order_acquire)->body_.get_key()); - std::cout << "Key: " << key << " (" << tuple << ")" << std::endl; - print_graph(tuple->graph_); + if (all_threads_in(OZE_MODE, mode_array)) { + return should_switch_to_occ() ? TO_OCC_MODE : OZE_MODE; } - - void print_transaction() { - std::cout << "TxID: " << txid_ << " " << std::endl; - print_read_write_set(readSet_, writeSet_); - print_graph(graph_); + if (cc_mode_ == TO_OCC_MODE && + some_other_threads_in(OZE_MODE, mode_array, thid_)) { + return TO_OCC_MODE; } - - std::string to_string() { - return std::to_string(txid_.epoch) + "_" - + std::to_string(txid_.thid) + "_" + std::to_string(txid_.tid); + if (cc_mode_ == TO_OZE_MODE && + some_other_threads_in(OCC_MODE, mode_array, thid_)) { + return TO_OZE_MODE; + } + if (some_threads_in(TO_OCC_MODE, mode_array)) { return OCC_MODE; } + if (some_threads_in(TO_OZE_MODE, mode_array)) { return OZE_MODE; } + ERR; + } + + void print_read_write_set(ReadSet rset, WriteSet wset) { + std::cout << " ReadSet: "; + for (const auto& [key, id] : rset) std::cout << key << "-" << id << " "; + std::cout << std::endl; + std::cout << " WriteSet: "; + for (auto& key : wset) std::cout << key << " "; + std::cout << std::endl; + } + + void print_graph(Graph g) { + std::cout << " Graph: " << std::endl; + for (const auto& [txid, node] : g) { + std::cout << " TxID: " << txid; + if (node.is_aborted) { + std::cout << " (a)" << std::endl; + } else { + std::cout << std::endl; + } + print_read_write_set(node.readSet_, node.writeSet_); + std::cout << " Read by: "; + for (const auto& id : node.readBy_) std::cout << id << " "; + std::cout << std::endl; + std::cout << " Written by: "; + for (const auto& id : node.writtenBy_) std::cout << id << " "; + std::cout << std::endl; + std::cout << " From: "; + for (const auto& id : node.from_) std::cout << id << " "; + std::cout << std::endl; + } + } + + void generate_dot_graph(std::string name, Graph& g) { + std::string thid = "th" + std::to_string(thid_); + std::string dotfile = DEBUG_OUT_DIR + thid + name + ".dot"; + std::string pngfile = DEBUG_OUT_DIR + thid + name + ".png"; + std::ofstream ofs(dotfile); + ofs << "digraph " << name << " {" << std::endl; + ofs << " graph [rankdir=LR];" << std::endl; + ofs << " node [shape=circle];" << std::endl; + for (const auto& [txid, node] : g) { + for (const auto& id : node.readBy_) { + ofs << " \"" << txid << "\" -> \"" << id << "\";" << std::endl; + } + for (const auto& id : node.writtenBy_) { + ofs << " \"" << txid << "\" -> \"" << id << "\"[color=red];" + << std::endl; + } + } + ofs << "}" << std::endl; + ofs.close(); + // std::string options = " -T png -o " + pngfile + " " + dotfile; + // std::string command = DOT_COMMAND + options; + // auto result = system(command.c_str()); + } + + void print_record(Tuple* tuple) { + if (!tuple) { + std::cout << "No such record." << std::endl; + return; } + std::string key(tuple->latest_.load(memory_order_acquire)->body_.get_key()); + std::cout << "Key: " << key << " (" << tuple << ")" << std::endl; + print_graph(tuple->graph_); + } + + void print_transaction() { + std::cout << "TxID: " << txid_ << " " << std::endl; + print_read_write_set(readSet_, writeSet_); + print_graph(graph_); + } + + std::string to_string() { + return std::to_string(txid_.epoch) + "_" + std::to_string(txid_.thid) + + "_" + std::to_string(txid_.tid); + } }; static_assert(TxExecutorLike); diff --git a/cc/oze/include/tuple.hh b/cc/oze/include/tuple.hh index ef7ef364..5a2933e7 100644 --- a/cc/oze/include/tuple.hh +++ b/cc/oze/include/tuple.hh @@ -13,7 +13,7 @@ // The nullptr is currenlty used for no readable version in serializablity perspective // Note that there exists "no readable version" case even if the version is not nullptr, // so it also must be fixed... -#define VERSION_TERMINATION (Version*)0x1 +#define VERSION_TERMINATION (Version*) 0x1 using namespace std; @@ -21,61 +21,62 @@ struct TupleId { union { uint64_t obj_; struct { - uint64_t tid: 32; - uint64_t epoch: 32; + uint64_t tid : 32; + uint64_t epoch : 32; }; }; TupleId() { obj_ = 0; } - bool operator==(const TupleId &right) const { return obj_ == right.obj_; } + bool operator==(const TupleId& right) const { return obj_ == right.obj_; } - bool operator!=(const TupleId &right) const { return !operator==(right); } + bool operator!=(const TupleId& right) const { return !operator==(right); } - bool operator<(const TupleId &right) const { return this->obj_ < right.obj_; } + bool operator<(const TupleId& right) const { return this->obj_ < right.obj_; } }; class Tuple { public: alignas(CACHE_LINE_SIZE) TupleId tuple_id_; RWLock lock_; - atomic latest_; + atomic latest_; TupleBody body_; // only used for index tuple as single version Graph graph_; - std::map> version_index_; + std::map> version_index_; Tuple() : latest_(nullptr) {} - Version *ldAcqLatest() { return latest_.load(std::memory_order_acquire); } + Version* ldAcqLatest() { return latest_.load(std::memory_order_acquire); } void init(TxID txid, TupleBody&& body) { latest_.store(new Version(), std::memory_order_release); (latest_.load(std::memory_order_acquire)) - ->set(txid, VERSION_TERMINATION, VersionStatus::pending); + ->set(txid, VERSION_TERMINATION, VersionStatus::pending); (latest_.load(std::memory_order_acquire))->body_ = std::move(body); body_ = std::ref((latest_.load(std::memory_order_acquire))->body_); - Graph* g = ::new(&graph_) Graph; + Graph* g = ::new (&graph_) Graph; g->emplace(txid, TxNode(txid, TransactionStatus::validating)); - version_index_ = std::map>(); + version_index_ = std::map>(); } // only for initial data preparation - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* param) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* param) { TxID txid = TxID(); txid.thid = thid; latest_.store(new Version(), std::memory_order_release); (latest_.load(std::memory_order_acquire)) - ->set(txid, nullptr, VersionStatus::committed); + ->set(txid, nullptr, VersionStatus::committed); (latest_.load(std::memory_order_acquire))->body_ = std::move(body); body_ = std::ref((latest_.load(std::memory_order_acquire))->body_); - Graph* g = ::new(&graph_) Graph; + Graph* g = ::new (&graph_) Graph; g->emplace(txid, TxNode(txid, TransactionStatus::validating)); - version_index_ = std::map>(); + version_index_ = std::map>(); // Omit to add all the key/pages write set of this TxNode. // But probably no problem because no transaction can precede this tx. diff --git a/cc/oze/include/txid.hh b/cc/oze/include/txid.hh index a4beb8f8..b36afd70 100644 --- a/cc/oze/include/txid.hh +++ b/cc/oze/include/txid.hh @@ -3,37 +3,38 @@ #include struct TxID { - union { - uint64_t obj_; - struct { - uint64_t tid: 24; - uint64_t thid: 8; - uint64_t epoch: 32; - }; + union { + uint64_t obj_; + struct { + uint64_t tid : 24; + uint64_t thid : 8; + uint64_t epoch : 32; }; + }; - TxID() : obj_(0) {}; - bool operator==(const TxID &right) const { return obj_ == right.obj_; } - bool operator!=(const TxID &right) const { return !operator==(right); } - bool operator<(const TxID &right) const { return obj_ < right.obj_; } - bool operator<=(const TxID &right) const { return obj_ <= right.obj_; } - bool operator>(const TxID &right) const { return obj_ > right.obj_; } - bool operator>=(const TxID &right) const { return obj_ >= right.obj_; } - friend std::ostream& operator<<(std::ostream& left, const TxID &right) { - left << right.epoch << ":" << right.thid << ":" << right.tid; - // << right.obj_ - // << "(epoch=" << right.epoch - // << ",thid=" << right.thid - // << ",id=" << right.tid << ")"; - return left; - } + TxID() : obj_(0){}; + bool operator==(const TxID& right) const { return obj_ == right.obj_; } + bool operator!=(const TxID& right) const { return !operator==(right); } + bool operator<(const TxID& right) const { return obj_ < right.obj_; } + bool operator<=(const TxID& right) const { return obj_ <= right.obj_; } + bool operator>(const TxID& right) const { return obj_ > right.obj_; } + bool operator>=(const TxID& right) const { return obj_ >= right.obj_; } + friend std::ostream& operator<<(std::ostream& left, const TxID& right) { + left << right.epoch << ":" << right.thid << ":" << right.tid; + // << right.obj_ + // << "(epoch=" << right.epoch + // << ",thid=" << right.thid + // << ",id=" << right.tid << ")"; + return left; + } }; namespace std { -template <> struct hash { - inline size_t operator()(const TxID &v) const { - hash hasher; - return hasher(v.obj_); - } +template <> +struct hash { + inline size_t operator()(const TxID& v) const { + hash hasher; + return hasher(v.obj_); + } }; -} +} // namespace std diff --git a/cc/oze/include/util.hh b/cc/oze/include/util.hh index 657c4ee3..79fb82d5 100644 --- a/cc/oze/include/util.hh +++ b/cc/oze/include/util.hh @@ -12,9 +12,9 @@ extern void displayDB(); extern void displayParameter(); -extern void leaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void leaderWork(uint64_t& epoch_timer_start, uint64_t& epoch_timer_stop); -extern void makeDB(uint64_t *initial_wts); +extern void makeDB(uint64_t* initial_wts); extern void partTableDelete([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); diff --git a/cc/oze/include/version.hh b/cc/oze/include/version.hh index abc0d125..d5f58fc4 100644 --- a/cc/oze/include/version.hh +++ b/cc/oze/include/version.hh @@ -1,7 +1,7 @@ #pragma once #include -#include // memcpy +#include // memcpy #include #include @@ -13,50 +13,50 @@ using namespace std; enum class VersionStatus : uint8_t { - invalid, - pending, - deleting, - aborted, - precommitted, - committed, - deleted, - unused, + invalid, + pending, + deleting, + aborted, + precommitted, + committed, + deleted, + unused, }; class Version { public: - TxID txid_; - atomic next_; - atomic status_; - - TupleBody body_; - - Version() { - status_.store(VersionStatus::pending, memory_order_release); - next_.store(nullptr, memory_order_release); - } - - Version(const TxID txid) { - txid_ = txid; - status_.store(VersionStatus::pending, memory_order_release); - next_.store(nullptr, memory_order_release); - } - - Version(const TxID txid, TupleBody&& body) : body_(body) { - txid_ = txid; - status_.store(VersionStatus::pending, memory_order_release); - next_.store(nullptr, memory_order_release); - } - - void set(const TxID txid, Version *next, const VersionStatus status) { - txid_ = txid; - status_.store(status, memory_order_release); - next_.store(next, memory_order_release); - } - - Version *ldAcqNext() { return next_.load(std::memory_order_acquire); } - - void strRelNext(Version *next) { // store release next = strRelNext - next_.store(next, std::memory_order_release); - } + TxID txid_; + atomic next_; + atomic status_; + + TupleBody body_; + + Version() { + status_.store(VersionStatus::pending, memory_order_release); + next_.store(nullptr, memory_order_release); + } + + Version(const TxID txid) { + txid_ = txid; + status_.store(VersionStatus::pending, memory_order_release); + next_.store(nullptr, memory_order_release); + } + + Version(const TxID txid, TupleBody&& body) : body_(body) { + txid_ = txid; + status_.store(VersionStatus::pending, memory_order_release); + next_.store(nullptr, memory_order_release); + } + + void set(const TxID txid, Version* next, const VersionStatus status) { + txid_ = txid; + status_.store(status, memory_order_release); + next_.store(next, memory_order_release); + } + + Version* ldAcqNext() { return next_.load(std::memory_order_acquire); } + + void strRelNext(Version* next) { // store release next = strRelNext + next_.store(next, std::memory_order_release); + } }; diff --git a/cc/oze/oze.cc b/cc/oze/oze.cc index 335e9346..7ce04067 100644 --- a/cc/oze/oze.cc +++ b/cc/oze/oze.cc @@ -34,11 +34,11 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Xoroshiro128Plus rnd; rnd.init(); - TxExecutor trans(thid, (Result *) &OzeResult[thid], quit); - Result &myres = std::ref(OzeResult[thid]); + TxExecutor trans(thid, (Result*) &OzeResult[thid], quit); + Result& myres = std::ref(OzeResult[thid]); uint64_t epoch_timer_start, epoch_timer_stop; FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); Backoff backoff(FLAGS_clocks_per_us); @@ -48,36 +48,35 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin - uint64_t tuples = FLAGS_tuple_num; - if (FLAGS_batch_simple_rr) { - tuples = FLAGS_tuple_num - FLAGS_batch_tuples; - } + uint64_t tuples = FLAGS_tuple_num; + if (FLAGS_batch_simple_rr) { tuples = FLAGS_tuple_num - FLAGS_batch_tuples; } storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { #if PARTITION_TABLE - makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, - FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, thid, myres); + makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, + FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, + thid, myres); #else auto r = rnd.next() % 100; - if ((FLAGS_thread_num && thid >= FLAGS_thread_num) - || (r < FLAGS_batch_ratio)) { + if ((FLAGS_thread_num && thid >= FLAGS_thread_num) || + (r < FLAGS_batch_ratio)) { trans.is_batch_ = true; - makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, - FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, - myres); - } else if (r >= FLAGS_batch_ratio - && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, + FLAGS_batch_tuples, FLAGS_batch_max_ope, + FLAGS_batch_rratio, FLAGS_rmw, myres); + } else if (r >= FLAGS_batch_ratio && + r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { trans.is_batch_ = false; makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, FLAGS_max_ope, myres); @@ -89,7 +88,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } #endif -RETRY: + RETRY: if (thid == 0) { leaderWork(epoch_timer_start, epoch_timer_stop); #if BACK_OFF @@ -126,9 +125,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } #ifdef INSERT_BATCH_DELAY_MS - if (trans.is_batch_) { - sleepMs(INSERT_BATCH_DELAY_MS); - } + if (trans.is_batch_) { sleepMs(INSERT_BATCH_DELAY_MS); } #endif /** @@ -152,8 +149,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } // Abondon ongoing long transaction when time up - if (trans.status_ == TransactionStatus::invalid) - break; + if (trans.status_ == TransactionStatus::invalid) break; /** * Write phase @@ -165,10 +161,10 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { */ if (trans.is_batch_) { storeRelease(myres.local_batch_commit_counts_, - loadAcquire(myres.local_batch_commit_counts_) + 1); + loadAcquire(myres.local_batch_commit_counts_) + 1); } else { storeRelease(myres.local_commit_counts_, - loadAcquire(myres.local_commit_counts_) + 1); + loadAcquire(myres.local_commit_counts_) + 1); } /** @@ -180,7 +176,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); @@ -201,15 +197,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { OzeResult[0].addLocalAllResult(OzeResult[i]); @@ -217,11 +211,9 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); deleteDB(); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/oze/tpcc_oze.cc b/cc/oze/tpcc_oze.cc index 85ad187c..60699b3c 100644 --- a/cc/oze/tpcc_oze.cc +++ b/cc/oze/tpcc_oze.cc @@ -36,10 +36,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &OzeResult[thid], quit); - TPCCWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &OzeResult[thid], quit); + TPCCWorkload workload; workload.prepare(trans, nullptr); #ifdef Linux @@ -47,13 +47,13 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin #if MASSTREE_USE MasstreeWrapper::thread_init(thid); @@ -63,21 +63,21 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start_ = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); gflags::SetUsageMessage("TPC-C Oze benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); - init(TPCCWorkload::getTableNum()); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + init(TPCCWorkload::getTableNum()); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -90,15 +90,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { OzeResult[0].addLocalAllResult(OzeResult[i]); @@ -106,11 +104,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; OzeResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/oze/transaction.cc b/cc/oze/transaction.cc index 34c1e9d6..e1a67624 100644 --- a/cc/oze/transaction.cc +++ b/cc/oze/transaction.cc @@ -1,6 +1,6 @@ #include -#include // memcpy +#include // memcpy #include #include @@ -14,10 +14,12 @@ #include "include/txid.hh" #include "include/version.hh" -extern bool chkClkSpan(const uint64_t start, const uint64_t stop, const uint64_t threshold); +extern bool chkClkSpan(const uint64_t start, const uint64_t stop, + const uint64_t threshold); extern void displaySLogSet(); extern void displayDB(); -extern void ozeLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void ozeLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); extern std::vector OzeResult; using namespace std; @@ -30,30 +32,31 @@ using namespace std; * @return void */ void TxExecutor::begin() { - this->status_ = TransactionStatus::inflight; + this->status_ = TransactionStatus::inflight; - atomicStoreThLocalEpoch(thid_, atomicLoadGE()); - auto e = get_min_epoch(); // align with slowest worker's epoch - if (this->txid_.epoch != e) { - this->txid_.tid = 0; - } else - this->txid_.tid++; - this->txid_.epoch = e; - this->reclamation_epoch_ = e - 1; + atomicStoreThLocalEpoch(thid_, atomicLoadGE()); + auto e = get_min_epoch(); // align with slowest worker's epoch + if (this->txid_.epoch != e) { + this->txid_.tid = 0; + } else + this->txid_.tid++; + this->txid_.epoch = e; + this->reclamation_epoch_ = e - 1; - this->cc_mode_ = get_next_cc_mode(); - ThManagementTable[thid_]->atomicStoreMode(this->cc_mode_); - this->occ_guard_required_ = some_threads_in(OCC_MODE|TO_OCC_MODE); + this->cc_mode_ = get_next_cc_mode(); + ThManagementTable[thid_]->atomicStoreMode(this->cc_mode_); + this->occ_guard_required_ = some_threads_in(OCC_MODE | TO_OCC_MODE); - // reset a flag for insert-only optimization - this->has_write_ = false; - this->has_insert_ = false; + // reset a flag for insert-only optimization + this->has_write_ = false; + this->has_insert_ = false; - // just for statistics - this->is_forwarded_ = false; + // just for statistics + this->is_forwarded_ = false; #if DEBUG_MSG - std::cout << "TxID " << txid_ << " begin by thread# " << txid_.thid << std::endl; + std::cout << "TxID " << txid_ << " begin by thread# " << txid_.thid + << std::endl; #endif } @@ -63,139 +66,135 @@ void TxExecutor::begin() { */ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS - - Status ret = Status::OK; - TxID target; - Tuple *tuple; - Version *ver = nullptr; - ReadElement* re; - WriteElement* we; + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS + + Status ret = Status::OK; + TxID target; + Tuple* tuple; + Version* ver = nullptr; + ReadElement* re; + WriteElement* we; #if DEBUG_MSG - std::cout << "TxID " << txid_ << " read " << key << " start" << std::endl; + std::cout << "TxID " << txid_ << " read " << key << " start" << std::endl; #endif - /** + /** * read-own-writes or re-read from local read set. */ - re = searchReadSet(s, key); - if (re) { - *body = &(re->ver_->body_); - goto FINISH_READ; - } - we = searchWriteSet(s, key); - if (we) { - *body = &(we->new_ver_->body_); - goto FINISH_READ; - } + re = searchReadSet(s, key); + if (re) { + *body = &(re->ver_->body_); + goto FINISH_READ; + } + we = searchWriteSet(s, key); + if (we) { + *body = &(we->new_ver_->body_); + goto FINISH_READ; + } - /** + /** * Search versions from data structure. */ - tuple = Masstrees[get_storage(s)].get_value(key); + tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS - ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS - if (tuple == nullptr) { - ret = Status::WARN_NOT_FOUND; - goto FINISH_READ; - } + ++result_->local_tree_traversal_; +#endif // if ADD_ANALYSIS + if (tuple == nullptr) { + ret = Status::WARN_NOT_FOUND; + goto FINISH_READ; + } - if (IS_OCC(cc_mode_)) { - ret = read_internal_occ(s, key, tuple, &ver); - } else { - ret = read_internal(s, key, tuple, &ver); - } - if (ret == Status::WARN_NOT_FOUND) { - goto FINISH_READ; - } - if (ret != Status::OK) { - goto ABORT_READ; - } + if (IS_OCC(cc_mode_)) { + ret = read_internal_occ(s, key, tuple, &ver); + } else { + ret = read_internal(s, key, tuple, &ver); + } + if (ret == Status::WARN_NOT_FOUND) { goto FINISH_READ; } + if (ret != Status::OK) { goto ABORT_READ; } - /** + /** * Read payload. */ - *body = &(ver->body_); + *body = &(ver->body_); FINISH_READ: #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " read " << key << " done" << std::endl; + std::cout << "TxID " << this->txid_ << " read " << key << " done" + << std::endl; #endif #if ADD_ANALYSIS - result_->local_read_latency_ += rdtscp() - start; + result_->local_read_latency_ += rdtscp() - start; #endif - return ret; + return ret; ABORT_READ: #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " read " << key << " aborted" << std::endl; + std::cout << "TxID " << this->txid_ << " read " << key << " aborted" + << std::endl; #endif #if ADD_ANALYSIS - result_->local_read_latency_ += rdtscp() - start; + result_->local_read_latency_ += rdtscp() - start; #endif - this->status_ = TransactionStatus::aborted; - return Status::WARN_NOT_FOUND; + this->status_ = TransactionStatus::aborted; + return Status::WARN_NOT_FOUND; } -Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple, Version** return_ver) { - TxID target; - Version *ver = nullptr; - Status stat = Status::OK; +Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple, + Version** return_ver) { + TxID target; + Version* ver = nullptr; + Status stat = Status::OK; - tuple->lock_.w_lock(); + tuple->lock_.w_lock(); - // sync pages that I read - if (!reconnoitering_) { - tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); - } + // sync pages that I read + if (!reconnoitering_) { + tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); + } #ifdef SYNC_GRAPH_AGGRESSIVELY - for (const auto& [tpl, id] : this->readSet_) { - tuple->graph_.emplace(id, TxNode(id)); - tuple->graph_.at(id).readBy_.emplace(this->txid_); - tuple->graph_.at(this->txid_).readSet_.emplace(tpl, id); - tuple->graph_.at(this->txid_).from_.emplace(id); - } + for (const auto& [tpl, id] : this->readSet_) { + tuple->graph_.emplace(id, TxNode(id)); + tuple->graph_.at(id).readBy_.emplace(this->txid_); + tuple->graph_.at(this->txid_).readSet_.emplace(tpl, id); + tuple->graph_.at(this->txid_).from_.emplace(id); + } #endif #ifndef NAIVE_VERSION_SELECTION - stat = get_visible_version(tuple, &ver); + stat = get_visible_version(tuple, &ver); #else - stat = get_aligned_visible_version(tuple, &ver); + stat = get_aligned_visible_version(tuple, &ver); #endif - if (stat != Status::OK) { - goto OUT; - } - if (ver == nullptr) { - ERR; - } - if (ver->status_ == VersionStatus::deleted) { - stat = Status::WARN_NOT_FOUND; - goto OUT; - } - *return_ver = ver; - target = ver->txid_; + if (stat != Status::OK) { goto OUT; } + if (ver == nullptr) { ERR; } + if (ver->status_ == VersionStatus::deleted) { + stat = Status::WARN_NOT_FOUND; + goto OUT; + } + *return_ver = ver; + target = ver->txid_; - if (!reconnoitering_) { - tuple->graph_.at(this->txid_).readSet_.emplace(tuple, target); - tuple->graph_.at(this->txid_).from_.emplace(target); - } + if (!reconnoitering_) { + tuple->graph_.at(this->txid_).readSet_.emplace(tuple, target); + tuple->graph_.at(this->txid_).from_.emplace(target); + } #if MERGE_ON_READ - merge(this->graph_, tuple->graph_); + merge(this->graph_, tuple->graph_); #endif - // TODO: read/write set management should be refactored - this->read_set_.emplace_back(s, key, tuple, ver, target, tuple->tuple_id_); - this->readSet_.emplace(tuple, target); + // TODO: read/write set management should be refactored + this->read_set_.emplace_back(s, key, tuple, ver, target, tuple->tuple_id_); + this->readSet_.emplace(tuple, target); OUT: - tuple->lock_.w_unlock(); - return stat; + tuple->lock_.w_unlock(); + return stat; } -Status TxExecutor::read_internal_occ(Storage s, std::string_view key, Tuple* tuple, Version** return_ver) { +Status TxExecutor::read_internal_occ(Storage s, std::string_view key, + Tuple* tuple, Version** return_ver) { Status stat; TupleId expected, check; @@ -203,15 +202,11 @@ Status TxExecutor::read_internal_occ(Storage s, std::string_view key, Tuple* tup expected.obj_ = loadAcquire(tuple->tuple_id_.obj_); stat = get_visible_version_occ(tuple, return_ver); check.obj_ = loadAcquire(tuple->tuple_id_.obj_); - if (stat != Status::OK) { - return stat; - } - if (expected == check) { - break; - } + if (stat != Status::OK) { return stat; } + if (expected == check) { break; } } - Version *ver = *return_ver; + Version* ver = *return_ver; this->read_set_.emplace_back(s, key, tuple, ver, ver->txid_, expected); return stat; } @@ -222,58 +217,56 @@ Status TxExecutor::read_internal_occ(Storage s, std::string_view key, Tuple* tup */ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << txid_ << " write " << key << " start" << std::endl; + std::cout << "TxID " << txid_ << " write " << key << " start" << std::endl; #endif - Status ret = Status::OK; - Tuple *tuple; + Status ret = Status::OK; + Tuple* tuple; - /** + /** * Update from local write set. * Special treat due to performance. */ - if (searchWriteSet(s, key)) goto FINISH_WRITE; + if (searchWriteSet(s, key)) goto FINISH_WRITE; - ReadElement *re; - re = searchReadSet(s, key); - if (re) { - /** + ReadElement* re; + re = searchReadSet(s, key); + if (re) { + /** * If it can find record in read set, use this for high performance. */ - tuple = re->rcdptr_; - } else { - /** + tuple = re->rcdptr_; + } else { + /** * Search record from data structure. */ - tuple = Masstrees[get_storage(s)].get_value(key); + tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS - ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS - if (tuple == nullptr) { - ret = Status::WARN_NOT_FOUND; - goto FINISH_WRITE; - } + ++result_->local_tree_traversal_; +#endif // if ADD_ANALYSIS + if (tuple == nullptr) { + ret = Status::WARN_NOT_FOUND; + goto FINISH_WRITE; } + } - if (IS_OZE(cc_mode_)) { - this->writeSet_.emplace(tuple); - } + if (IS_OZE(cc_mode_)) { this->writeSet_.emplace(tuple); } - Version *new_ver; - new_ver = newVersionGeneration(tuple, std::move(body)); - write_set_.emplace_back(s, key, tuple, new_ver, OpType::UPDATE); - has_write_ = true; + Version* new_ver; + new_ver = newVersionGeneration(tuple, std::move(body)); + write_set_.emplace_back(s, key, tuple, new_ver, OpType::UPDATE); + has_write_ = true; FINISH_WRITE: #if ADD_ANALYSIS - result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS + result_->local_write_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << txid_ << " write " << key << " done" << std::endl; + std::cout << "TxID " << txid_ << " write " << key << " done" << std::endl; #endif return ret; } @@ -284,65 +277,64 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { */ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << txid_ << " insert " << key << " start" << std::endl; + std::cout << "TxID " << txid_ << " insert " << key << " start" << std::endl; #endif - if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; + if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; - Tuple* tuple = Masstrees[get_storage(s)].get_value(key); + Tuple* tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS - ++result_->local_tree_traversal_; + ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } - tuple = new Tuple(); - tuple->init(this->txid_, std::move(body)); + tuple = new Tuple(); + tuple->init(this->txid_, std::move(body)); - if (IS_OCC(cc_mode_)) { - typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); - if (stat == Status::WARN_ALREADY_EXISTS) { - delete tuple; - return stat; - } - if (insert_info.node) { - if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); - if (it != node_map_.end()) { - if (unlikely(it->second != insert_info.old_version)) { - status_ = TransactionStatus::aborted; - return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; - } - // otherwise, bump the version - it->second = insert_info.new_version; + if (IS_OCC(cc_mode_)) { + typename MasstreeWrapper::insert_info_t insert_info; + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + if (stat == Status::WARN_ALREADY_EXISTS) { + delete tuple; + return stat; + } + if (insert_info.node) { + if (!node_map_.empty()) { + auto it = node_map_.find((void*) insert_info.node); + if (it != node_map_.end()) { + if (unlikely(it->second != insert_info.old_version)) { + status_ = TransactionStatus::aborted; + return Status::ERROR_CONCURRENT_WRITE_OR_DELETE; } + // otherwise, bump the version + it->second = insert_info.new_version; } - } else { - ERR; } } else { - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple); - if (stat == Status::WARN_ALREADY_EXISTS) { - delete tuple; - return stat; - } - this->writeSet_.emplace(tuple); + ERR; } + } else { + Status stat = Masstrees[get_storage(s)].insert_value(key, tuple); + if (stat == Status::WARN_ALREADY_EXISTS) { + delete tuple; + return stat; + } + this->writeSet_.emplace(tuple); + } - write_set_.emplace_back(s, key, tuple, tuple->ldAcqLatest(), OpType::INSERT); - has_insert_ = true; + write_set_.emplace_back(s, key, tuple, tuple->ldAcqLatest(), OpType::INSERT); + has_insert_ = true; #if ADD_ANALYSIS - result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS + result_->local_write_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << txid_ << " insert " << key << " done" << std::endl; + std::cout << "TxID " << txid_ << " insert " << key << " done" << std::endl; #endif return Status::OK; } @@ -350,7 +342,7 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { Status TxExecutor::delete_record(Storage s, std::string_view key) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS #if DEBUG_MSG std::cout << "TxID " << txid_ << " delete " << key << " start" << std::endl; @@ -359,13 +351,11 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple; - ReadElement *re; + ReadElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -373,22 +363,20 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } - if (IS_OZE(cc_mode_)) { - this->writeSet_.emplace(tuple); - } + if (IS_OZE(cc_mode_)) { this->writeSet_.emplace(tuple); } - Version *new_ver; + Version* new_ver; new_ver = newVersionGeneration(tuple); write_set_.emplace_back(s, key, tuple, new_ver, OpType::DELETE); has_write_ = true; // since delete is a sort of update #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS #if DEBUG_MSG std::cout << "TxID " << txid_ << " delete " << key << " done" << std::endl; @@ -396,17 +384,16 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); @@ -427,7 +414,7 @@ Status TxExecutor::scan(const Storage s, right_key.size(), r_exclusive, &scan_res, limit); } - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { // TODO: Tuple should have key? Accessing key through the latest ver is ugly // Must be a copy to avoid buffer overflow when changing the latest std::string key(itr->latest_.load(memory_order_acquire)->body_.get_key()); @@ -451,14 +438,14 @@ Status TxExecutor::scan(const Storage s, stat = read_internal(s, key, itr, &ver); } if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { - status_ = TransactionStatus::aborted; - return stat; + status_ = TransactionStatus::aborted; + return stat; } } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).ver_->body_)); } } @@ -467,544 +454,530 @@ Status TxExecutor::scan(const Storage s, } void TxExecutor::validation_worker([[maybe_unused]] size_t worker_id, - KeySet &target_set, size_t offset, size_t assignment, - KeySet &propagate_set, Graph &graph, TransactionStatus &result) { - // copy initial state - graph.clear(); - graph.insert(this->graph_.begin(), this->graph_.end()); + KeySet& target_set, size_t offset, + size_t assignment, KeySet& propagate_set, + Graph& graph, TransactionStatus& result) { + // copy initial state + graph.clear(); + graph.insert(this->graph_.begin(), this->graph_.end()); + // std::cout << "[" << this->txid_ << ":" << worker_id << "] " + // << "Graph size: " << graph.size() << std::endl; + + // set assignment + auto iterator = target_set.begin(); + auto end = target_set.begin(); + advance(iterator, offset); + advance(end, offset + assignment); + + uint64_t num_pages = 0; + for (; iterator != end; iterator++) { + if (iterator == target_set.end()) break; + Tuple* tuple = *iterator; + + tuple->lock_.w_lock(); + tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); + tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; + // std::cout << "[" << this->txid_ << ":" << worker_id << "] " - // << "Graph size: " << graph.size() << std::endl; - - // set assignment - auto iterator = target_set.begin(); - auto end = target_set.begin(); - advance(iterator, offset); - advance(end, offset + assignment); - - uint64_t num_pages = 0; - for (; iterator != end; iterator++) { - if (iterator == target_set.end()) - break; - Tuple* tuple = *iterator; - - tuple->lock_.w_lock(); - tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); - tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; - - // std::cout << "[" << this->txid_ << ":" << worker_id << "] " - // << "Per-page validation start for " << key << std::endl; - - // merge graph - merge(tuple->graph_, graph); - // gc(tuple->graph_, this->reclamation_epoch_); - - if (has_cycle(tuple->graph_, this->txid_)) { - clean_up_node_edges(tuple->graph_, this->txid_); - tuple->lock_.w_unlock(); - goto ABORT_VALIDATION; - } + // << "Per-page validation start for " << key << std::endl; - tuple->graph_.at(this->txid_).readSet_.insert( - this->readSet_.begin(), this->readSet_.end() - ); - tuple->graph_.at(this->txid_).writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); - - // for propagation - KeySet keys; - TxSet reachable_to; - find_reachable_to(this->txid_, tuple->graph_, reachable_to); - for (auto& txid : reachable_to) { - add_related_read_keys(&tuple->graph_.at(txid), keys); - } - for (const auto& k : keys) { - auto itr = std::find(target_set.begin(), target_set.end(), k); - if (itr == target_set.end()) - propagate_set.insert(k); - } + // merge graph + merge(tuple->graph_, graph); + // gc(tuple->graph_, this->reclamation_epoch_); + + if (has_cycle(tuple->graph_, this->txid_)) { + clean_up_node_edges(tuple->graph_, this->txid_); + tuple->lock_.w_unlock(); + goto ABORT_VALIDATION; + } - graph.clear(); - graph.insert(tuple->graph_.begin(), tuple->graph_.end()); + tuple->graph_.at(this->txid_) + .readSet_.insert(this->readSet_.begin(), this->readSet_.end()); + tuple->graph_.at(this->txid_) + .writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); - // std::cout << "[" << this->txid_ << ":" << worker_id << "] " - // << "Per-page validation done for " << key << std::endl; + // for propagation + KeySet keys; + TxSet reachable_to; + find_reachable_to(this->txid_, tuple->graph_, reachable_to); + for (auto& txid : reachable_to) { + add_related_read_keys(&tuple->graph_.at(txid), keys); + } + for (const auto& k : keys) { + auto itr = std::find(target_set.begin(), target_set.end(), k); + if (itr == target_set.end()) propagate_set.insert(k); + } - tuple->lock_.w_unlock(); + graph.clear(); + graph.insert(tuple->graph_.begin(), tuple->graph_.end()); + + // std::cout << "[" << this->txid_ << ":" << worker_id << "] " + // << "Per-page validation done for " << key << std::endl; + + tuple->lock_.w_unlock(); - num_pages++; + num_pages++; #if DEBUG_MSG - if (num_pages % 100 == 0) { - std::stringstream ss; - ss << "validation worker" - << worker_id << " " << num_pages << " done"; - } + if (num_pages % 100 == 0) { + std::stringstream ss; + ss << "validation worker" << worker_id << " " << num_pages << " done"; + } #endif - if (loadAcquire(this->quit_)) { - result = TransactionStatus::invalid; - return; - } - + if (loadAcquire(this->quit_)) { + result = TransactionStatus::invalid; + return; } - result = TransactionStatus::validating; - return; + } + result = TransactionStatus::validating; + return; ABORT_VALIDATION: - result = TransactionStatus::aborted; - return; + result = TransactionStatus::aborted; + return; } bool TxExecutor::validation() { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS - - KeySet finished_set; - KeySet propagate_set; - - this->graph_.emplace(this->txid_, TxNode(this->txid_)); - this->graph_.at(this->txid_).status_ = TransactionStatus::validating; - - // for read-only transacton (cf. read crown) - if (this->writeSet_.size() == 0) { - for (const auto& [tpl, _] : this->readSet_) { - tpl->lock_.w_lock(); - merge(tpl->graph_, this->graph_); - if (has_cycle(tpl->graph_, this->txid_)) { - if (this->status_ != TransactionStatus::invalid) - this->status_ = TransactionStatus::aborted; - tpl->lock_.w_unlock(); - goto ABORT_VALIDATION; - } else { - this->graph_.clear(); - this->graph_.insert(tpl->graph_.begin(), tpl->graph_.end()); - } - tpl->lock_.w_unlock(); - } - goto FINISH_VALIDATION; - } + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS + + KeySet finished_set; + KeySet propagate_set; - // insert-only optimization - if (!has_write_ && has_insert_) { - for (auto& we : this->write_set_) { - if (!insert_validation(we)) - goto ABORT_VALIDATION; - finished_set.insert(we.rcdptr_); + this->graph_.emplace(this->txid_, TxNode(this->txid_)); + this->graph_.at(this->txid_).status_ = TransactionStatus::validating; + + // for read-only transacton (cf. read crown) + if (this->writeSet_.size() == 0) { + for (const auto& [tpl, _] : this->readSet_) { + tpl->lock_.w_lock(); + merge(tpl->graph_, this->graph_); + if (has_cycle(tpl->graph_, this->txid_)) { + if (this->status_ != TransactionStatus::invalid) + this->status_ = TransactionStatus::aborted; + tpl->lock_.w_unlock(); + goto ABORT_VALIDATION; + } else { + this->graph_.clear(); + this->graph_.insert(tpl->graph_.begin(), tpl->graph_.end()); } - goto FINISH_VALIDATION; + tpl->lock_.w_unlock(); } + goto FINISH_VALIDATION; + } + // insert-only optimization + if (!has_write_ && has_insert_) { for (auto& we : this->write_set_) { - if (we.op_ == OpType::INSERT) { - if (!insert_validation(we)) - goto ABORT_VALIDATION; - finished_set.insert(we.rcdptr_); - } else { // OpType::UPDATE or OpType::DELETE - if (!write_validation(we, finished_set, propagate_set)) - goto ABORT_VALIDATION; - } - if (loadAcquire(this->quit_)) { - this->status_ = TransactionStatus::invalid; - goto FINISH_VALIDATION; - } + if (!insert_validation(we)) goto ABORT_VALIDATION; + finished_set.insert(we.rcdptr_); } + goto FINISH_VALIDATION; + } - for (const auto& [tpl, _] : this->readSet_) { - if (auto it = this->writeSet_.find(tpl); it == this->writeSet_.end()) - propagate_set.insert(tpl); + for (auto& we : this->write_set_) { + if (we.op_ == OpType::INSERT) { + if (!insert_validation(we)) goto ABORT_VALIDATION; + finished_set.insert(we.rcdptr_); + } else { // OpType::UPDATE or OpType::DELETE + if (!write_validation(we, finished_set, propagate_set)) + goto ABORT_VALIDATION; + } + if (loadAcquire(this->quit_)) { + this->status_ = TransactionStatus::invalid; + goto FINISH_VALIDATION; } + } - if (FLAGS_validation_th_num == 1 || - propagate_set.size() <= FLAGS_validation_threshold) { - bool ret = read_validation(propagate_set, finished_set); - if (ret && propagate_set.empty()) { - goto FINISH_VALIDATION; - } else if (!ret) { - goto ABORT_VALIDATION; - } + for (const auto& [tpl, _] : this->readSet_) { + if (auto it = this->writeSet_.find(tpl); it == this->writeSet_.end()) + propagate_set.insert(tpl); + } + + if (FLAGS_validation_th_num == 1 || + propagate_set.size() <= FLAGS_validation_threshold) { + bool ret = read_validation(propagate_set, finished_set); + if (ret && propagate_set.empty()) { + goto FINISH_VALIDATION; + } else if (!ret) { + goto ABORT_VALIDATION; } + } - while (!propagate_set.empty()) { - uint64_t workers = 1; - uint64_t total_task = propagate_set.size(); - uint64_t assignment = total_task; - if (FLAGS_validation_th_num > 1 && - total_task > FLAGS_validation_threshold) { - workers = FLAGS_validation_th_num; - assignment = (size_t)ceil((double)total_task/(double)workers); - } - std::vector thv; - std::vector propagate_subset(workers); - std::vector graph(workers); - TransactionStatus result[workers]; - - for (size_t i = 0; i < workers; ++i) { - propagate_subset[i] = KeySet(); - graph[i] = Graph(); - thv.emplace_back(&TxExecutor::validation_worker, this, i, - std::ref(propagate_set), assignment*i, assignment, - std::ref(propagate_subset[i]), std::ref(graph[i]), - std::ref(result[i])); - } - for (auto &th : thv) th.join(); - - for (size_t i = 0; i < workers; ++i) { - if (result[i] == TransactionStatus::validating) { - // std::cout << "Merging results from a worker: " << i << std::endl; - merge(this->graph_, graph[i]); - } else if (result[i] == TransactionStatus::aborted) { - // std::cout << "Validation failed in a worker: " << i << std::endl; - goto ABORT_VALIDATION; - } else if (result[i] == TransactionStatus::invalid) { - // cancel due to timeout - this->status_ = TransactionStatus::invalid; - goto FINISH_VALIDATION; - } else { - ERR; - } - } + while (!propagate_set.empty()) { + uint64_t workers = 1; + uint64_t total_task = propagate_set.size(); + uint64_t assignment = total_task; + if (FLAGS_validation_th_num > 1 && + total_task > FLAGS_validation_threshold) { + workers = FLAGS_validation_th_num; + assignment = (size_t) ceil((double) total_task / (double) workers); + } + std::vector thv; + std::vector propagate_subset(workers); + std::vector graph(workers); + TransactionStatus result[workers]; + + for (size_t i = 0; i < workers; ++i) { + propagate_subset[i] = KeySet(); + graph[i] = Graph(); + thv.emplace_back(&TxExecutor::validation_worker, this, i, + std::ref(propagate_set), assignment * i, assignment, + std::ref(propagate_subset[i]), std::ref(graph[i]), + std::ref(result[i])); + } + for (auto& th : thv) th.join(); + + for (size_t i = 0; i < workers; ++i) { + if (result[i] == TransactionStatus::validating) { + // std::cout << "Merging results from a worker: " << i << std::endl; + merge(this->graph_, graph[i]); + } else if (result[i] == TransactionStatus::aborted) { + // std::cout << "Validation failed in a worker: " << i << std::endl; + goto ABORT_VALIDATION; + } else if (result[i] == TransactionStatus::invalid) { + // cancel due to timeout + this->status_ = TransactionStatus::invalid; + goto FINISH_VALIDATION; + } else { + ERR; + } + } - if (has_cycle(this->graph_, this->txid_)) { - // TODO: should we clean up edges on each tuple? - // cf. clean_up_node_edges(tuple->graph_, this->txid_); - goto ABORT_VALIDATION; - } + if (has_cycle(this->graph_, this->txid_)) { + // TODO: should we clean up edges on each tuple? + // cf. clean_up_node_edges(tuple->graph_, this->txid_); + goto ABORT_VALIDATION; + } - finished_set.insert(propagate_set.begin(), propagate_set.end()); - propagate_set.clear(); + finished_set.insert(propagate_set.begin(), propagate_set.end()); + propagate_set.clear(); - for (size_t i = 0; i < workers; ++i) { - for (auto& k : propagate_subset[i]) { - if (auto it = finished_set.find(k); it == finished_set.end()) { - propagate_set.insert(k); - } - } + for (size_t i = 0; i < workers; ++i) { + for (auto& k : propagate_subset[i]) { + if (auto it = finished_set.find(k); it == finished_set.end()) { + propagate_set.insert(k); } + } + } - if (loadAcquire(this->quit_)) { - this->status_ = TransactionStatus::invalid; - goto FINISH_VALIDATION; - } + if (loadAcquire(this->quit_)) { + this->status_ = TransactionStatus::invalid; + goto FINISH_VALIDATION; } + } FINISH_VALIDATION: #if ADD_ANALYSIS - result_->local_vali_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return true; + result_->local_vali_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return true; ABORT_VALIDATION: #if ADD_ANALYSIS - result_->local_vali_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return false; + result_->local_vali_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return false; } -bool TxExecutor::write_validation(WriteElement element, KeySet& finished_set, KeySet& propagate_set) { +bool TxExecutor::write_validation(WriteElement element, + KeySet& finished_set, KeySet& propagate_set) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << " Per-page write validation start for " << tuple << std::endl; + std::cout << " Per-page write validation start for " << tuple << std::endl; #endif - Status stat; - TxSet decided, reachable_to; - KeySet followers_read_keys; - Tuple* tuple = element.rcdptr_; - OpType op = element.op_; + Status stat; + TxSet decided, reachable_to; + KeySet followers_read_keys; + Tuple* tuple = element.rcdptr_; + OpType op = element.op_; - tuple->lock_.w_lock(); + tuple->lock_.w_lock(); - tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); - tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; + tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); + tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; - // merge graph - merge(tuple->graph_, this->graph_); - gc(tuple->graph_, this->reclamation_epoch_); + // merge graph + merge(tuple->graph_, this->graph_); + gc(tuple->graph_, this->reclamation_epoch_); #if DEBUG_MSG - std::cout << " Merged done, now find readers" << std::endl; + std::cout << " Merged done, now find readers" << std::endl; #endif - // add edges and check my RF - // 1. find readers (who reads write-target pages?) - // 2. add this txid to readers' writtenBy list - // 3. check my RF - TxSet readers; - TxSet followers; - find_readers(tuple->graph_, tuple, readers); - for (const auto& r : readers) { + // add edges and check my RF + // 1. find readers (who reads write-target pages?) + // 2. add this txid to readers' writtenBy list + // 3. check my RF + TxSet readers; + TxSet followers; + find_readers(tuple->graph_, tuple, readers); + for (const auto& r : readers) { #if DEBUG_MSG - std::cout << " Reader: " << r << std::endl; + std::cout << " Reader: " << r << std::endl; #endif - if (this->txid_.epoch < r.epoch - 1) { - goto ABORT_VALIDATION; - } - tuple->graph_.at(r).writtenBy_.insert(this->txid_); - tuple->graph_.at(this->txid_).from_.insert(r); - } + if (this->txid_.epoch < r.epoch - 1) { goto ABORT_VALIDATION; } + tuple->graph_.at(r).writtenBy_.insert(this->txid_); + tuple->graph_.at(this->txid_).from_.insert(r); + } - if (has_cycle(tuple->graph_, this->txid_)) { + if (has_cycle(tuple->graph_, this->txid_)) { #if DEBUG_MSG - std::cout << " Cycle: " << this->txid_ << " Tuple: " << tuple << std::endl; - std::cout << " Try order forwarding: " << tuple << std::endl; + std::cout << " Cycle: " << this->txid_ << " Tuple: " << tuple << std::endl; + std::cout << " Try order forwarding: " << tuple << std::endl; #endif - if (op == OpType::DELETE || !FLAGS_forwarding) { - goto ABORT_VALIDATION; - } - find_followers(tuple->graph_, tuple, readers, followers); - for (const auto& r : readers) { - if (auto it = decided.find(r); it == decided.end()) { - tuple->graph_.at(r).writtenBy_.erase(this->txid_); - tuple->graph_.at(this->txid_).from_.erase(r); - } - } - for (const auto& f : followers) { - if (f.epoch < this->txid_.epoch - 1) { - // Do not forward to the position before the tx in the previous epoch - goto ABORT_VALIDATION; - } - tuple->graph_.at(this->txid_).writtenBy_.insert(f); - tuple->graph_.at(f).from_.insert(this->txid_); - } - if (has_cycle(tuple->graph_, this->txid_)) { - goto ABORT_VALIDATION; - } - } else { - for (const auto& r : readers) { - decided.insert(r); - } + if (op == OpType::DELETE || !FLAGS_forwarding) { goto ABORT_VALIDATION; } + find_followers(tuple->graph_, tuple, readers, followers); + for (const auto& r : readers) { + if (auto it = decided.find(r); it == decided.end()) { + tuple->graph_.at(r).writtenBy_.erase(this->txid_); + tuple->graph_.at(this->txid_).from_.erase(r); + } } - - tuple->graph_.at(this->txid_).readSet_.insert( - this->readSet_.begin(), this->readSet_.end() - ); - tuple->graph_.at(this->txid_).writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); - - // insert write version to the appropriate position in the linked list - stat = insert_version(element, followers); - if (stat != Status::OK) { + for (const auto& f : followers) { + if (f.epoch < this->txid_.epoch - 1) { + // Do not forward to the position before the tx in the previous epoch goto ABORT_VALIDATION; + } + tuple->graph_.at(this->txid_).writtenBy_.insert(f); + tuple->graph_.at(f).from_.insert(this->txid_); } + if (has_cycle(tuple->graph_, this->txid_)) { goto ABORT_VALIDATION; } + } else { + for (const auto& r : readers) { decided.insert(r); } + } + + tuple->graph_.at(this->txid_) + .readSet_.insert(this->readSet_.begin(), this->readSet_.end()); + tuple->graph_.at(this->txid_) + .writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); + + // insert write version to the appropriate position in the linked list + stat = insert_version(element, followers); + if (stat != Status::OK) { goto ABORT_VALIDATION; } #if DEBUG_MSG - std::cout << " Per-page write validation done for " << tuple << std::endl; - print_record(tuple); - print_transaction(); - // generate_dot_graph("validation"+std::to_string(key), tuple->graph_); - std::cout << " Find propagation targets" << std::endl; + std::cout << " Per-page write validation done for " << tuple << std::endl; + print_record(tuple); + print_transaction(); + // generate_dot_graph("validation"+std::to_string(key), tuple->graph_); + std::cout << " Find propagation targets" << std::endl; #endif - // for propagation - find_reachable_to(this->txid_, tuple->graph_, reachable_to); - for (auto& txid : reachable_to) { - add_related_read_keys(&tuple->graph_.at(txid), followers_read_keys); - } - for ([[maybe_unused]] const auto& k : followers_read_keys) { - push_candidate_keys(propagate_set, finished_set, followers_read_keys); - } + // for propagation + find_reachable_to(this->txid_, tuple->graph_, reachable_to); + for (auto& txid : reachable_to) { + add_related_read_keys(&tuple->graph_.at(txid), followers_read_keys); + } + for ([[maybe_unused]] const auto& k : followers_read_keys) { + push_candidate_keys(propagate_set, finished_set, followers_read_keys); + } - this->graph_.clear(); - this->graph_.insert(tuple->graph_.begin(), tuple->graph_.end()); + this->graph_.clear(); + this->graph_.insert(tuple->graph_.begin(), tuple->graph_.end()); - tuple->lock_.w_unlock(); - finished_set.insert(tuple); - if (loadAcquire(this->quit_)) { - this->status_ = TransactionStatus::invalid; - return true; - } + tuple->lock_.w_unlock(); + finished_set.insert(tuple); + if (loadAcquire(this->quit_)) { + this->status_ = TransactionStatus::invalid; + return true; + } #if ADD_ANALYSIS - result_->local_write_validation_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return true; + result_->local_write_validation_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return true; ABORT_VALIDATION: - clean_up_node_edges(tuple->graph_, this->txid_); - tuple->lock_.w_unlock(); + clean_up_node_edges(tuple->graph_, this->txid_); + tuple->lock_.w_unlock(); #if ADD_ANALYSIS - result_->local_write_validation_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return false; + result_->local_write_validation_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return false; } bool TxExecutor::insert_validation(WriteElement element) { - Tuple* tuple = element.rcdptr_; - Storage s = element.storage_; - string_view key = element.key_; - ScanEntry *prev, *entry; - int history_offset = SCAN_HISTORY_INDEX(s, this->txid_.epoch); + Tuple* tuple = element.rcdptr_; + Storage s = element.storage_; + string_view key = element.key_; + ScanEntry *prev, *entry; + int history_offset = SCAN_HISTORY_INDEX(s, this->txid_.epoch); #if DEBUG_MSG - std::cout << " Per-page insert validation start for " << tuple << std::endl; + std::cout << " Per-page insert validation start for " << tuple << std::endl; #endif - tuple->lock_.w_lock(); - - // check scan index - uint64_t range = ScanRange[history_offset].load(std::memory_order_acquire); - uint32_t min = range >> 32; - uint32_t max = range & 0xffffffff; - uint32_t prefix = *reinterpret_cast(key.data()); - if (prefix < min || max < prefix) { - goto OUT; - } - - // check scan history - prev = nullptr; - entry = ScanHistory[history_offset].load(std::memory_order_acquire); - while (entry && entry->txid_.epoch == this->txid_.epoch) { + tuple->lock_.w_lock(); + + // check scan index + uint64_t range = ScanRange[history_offset].load(std::memory_order_acquire); + uint32_t min = range >> 32; + uint32_t max = range & 0xffffffff; + uint32_t prefix = *reinterpret_cast(key.data()); + if (prefix < min || max < prefix) { goto OUT; } + + // check scan history + prev = nullptr; + entry = ScanHistory[history_offset].load(std::memory_order_acquire); + while (entry && entry->txid_.epoch == this->txid_.epoch) { #if DEBUG_MSG - std::cout << " Scan entry: " << tuple << std::endl; + std::cout << " Scan entry: " << tuple << std::endl; #endif - if (entry->txid_ != txid_ && entry->contains(element.key_)) { - // add edge; scanner to inserter - if (auto it = this->graph_.find(entry->txid_); it == this->graph_.end()) - this->graph_.emplace(entry->txid_, TxNode(entry->txid_)); - this->graph_.at(entry->txid_).writtenBy_.insert(this->txid_); - this->graph_.at(this->txid_).from_.insert(entry->txid_); - // check cycle - if (has_cycle(this->graph_, this->txid_)) { - tuple->lock_.w_unlock(); - return false; - } - } - prev = entry; - entry = entry->ldAcqNext(); + if (entry->txid_ != txid_ && entry->contains(element.key_)) { + // add edge; scanner to inserter + if (auto it = this->graph_.find(entry->txid_); it == this->graph_.end()) + this->graph_.emplace(entry->txid_, TxNode(entry->txid_)); + this->graph_.at(entry->txid_).writtenBy_.insert(this->txid_); + this->graph_.at(this->txid_).from_.insert(entry->txid_); + // check cycle + if (has_cycle(this->graph_, this->txid_)) { + tuple->lock_.w_unlock(); + return false; + } } + prev = entry; + entry = entry->ldAcqNext(); + } - if (entry && entry->txid_.epoch <= reclamation_epoch_) { - if (prev == nullptr) { - if (ScanHistory[history_offset].compare_exchange_strong(entry, nullptr, - memory_order_acq_rel, memory_order_acquire)) { - delete entry; - } - } else { - if (prev->next_.compare_exchange_strong(entry, nullptr, - memory_order_acq_rel, memory_order_acquire)) { - while (entry) { - prev = entry; - entry = entry->ldAcqNext(); - delete prev; - } - } + if (entry && entry->txid_.epoch <= reclamation_epoch_) { + if (prev == nullptr) { + if (ScanHistory[history_offset].compare_exchange_strong( + entry, nullptr, memory_order_acq_rel, memory_order_acquire)) { + delete entry; + } + } else { + if (prev->next_.compare_exchange_strong( + entry, nullptr, memory_order_acq_rel, memory_order_acquire)) { + while (entry) { + prev = entry; + entry = entry->ldAcqNext(); + delete prev; } + } } + } OUT: - // sync graph to log my reads-from at least - tuple->graph_.insert(this->graph_.begin(), this->graph_.end()); + // sync graph to log my reads-from at least + tuple->graph_.insert(this->graph_.begin(), this->graph_.end()); #if DEBUG_MSG - print_record(tuple); + print_record(tuple); #endif - tuple->lock_.w_unlock(); + tuple->lock_.w_unlock(); #if DEBUG_MSG - std::cout << " Per-page insert validation done for " << tuple << std::endl; + std::cout << " Per-page insert validation done for " << tuple << std::endl; #endif - return true; + return true; } bool TxExecutor::read_validation(KeySet& target_set, KeySet& finished_set) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS + uint64_t start = rdtscp(); +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " read page validation start" << std::endl; + std::cout << "TxID " << this->txid_ << " read page validation start" + << std::endl; #endif - while (!target_set.empty()) { - auto iterator = target_set.cbegin(); - Tuple* tuple = *iterator; - std::string key(tuple->latest_.load(memory_order_acquire)->body_.get_key()); + while (!target_set.empty()) { + auto iterator = target_set.cbegin(); + Tuple* tuple = *iterator; + std::string key(tuple->latest_.load(memory_order_acquire)->body_.get_key()); - tuple->lock_.w_lock(); + tuple->lock_.w_lock(); #if DEBUG_MSG - std::cout << " Per-page validation start for " << key << std::endl; + std::cout << " Per-page validation start for " << key << std::endl; #endif - tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); - tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; + tuple->graph_.emplace(this->txid_, TxNode(this->txid_)); + tuple->graph_.at(this->txid_).status_ = TransactionStatus::validating; - // merge graph - merge(tuple->graph_, this->graph_); - gc(tuple->graph_, this->reclamation_epoch_); + // merge graph + merge(tuple->graph_, this->graph_); + gc(tuple->graph_, this->reclamation_epoch_); #if DEBUG_MSG - std::cout << " Merged done, check cycle" << std::endl; + std::cout << " Merged done, check cycle" << std::endl; #endif - if (has_cycle(tuple->graph_, this->txid_)) { + if (has_cycle(tuple->graph_, this->txid_)) { #if DEBUG_MSG - std::cout << " Cycle: " << this->txid_ << " Key: " << key << std::endl; + std::cout << " Cycle: " << this->txid_ << " Key: " << key << std::endl; #endif - clean_up_node_edges(tuple->graph_, this->txid_); - tuple->lock_.w_unlock(); - goto ABORT_VALIDATION; - } + clean_up_node_edges(tuple->graph_, this->txid_); + tuple->lock_.w_unlock(); + goto ABORT_VALIDATION; + } - tuple->graph_.at(this->txid_).readSet_.insert( - this->readSet_.begin(), this->readSet_.end() - ); - tuple->graph_.at(this->txid_).writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); + tuple->graph_.at(this->txid_) + .readSet_.insert(this->readSet_.begin(), this->readSet_.end()); + tuple->graph_.at(this->txid_) + .writeSet_.insert(this->writeSet_.begin(), this->writeSet_.end()); #if DEBUG_MSG - std::cout << " Per-page validation done for " << key << std::endl; - print_record(tuple); - print_transaction(); - // generate_dot_graph("validation"+std::to_string(key), tuple->graph_); - std::cout << " Find propagation targets" << std::endl; + std::cout << " Per-page validation done for " << key << std::endl; + print_record(tuple); + print_transaction(); + // generate_dot_graph("validation"+std::to_string(key), tuple->graph_); + std::cout << " Find propagation targets" << std::endl; #endif - // for propagation - KeySet keys; - TxSet reachable_to; - find_reachable_to(this->txid_, tuple->graph_, reachable_to); - for (auto& txid : reachable_to) { - add_related_read_keys(&tuple->graph_.at(txid), keys); - } - for ([[maybe_unused]] const auto& k : keys) { - push_candidate_keys(target_set, finished_set, keys); - } + // for propagation + KeySet keys; + TxSet reachable_to; + find_reachable_to(this->txid_, tuple->graph_, reachable_to); + for (auto& txid : reachable_to) { + add_related_read_keys(&tuple->graph_.at(txid), keys); + } + for ([[maybe_unused]] const auto& k : keys) { + push_candidate_keys(target_set, finished_set, keys); + } - this->graph_.clear(); - this->graph_.insert(tuple->graph_.begin(), tuple->graph_.end()); + this->graph_.clear(); + this->graph_.insert(tuple->graph_.begin(), tuple->graph_.end()); - tuple->lock_.w_unlock(); - finished_set.insert(tuple); - target_set.erase(iterator); + tuple->lock_.w_unlock(); + finished_set.insert(tuple); + target_set.erase(iterator); - if (FLAGS_validation_th_num != 1 && - target_set.size() > FLAGS_validation_threshold) { - // oops, many propagate found, so fall back parallel validation + if (FLAGS_validation_th_num != 1 && + target_set.size() > FLAGS_validation_threshold) { + // oops, many propagate found, so fall back parallel validation #if DEBUG_MSG - dump(thid_, "fall back parallel validation"); + dump(thid_, "fall back parallel validation"); #endif - return true; - } + return true; + } - if (loadAcquire(this->quit_)) { - this->status_ = TransactionStatus::invalid; - return true; - } + if (loadAcquire(this->quit_)) { + this->status_ = TransactionStatus::invalid; + return true; } + } #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " read page validation done" << std::endl; + std::cout << "TxID " << this->txid_ << " read page validation done" + << std::endl; #endif - // generate_dot_graph("test" + std::to_string(this->txid_.thid), this->graph_); + // generate_dot_graph("test" + std::to_string(this->txid_.thid), this->graph_); #if ADD_ANALYSIS - result_->local_read_validation_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return true; + result_->local_read_validation_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return true; ABORT_VALIDATION: #if DEBUG_MSG - std::cout << "TxID: " << this->txid_ << " aborted" << std::endl; + std::cout << "TxID: " << this->txid_ << " aborted" << std::endl; #endif #if ADD_ANALYSIS - result_->local_read_validation_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS - return false; + result_->local_read_validation_latency_ += rdtscp() - start; +#endif // if ADD_ANALYSIS + return false; } /** @@ -1015,34 +988,34 @@ bool TxExecutor::read_validation(KeySet& target_set, KeySet& finished_set) { void TxExecutor::abort() { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " abort process begin" << std::endl; + std::cout << "TxID " << this->txid_ << " abort process begin" << std::endl; #endif - writeSetClean(); - read_set_.clear(); - node_map_.clear(); + writeSetClean(); + read_set_.clear(); + node_map_.clear(); - graph_.clear(); - readSet_.clear(); - writeSet_.clear(); + graph_.clear(); + readSet_.clear(); + writeSet_.clear(); #ifdef GC_ABORTED_TX - AbortTx* tx = new AbortTx(this->txid_); - AbortTx* expected = AbortTxList.load(std::memory_order_acquire); - tx->strRelNext(expected); - while (!AbortTxList.compare_exchange_strong(expected, tx, - memory_order_acq_rel, memory_order_acquire)) {} + AbortTx* tx = new AbortTx(this->txid_); + AbortTx* expected = AbortTxList.load(std::memory_order_acquire); + tx->strRelNext(expected); + while (!AbortTxList.compare_exchange_strong( + expected, tx, memory_order_acq_rel, memory_order_acquire)) {} #endif - mainte(); + mainte(); #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " abort process done" << std::endl; + std::cout << "TxID " << this->txid_ << " abort process done" << std::endl; #endif #if BACK_OFF - backoff(); + backoff(); #endif #if ADD_ANALYSIS result_->local_abort_latency_ += rdtscp() - start; @@ -1054,25 +1027,25 @@ bool TxExecutor::validation_occ() { sort(write_set_.begin(), write_set_.end()); lock_write_set(); - if (this->status_ == TransactionStatus::aborted) { - return false; - } + if (this->status_ == TransactionStatus::aborted) { return false; } - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); atomicStoreThLocalEpoch(thid_, atomicLoadGE()); - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { TupleId check; - check.obj_ = __atomic_load_n(&((*itr).rcdptr_->tuple_id_.obj_), __ATOMIC_ACQUIRE); - if ((*itr).tuple_id_.epoch != check.epoch || (*itr).tuple_id_.tid != check.tid) { + check.obj_ = + __atomic_load_n(&((*itr).rcdptr_->tuple_id_.obj_), __ATOMIC_ACQUIRE); + if ((*itr).tuple_id_.epoch != check.epoch || + (*itr).tuple_id_.tid != check.tid) { this->status_ = TransactionStatus::aborted; unlock_write_set(); return false; } - if ((*itr).rcdptr_->lock_.counter.load(std::memory_order_acquire) == -1 - && searchWriteSet((*itr).storage_, (*itr).key_) == nullptr) { + if ((*itr).rcdptr_->lock_.counter.load(std::memory_order_acquire) == -1 && + searchWriteSet((*itr).storage_, (*itr).key_) == nullptr) { this->status_ = TransactionStatus::aborted; unlock_write_set(); return false; @@ -1083,7 +1056,7 @@ bool TxExecutor::validation_occ() { // validate the node set for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { this->status_ = TransactionStatus::aborted; unlock_write_set(); @@ -1121,106 +1094,88 @@ void TxExecutor::mainte() { void TxExecutor::writePhase() { #if ADD_ANALYSIS - uint64_t start = rdtscp(); + uint64_t start = rdtscp(); #endif - if (IS_OCC(cc_mode_) || occ_guard_required_) { - most_recent_tid_ = decide_tuple_id(); - for (auto we : write_set_) { - if (we.op_ != OpType::INSERT) { - insert_version(we); - } - commit_version(we); - storeRelease(we.rcdptr_->tuple_id_.obj_, most_recent_tid_.obj_); - if (we.op_ != OpType::INSERT) { - we.rcdptr_->lock_.w_unlock(); - } - } - } else { - for (auto we : write_set_) { - commit_version(we); - } + if (IS_OCC(cc_mode_) || occ_guard_required_) { + most_recent_tid_ = decide_tuple_id(); + for (auto we : write_set_) { + if (we.op_ != OpType::INSERT) { insert_version(we); } + commit_version(we); + storeRelease(we.rcdptr_->tuple_id_.obj_, most_recent_tid_.obj_); + if (we.op_ != OpType::INSERT) { we.rcdptr_->lock_.w_unlock(); } } + } else { + for (auto we : write_set_) { commit_version(we); } + } - read_set_.clear(); - write_set_.clear(); - node_map_.clear(); - readSet_.clear(); - writeSet_.clear(); - graph_.clear(); - following_.clear(); - followers_.clear(); + read_set_.clear(); + write_set_.clear(); + node_map_.clear(); + readSet_.clear(); + writeSet_.clear(); + graph_.clear(); + following_.clear(); + followers_.clear(); #if DEBUG_MSG - std::cout << "TxID " << this->txid_ << " done" << std::endl; + std::cout << "TxID " << this->txid_ << " done" << std::endl; #endif #if ADD_ANALYSIS - result_->local_commit_latency_ += rdtscp() - start; + result_->local_commit_latency_ += rdtscp() - start; #endif } bool TxExecutor::commit() { if (IS_OCC(cc_mode_)) { - if (cc_mode_ & TO_OZE_MODE) { - ERR; - } - if (!validation_occ()) { - return false; - } + if (cc_mode_ & TO_OZE_MODE) { ERR; } + if (!validation_occ()) { return false; } writePhase(); mainte(); return true; } - if (!validation()) { - return false; - } + if (!validation()) { return false; } // Abandon ongoing long transaction when time up - if (status_ == TransactionStatus::invalid) - return false; + if (status_ == TransactionStatus::invalid) return false; - occ_guard_required_ |= some_threads_in(OCC_MODE|TO_OCC_MODE); - if (occ_guard_required_ && !validation_occ()) { - return false; - } + occ_guard_required_ |= some_threads_in(OCC_MODE | TO_OCC_MODE); + if (occ_guard_required_ && !validation_occ()) { return false; } writePhase(); mainte(); return true; } void TxExecutor::reconnoiter_begin() { - if (status_ != TransactionStatus::inflight) { - begin(); - } - reconnoitering_ = true; + if (status_ != TransactionStatus::inflight) { begin(); } + reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { - node_map_.clear(); - read_set_.clear(); - readSet_.clear(); - graph_.clear(); - if (write_set_.size() != 0 || writeSet_.size() != 0) { - dump(thid_, "WARN: Write happened in reconnoitering mode."); - } - reconnoitering_ = false; - begin(); + node_map_.clear(); + read_set_.clear(); + readSet_.clear(); + graph_.clear(); + if (write_set_.size() != 0 || writeSet_.size() != 0) { + dump(thid_, "WARN: Write happened in reconnoitering mode."); + } + reconnoitering_ = false; + begin(); } -bool TxExecutor::isLeader() { - return this->thid_ == 1; -} +bool TxExecutor::isLeader() { return this->thid_ == 1; } void TxExecutor::leaderWork() { - ozeLeaderWork(epoch_timer_start_, epoch_timer_stop_); + ozeLeaderWork(epoch_timer_start_, epoch_timer_stop_); #if BACK_OFF - leaderBackoffWork(backoff_, OzeResult); + leaderBackoffWork(backoff_, OzeResult); #endif } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/oze/util.cc b/cc/oze/util.cc index ef4fb2c8..f8857251 100644 --- a/cc/oze/util.cc +++ b/cc/oze/util.cc @@ -24,19 +24,17 @@ void init(int32_t table_num) { // Prepare two (even/odd) scan histories for each table // offset = 2 * storage_index + epoch % 2 - if (posix_memalign((void **) &ScanHistory, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ScanHistory, CACHE_LINE_SIZE, table_num * 2 * sizeof(atomic)) != 0) ERR; - if (posix_memalign((void **) &ScanRange, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ScanRange, CACHE_LINE_SIZE, table_num * 2 * sizeof(atomic)) != 0) ERR; // init try { - ThManagementTable = new ThreadManagementEntry *[TotalThreadNum]; - } catch (const bad_alloc&) { - ERR; - } + ThManagementTable = new ThreadManagementEntry*[TotalThreadNum]; + } catch (const bad_alloc&) { ERR; } for (unsigned int i = 0; i < TotalThreadNum; ++i) { ThManagementTable[i] = new ThreadManagementEntry(1, FLAGS_cc_mode); } @@ -54,7 +52,8 @@ void displayParameter() { cout << "#FLAGS_forwarding:\t" << FLAGS_forwarding << endl; if (FLAGS_validation_th_num > 1) { cout << "#FLAGS_validation_th_num:\t" << FLAGS_validation_th_num << endl; - cout << "#FLAGS_validation_threshold:\t" << FLAGS_validation_threshold << endl; + cout << "#FLAGS_validation_threshold:\t" << FLAGS_validation_threshold + << endl; } } @@ -62,14 +61,13 @@ bool chkEpochLoaded() { uint64_t nowepo = atomicLoadGE(); // check if all worker threads read the latest epoch for (unsigned int i = 0; i < TotalThreadNum; ++i) { - if (ThManagementTable[i]->atomicLoadEpoch() != nowepo) - return false; + if (ThManagementTable[i]->atomicLoadEpoch() != nowepo) return false; } return true; } -void ozeLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop) { +void ozeLeaderWork(uint64_t& epoch_timer_start, uint64_t& epoch_timer_stop) { epoch_timer_stop = rdtscp(); if (chkClkSpan(epoch_timer_start, epoch_timer_stop, FLAGS_epoch_time * FLAGS_clocks_per_us * 1000) && diff --git a/cc/oze/ycsb_oze.cc b/cc/oze/ycsb_oze.cc index 8c555c85..3655dcc6 100644 --- a/cc/oze/ycsb_oze.cc +++ b/cc/oze/ycsb_oze.cc @@ -36,35 +36,35 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { YcsbWorkload workload; Backoff backoff(FLAGS_clocks_per_us); - TxExecutor trans(thid, backoff, (Result *) &OzeResult[thid], quit); + TxExecutor trans(thid, backoff, (Result*) &OzeResult[thid], quit); #ifdef Linux setThreadAffinity(thid); // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %d\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux #ifdef Darwin int nowcpu; GETCPU(nowcpu); // printf("Thread %d on CPU %d\n", *myid, nowcpu); -#endif // Darwin +#endif // Darwin storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start_ = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { google::InitGoogleLogging(argv[0]); google::InstallFailureSignalHandler(); @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) try { gflags::ParseCommandLineFlags(&argc, &argv, true); init(YcsbWorkload::getTableNum()); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -85,24 +85,21 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { OzeResult[0].addLocalAllResult(OzeResult[i]); } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + OzeResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/si/bomb_si.cc b/cc/si/bomb_si.cc index 35152291..02b98660 100644 --- a/cc/si/bomb_si.cc +++ b/cc/si/bomb_si.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &SIResult[thid], quit); - BombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &SIResult[thid], quit); + BombWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB SI benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -75,25 +75,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -102,11 +100,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SIResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/si/garbage_collection.cc b/cc/si/garbage_collection.cc index 0052eb94..4b3deae4 100644 --- a/cc/si/garbage_collection.cc +++ b/cc/si/garbage_collection.cc @@ -14,7 +14,7 @@ using std::cout, std::endl; // start, for leader thread. bool GarbageCollection::chkSecondRange() { - TransactionTable *tmt; + TransactionTable* tmt; smin_ = UINT32_MAX; smax_ = 0; @@ -35,7 +35,7 @@ bool GarbageCollection::chkSecondRange() { } void GarbageCollection::decideFirstRange() { - TransactionTable *tmt; + TransactionTable* tmt; fmin_ = fmax_ = 0; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -50,7 +50,7 @@ void GarbageCollection::decideFirstRange() { // end, for leader thread. // for worker thread -void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { +void GarbageCollection::gcVersion([[maybe_unused]] Result* eres_) { uint32_t threshold = getGcThreshold(); // my customized Rapid garbage collection inspired from Cicada (sigmod 2017). @@ -60,7 +60,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { // (a) acquiring the garbage collection lock succeeds uint8_t zero = 0; uint8_t one = 1; - Tuple *tuple = gcq_for_version_.front().rcdptr_; + Tuple* tuple = gcq_for_version_.front().rcdptr_; if (!tuple->gc_lock_.compare_exchange_strong( zero, one, std::memory_order_acq_rel, std::memory_order_acquire)) { // fail acquiring the lock @@ -79,7 +79,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { } // this pointer may be dangling. - Version *delTarget = gcq_for_version_.front().ver_->prev_; + Version* delTarget = gcq_for_version_.front().ver_->prev_; if (delTarget == nullptr) { tuple->gc_lock_.store(0, std::memory_order_release); gcq_for_version_.pop_front(); @@ -94,7 +94,7 @@ void GarbageCollection::gcVersion([[maybe_unused]] Result *eres_) { while (delTarget != nullptr) { // next pointer escape - Version *tmp = delTarget->prev_; + Version* tmp = delTarget->prev_; reuse_version_from_gc_.emplace_back(delTarget); delTarget = tmp; #if ADD_ANALYSIS @@ -143,12 +143,12 @@ void GarbageCollection::gcRecord() { return; } -void GarbageCollection::gcTMTelement([[maybe_unused]] Result *eres_) { +void GarbageCollection::gcTMTelement([[maybe_unused]] Result* eres_) { uint32_t threshold = getGcThreshold(); if (gcq_for_TMT_.empty()) return; for (;;) { - TransactionTable *tmt = gcq_for_TMT_.front(); + TransactionTable* tmt = gcq_for_TMT_.front(); if (tmt->txid_ < threshold) { gcq_for_TMT_.pop_front(); reuse_TMT_element_from_gc_.emplace_back(tmt); diff --git a/cc/si/include/common.hh b/cc/si/include/common.hh index b20c638b..036f246f 100644 --- a/cc/si/include/common.hh +++ b/cc/si/include/common.hh @@ -30,13 +30,17 @@ alignas(CACHE_LINE_SIZE) GLOBAL MasstreeWrapper MT; #endif #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint64(clocks_per_us, 2100, "CPU_MHz. Use this info for measuring time."); +DEFINE_uint64(clocks_per_us, 2100, + "CPU_MHz. Use this info for measuring time."); DEFINE_uint64(extime, 3, "Execution time[sec]."); DEFINE_uint64(gc_inter_us, 10, "GC interval[us]."); DEFINE_uint64(max_ope, 10, "Total number of operations per single transaction."); -DEFINE_uint64(pre_reserve_tmt_element, 100, "Pre-allocating memory for the transaction mapping table elements."); -DEFINE_uint64(pre_reserve_version, 10000, "Pre-allocating memory for the version."); +DEFINE_uint64( + pre_reserve_tmt_element, 100, + "Pre-allocating memory for the transaction mapping table elements."); +DEFINE_uint64(pre_reserve_version, 10000, + "Pre-allocating memory for the version."); DEFINE_bool(rmw, false, "True means read modify write, false means blind write."); DEFINE_uint64(rratio, 50, "read ratio of single transaction."); @@ -51,8 +55,10 @@ DEFINE_uint64(batch_ratio, 0, "ratio of batch transaction."); DEFINE_uint64(batch_max_ope, 1000, "Total number of operations per single batch transaction."); DEFINE_uint64(batch_rratio, 100, "read ratio of single batch transaction."); -DEFINE_uint64(batch_tuples, 0, "Number of update-only records for batch transaction."); -DEFINE_bool(batch_simple_rr, false, "No one touches update-only records of batch transaction."); +DEFINE_uint64(batch_tuples, 0, + "Number of update-only records for batch transaction."); +DEFINE_bool(batch_simple_rr, false, + "No one touches update-only records of batch transaction."); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(extime); @@ -77,9 +83,9 @@ DECLARE_bool(batch_simple_rr); GLOBAL uint64_t TotalThreadNum; -alignas(CACHE_LINE_SIZE) GLOBAL Tuple *Table; +alignas(CACHE_LINE_SIZE) GLOBAL Tuple* Table; alignas(CACHE_LINE_SIZE) GLOBAL -TransactionTable **TMT; // Transaction Mapping Table + TransactionTable** TMT; // Transaction Mapping Table // Per-thread "smallest cstamp currently in this thread's gcq_for_version_", // or UINT32_MAX if the queue is empty. Each thread updates its own slot @@ -87,6 +93,6 @@ TransactionTable **TMT; // Transaction Mapping Table // and only frees a Tuple whose delete-version cstamp is strictly less // than that min, guaranteeing no other thread still references the Tuple // from its gcq_for_version_ (epoch-based reclamation). -alignas(CACHE_LINE_SIZE) GLOBAL std::atomic *MinQueuedCstamp; +alignas(CACHE_LINE_SIZE) GLOBAL std::atomic* MinQueuedCstamp; GLOBAL std::mutex SsnLock; diff --git a/cc/si/include/garbage_collection.hh b/cc/si/include/garbage_collection.hh index 8fe8b211..bce6081e 100644 --- a/cc/si/include/garbage_collection.hh +++ b/cc/si/include/garbage_collection.hh @@ -15,17 +15,17 @@ class TransactionTable; class GarbageCollection { private: - uint32_t fmin_, fmax_; // first range of txid in TMT. - uint32_t smin_, smax_; // second range of txid in TMT. - static std::atomic - GC_threshold_; // share for all object (meaning all thread). + uint32_t fmin_, fmax_; // first range of txid in TMT. + uint32_t smin_, smax_; // second range of txid in TMT. + static std::atomic + GC_threshold_; // share for all object (meaning all thread). public: - std::deque gcq_for_TMT_; - std::deque reuse_TMT_element_from_gc_; - std::deque gcq_for_record_; - std::deque > gcq_for_version_; - std::deque reuse_version_from_gc_; + std::deque gcq_for_TMT_; + std::deque reuse_TMT_element_from_gc_; + std::deque gcq_for_record_; + std::deque> gcq_for_version_; + std::deque reuse_version_from_gc_; uint8_t thid_; GarbageCollection() {} @@ -56,11 +56,11 @@ public: // ----- // for worker thread - void gcVersion(Result *eres_); + void gcVersion(Result* eres_); void gcRecord(); - void gcTMTelement(Result *eres_); + void gcTMTelement(Result* eres_); // ----- // Publish the smallest cstamp currently held in this thread's @@ -68,9 +68,8 @@ public: // refuse to free a Tuple unless every thread's published min strictly // exceeds the Tuple's delete-version cstamp. INLINE void publishMinQueuedCstamp() { - uint32_t v = gcq_for_version_.empty() - ? UINT32_MAX - : gcq_for_version_.front().cstamp_; + uint32_t v = gcq_for_version_.empty() ? UINT32_MAX + : gcq_for_version_.front().cstamp_; MinQueuedCstamp[thid_].store(v, std::memory_order_release); } }; diff --git a/cc/si/include/lock.hh b/cc/si/include/lock.hh index 4553d945..dcc5a582 100644 --- a/cc/si/include/lock.hh +++ b/cc/si/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -40,7 +38,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -56,7 +54,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/cc/si/include/result.hh b/cc/si/include/result.hh index bed8d2c5..d7f133db 100644 --- a/cc/si/include/result.hh +++ b/cc/si/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector SIResult; +extern std::vector SIResult; extern void initResult(); diff --git a/cc/si/include/scan_callback.hh b/cc/si/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/si/include/scan_callback.hh +++ b/cc/si/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/si/include/si_op_element.hh b/cc/si/include/si_op_element.hh index 43a344cf..0576c466 100644 --- a/cc/si/include/si_op_element.hh +++ b/cc/si/include/si_op_element.hh @@ -4,39 +4,42 @@ #include "version.hh" -template +template class SetElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; - SetElement(Storage s, std::string_view key, T *rcdptr, Version *ver) - : OpElement::OpElement(s, key, rcdptr) { + SetElement(Storage s, std::string_view key, T* rcdptr, Version* ver) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; } - SetElement(Storage s, std::string_view key, T *rcdptr, Version *ver, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + SetElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { this->ver_ = ver; } - bool operator<(const SetElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const SetElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class GCElement : public OpElement { public: using OpElement::OpElement; - Version *ver_; + Version* ver_; uint32_t cstamp_; - GCElement(Storage s, std::string_view key, T *rcdptr, Version *ver, uint32_t cstamp) - : OpElement::OpElement(s, key, rcdptr) { + GCElement(Storage s, std::string_view key, T* rcdptr, Version* ver, + uint32_t cstamp) + : OpElement::OpElement(s, key, rcdptr) { this->ver_ = ver; this->cstamp_ = cstamp; } diff --git a/cc/si/include/transaction.hh b/cc/si/include/transaction.hh index 43b0cea6..53f76a74 100644 --- a/cc/si/include/transaction.hh +++ b/cc/si/include/transaction.hh @@ -27,40 +27,42 @@ class TxScanCallback; class TxExecutor { public: - uint8_t thid_; // thread ID - uint32_t cstamp_ = 0; // Transaction end time, c(T) - uint32_t pstamp_ = 0; // Predecessor high-water mark, η (T) - uint32_t sstamp_ = UINT32_MAX; // Successor low-water mark, pi (T) + uint8_t thid_; // thread ID + uint32_t cstamp_ = 0; // Transaction end time, c(T) + uint32_t pstamp_ = 0; // Predecessor high-water mark, η (T) + uint32_t sstamp_ = UINT32_MAX; // Successor low-water mark, pi (T) uint32_t pre_gc_threshold_ = 0; - uint32_t txid_; // TID and begin timestamp - the current log sequence number (LSN) - uint64_t gcstart_, gcstop_; // counter for garbage collection + uint32_t + txid_; // TID and begin timestamp - the current log sequence number (LSN) + uint64_t gcstart_, gcstop_; // counter for garbage collection - vector > read_set_; - vector > write_set_; + vector> read_set_; + vector> write_set_; std::unordered_map node_map_; - vector pro_set_; + vector pro_set_; bool reconnoitering_ = false; bool is_ronly_ = false; bool is_batch_ = false; - Result *result_; + Result* result_; TransactionStatus status_ = - TransactionStatus::inflight; // Status: inflight, committed, or aborted + TransactionStatus::inflight; // Status: inflight, committed, or aborted GarbageCollection gcobject_; GarbageCollection gcob; TxScanCallback callback_; Backoff& backoff_; const bool& quit_; // for thread termination control - TxExecutor(uint8_t thid, Backoff& backoff, Result *res, const bool &quit) - : thid_(thid), result_(res), callback_(TxScanCallback(this)), backoff_(backoff), quit_(quit) { + TxExecutor(uint8_t thid, Backoff& backoff, Result* res, const bool& quit) + : thid_(thid), result_(res), callback_(TxScanCallback(this)), + backoff_(backoff), quit_(quit) { gcobject_.set_thid_(thid); if (FLAGS_pre_reserve_tmt_element) { for (size_t i = 0; i < FLAGS_pre_reserve_tmt_element; ++i) gcobject_.reuse_TMT_element_from_gc_.emplace_back( - new TransactionTable()); + new TransactionTable()); } if (FLAGS_pre_reserve_version) { @@ -80,15 +82,13 @@ public: Status delete_record(Storage s, std::string_view key); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); void si_commit(); @@ -102,11 +102,11 @@ public: void leaderWork(); - void reconnoiter_begin(); + void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_end(); - Status install_version(Tuple* tuple, Version *ver); + Status install_version(Tuple* tuple, Version* ver); void verify_exclusion_or_abort(); @@ -114,7 +114,7 @@ public: void dispRS(); - void upReadersBits(Version *ver) { + void upReadersBits(Version* ver) { uint64_t expected, desired; expected = ver->readers_.load(memory_order_acquire); for (;;) { @@ -125,7 +125,7 @@ public: } } - void downReadersBits(Version *ver) { + void downReadersBits(Version* ver) { uint64_t expected, desired; expected = ver->readers_.load(memory_order_acquire); for (;;) { @@ -136,7 +136,7 @@ public: } } - static INLINE Tuple *get_tuple(Tuple *table, uint64_t key) { + static INLINE Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } @@ -148,8 +148,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline SetElement *searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { + inline SetElement* searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -165,8 +165,8 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - inline SetElement *searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { + inline SetElement* searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } diff --git a/cc/si/include/transaction_table.hh b/cc/si/include/transaction_table.hh index 3b615b81..d2a92191 100644 --- a/cc/si/include/transaction_table.hh +++ b/cc/si/include/transaction_table.hh @@ -8,11 +8,11 @@ class TransactionTable { public: - alignas(CACHE_LINE_SIZE) std::atomic txid_; - std::atomic cstamp_; - std::atomic sstamp_; - std::atomic lastcstamp_; - std::atomic status_; + alignas(CACHE_LINE_SIZE) std::atomic txid_; + std::atomic cstamp_; + std::atomic sstamp_; + std::atomic lastcstamp_; + std::atomic status_; TransactionTable() {} diff --git a/cc/si/include/tuple.hh b/cc/si/include/tuple.hh index 9483410a..1818b816 100644 --- a/cc/si/include/tuple.hh +++ b/cc/si/include/tuple.hh @@ -8,9 +8,9 @@ class Tuple { public: - alignas(CACHE_LINE_SIZE) std::atomic latest_; - std::atomic min_cstamp_; - std::atomic gc_lock_; + alignas(CACHE_LINE_SIZE) std::atomic latest_; + std::atomic min_cstamp_; + std::atomic gc_lock_; TupleBody body_; // only used for index tuple as single version Tuple() { @@ -18,11 +18,12 @@ public: gc_lock_.store(0, std::memory_order_release); } - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* param) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* param) { // for initializer min_cstamp_ = 0; latest_.store(new Version(), std::memory_order_release); - Version *verTmp = latest_.load(std::memory_order_acquire); + Version* verTmp = latest_.load(std::memory_order_acquire); verTmp->cstamp_ = 0; // verTmp->pstamp = 0; // verTmp->sstamp = UINT64_MAX & ~(1); @@ -40,7 +41,7 @@ public: void init(uint32_t txid, TupleBody&& body) { min_cstamp_ = 0; latest_.store(new Version(), std::memory_order_release); - Version *verTmp = latest_.load(std::memory_order_acquire); + Version* verTmp = latest_.load(std::memory_order_acquire); verTmp->cstamp_.store(txid, memory_order_release); verTmp->psstamp_.pstamp_ = 0; verTmp->psstamp_.sstamp_ = UINT32_MAX & ~(1); diff --git a/cc/si/include/util.hh b/cc/si/include/util.hh index 5ebf3d6c..4924c8ab 100644 --- a/cc/si/include/util.hh +++ b/cc/si/include/util.hh @@ -8,11 +8,11 @@ extern void displayDB(); extern void displayParameter(); -extern void leaderWork(GarbageCollection &gcob); +extern void leaderWork(GarbageCollection& gcob); extern void makeDB(); -extern void naiveGarbageCollection(const bool &quit); +extern void naiveGarbageCollection(const bool& quit); extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); diff --git a/cc/si/include/version.hh b/cc/si/include/version.hh index 211c0fca..9cb42249 100644 --- a/cc/si/include/version.hh +++ b/cc/si/include/version.hh @@ -92,11 +92,11 @@ struct Psstamp { class Version { public: alignas(CACHE_LINE_SIZE) Psstamp - psstamp_; // Version access stamp, eta(V), Version successor stamp, pi(V) - Version *prev_; // Pointer to overwritten version - std::atomic readers_; // summarize all of V's readers. - std::atomic cstamp_; // Version creation stamp, c(V) - std::atomic status_; + psstamp_; // Version access stamp, eta(V), Version successor stamp, pi(V) + Version* prev_; // Pointer to overwritten version + std::atomic readers_; // summarize all of V's readers. + std::atomic cstamp_; // Version creation stamp, c(V) + std::atomic status_; TupleBody body_; diff --git a/cc/si/sbomb_si.cc b/cc/si/sbomb_si.cc index 5d137901..eb083e2f 100644 --- a/cc/si/sbomb_si.cc +++ b/cc/si/sbomb_si.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &SIResult[thid], quit); - StaticBombWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &SIResult[thid], quit); + StaticBombWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB SI benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); - StaticBombWorkload::makeDB(nullptr); + StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -80,15 +80,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -97,11 +95,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SIResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/si/si.cc b/cc/si/si.cc index a1b47834..1792f77d 100644 --- a/cc/si/si.cc +++ b/cc/si/si.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -31,11 +31,11 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - TxExecutor trans(thid, (Result *) &SIResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + TxExecutor trans(thid, (Result*) &SIResult[thid]); Xoroshiro128Plus rnd; rnd.init(); - Result &myres = std::ref(SIResult[thid]); + Result& myres = std::ref(SIResult[thid]); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); GarbageCollection gcob; /** @@ -52,13 +52,11 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); uint64_t tuples = FLAGS_tuple_num; - if (FLAGS_batch_simple_rr) { - tuples = FLAGS_tuple_num - FLAGS_batch_tuples; - } + if (FLAGS_batch_simple_rr) { tuples = FLAGS_tuple_num - FLAGS_batch_tuples; } if (thid == 0) gcob.decideFirstRange(); storeRelease(ready, 1); @@ -66,14 +64,14 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { trans.gcstart_ = rdtscp(); while (!loadAcquire(quit)) { auto r = rnd.next() % 100; - if ((FLAGS_thread_num && thid >= FLAGS_thread_num) - || (r < FLAGS_batch_ratio)) { + if ((FLAGS_thread_num && thid >= FLAGS_thread_num) || + (r < FLAGS_batch_ratio)) { trans.is_batch_ = true; - makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, - FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, - myres); - } else if (r >= FLAGS_batch_ratio - && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, + FLAGS_batch_tuples, FLAGS_batch_max_ope, + FLAGS_batch_rratio, FLAGS_rmw, myres); + } else if (r >= FLAGS_batch_ratio && + r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { trans.is_batch_ = false; makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, FLAGS_max_ope, myres); @@ -83,7 +81,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, thid, myres); } -RETRY: + RETRY: if (thid == 0) { leaderWork(std::ref(gcob)); leaderBackoffWork(backoff, SIResult); @@ -128,9 +126,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { } #ifdef INSERT_BATCH_DELAY_MS - if (trans.is_batch_) { - sleepMs(INSERT_BATCH_DELAY_MS); - } + if (trans.is_batch_) { sleepMs(INSERT_BATCH_DELAY_MS); } #endif trans.ssn_parallel_commit(); @@ -141,10 +137,10 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { */ if (trans.is_batch_) { storeRelease(myres.local_batch_commit_counts_, - loadAcquire(myres.local_batch_commit_counts_) + 1); + loadAcquire(myres.local_batch_commit_counts_) + 1); } else { storeRelease(myres.local_commit_counts_, - loadAcquire(myres.local_commit_counts_) + 1); + loadAcquire(myres.local_commit_counts_) + 1); } } else if (trans.status_ == TransactionStatus::aborted) { trans.abort(); @@ -165,7 +161,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("SI benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); @@ -182,15 +178,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SIResult[0].addLocalAllResult(SIResult[i]); @@ -198,10 +192,8 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/si/tpcc_si.cc b/cc/si/tpcc_si.cc index cac9a1ff..bf35ea42 100644 --- a/cc/si/tpcc_si.cc +++ b/cc/si/tpcc_si.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,21 +33,21 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { #if MASSTREE_USE MasstreeWrapper::thread_init(int(thid)); #endif Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &SIResult[thid], quit); - TPCCWorkload workload; + TxExecutor trans(thid, backoff, (Result*) &SIResult[thid], quit); + TPCCWorkload workload; #ifdef Linux setThreadAffinity(thid); // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -57,17 +57,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C SI benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -80,15 +80,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); std::cout << "done" << std::endl; for (unsigned int i = 0; i < TotalThreadNum; ++i) { @@ -97,11 +95,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SIResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/si/transaction.cc b/cc/si/transaction.cc index b57c6ddb..2e93a6fb 100644 --- a/cc/si/transaction.cc +++ b/cc/si/transaction.cc @@ -116,16 +116,17 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search versions from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif if (tuple == nullptr) return Status::WARN_NOT_FOUND; - Version *ver; + Version* ver; ver = read_internal(s, key, tuple); - if (ver == nullptr || ver->status_.load(memory_order_acquire) == VersionStatus::deleted) + if (ver == nullptr || + ver->status_.load(memory_order_acquire) == VersionStatus::deleted) return Status::WARN_NOT_FOUND; /** @@ -143,19 +144,18 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { return Status::OK; } -Version* TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Version* TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { /** * Move to the points of this view. */ - Version *ver; + Version* ver; ver = tuple->latest_.load(memory_order_acquire); - while ((ver->status_.load(memory_order_acquire) != VersionStatus::committed - && ver->status_.load(memory_order_acquire) != VersionStatus::deleted) - || txid_ < ver->cstamp_.load(memory_order_acquire)) { + while ((ver->status_.load(memory_order_acquire) != VersionStatus::committed && + ver->status_.load(memory_order_acquire) != VersionStatus::deleted) || + txid_ < ver->cstamp_.load(memory_order_acquire)) { ver = ver->prev_; - if (ver == nullptr) { - return nullptr; - } + if (ver == nullptr) { return nullptr; } } // SI: just record the version we observed in the snapshot. @@ -189,8 +189,9 @@ Status TxExecutor::install_version(Tuple* tuple, Version* desired) { // if latest version is not comitted. vertmp = expected; - while (vertmp->status_.load(memory_order_acquire) != VersionStatus::committed - && vertmp->status_.load(memory_order_acquire) != VersionStatus::deleted) + while (vertmp->status_.load(memory_order_acquire) != + VersionStatus::committed && + vertmp->status_.load(memory_order_acquire) != VersionStatus::deleted) vertmp = vertmp->prev_; // vertmp is latest committed version. @@ -233,7 +234,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * avoid false positive. */ - Tuple *tuple; + Tuple* tuple; tuple = nullptr; for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { if ((*itr).storage_ == s && (*itr).key_ == key) { @@ -264,7 +265,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { * Forbid a transaction to update a record that has a committed head version * later than its begin timestamp. */ - Version *desired; + Version* desired; desired = new Version(); if (gcobject_.reuse_version_from_gc_.empty()) { desired = new Version(); @@ -279,13 +280,12 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { ++result_->local_version_reuse_; #endif } - desired->cstamp_.store(this->txid_, memory_order_relaxed); // read operation, write operation, + desired->cstamp_.store( + this->txid_, memory_order_relaxed); // read operation, write operation, // it is also accessed by garbage collection. stat = install_version(tuple, desired); - if (stat != Status::OK) { - goto FINISH_WRITE; - } + if (stat != Status::OK) { goto FINISH_WRITE; } // SI: no SSN bookkeeping (sstamp/pstamp updates) — just record the write. desired->body_ = std::move(body); @@ -301,7 +301,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (searchWriteSet(s, key)) return Status::WARN_ALREADY_EXISTS; @@ -309,22 +309,21 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(this->txid_, std::move(body)); Version* ver = tuple->latest_.load(std::memory_order_acquire); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -342,22 +341,20 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS return Status::OK; } Status TxExecutor::delete_record(Storage s, std::string_view key) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS Status stat = Status::OK; // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple = nullptr; @@ -374,11 +371,11 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; -#endif // if ADD_ANALYSIS +#endif // if ADD_ANALYSIS if (tuple == nullptr) return Status::WARN_NOT_FOUND; } - Version *desired; + Version* desired; desired = new Version(); if (gcobject_.reuse_version_from_gc_.empty()) { desired = new Version(); @@ -393,14 +390,13 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { ++result_->local_version_reuse_; #endif } - desired->cstamp_.store(this->txid_, memory_order_relaxed); // read operation, write operation, + desired->cstamp_.store( + this->txid_, memory_order_relaxed); // read operation, write operation, // it is also accessed by garbage collection. stat = install_version(tuple, desired); - if (stat != Status::OK) { - goto FINISH_DELETE; - } + if (stat != Status::OK) { goto FINISH_DELETE; } // SI: no SSN bookkeeping for deletes either. write_set_.emplace_back(s, key, tuple, desired, OpType::DELETE); @@ -412,28 +408,26 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { return stat; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); std::set seen; - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { // TODO: Tuple should have key? Accessing key through the latest ver is ugly // Must be a copy to avoid buffer overflow when changing the latest std::string key(itr->latest_.load(memory_order_acquire)->body_.get_key()); @@ -454,7 +448,8 @@ Status TxExecutor::scan(const Storage s, Version* v = read_internal(s, key, itr); if (this->status_ == TransactionStatus::aborted) return Status::ERROR_PREEMPTIVE_ABORT; - if (v == nullptr || v->status_.load(memory_order_acquire) == VersionStatus::deleted) + if (v == nullptr || + v->status_.load(memory_order_acquire) == VersionStatus::deleted) continue; if (seen.find(v) == seen.end()) { result.emplace_back(&(v->body_)); @@ -478,7 +473,7 @@ void TxExecutor::si_commit() { uint64_t start(rdtscp()); #endif this->status_ = TransactionStatus::committing; - TransactionTable *tmt = TMT[thid_]; + TransactionTable* tmt = TMT[thid_]; tmt->status_.store(TransactionStatus::committing); this->cstamp_ = ++Lsn; @@ -488,7 +483,7 @@ void TxExecutor::si_commit() { // for scans require that no concurrent insert/delete have changed the // structure of nodes we scanned through. for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { status_ = TransactionStatus::aborted; tmt->status_.store(TransactionStatus::aborted, memory_order_release); @@ -520,10 +515,12 @@ void TxExecutor::si_commit() { (*itr).ver_->status_.store(VersionStatus::deleted, memory_order_release); gcobject_.gcq_for_record_.push_back((*itr).rcdptr_); } else { - (*itr).ver_->status_.store(VersionStatus::committed, memory_order_release); + (*itr).ver_->status_.store(VersionStatus::committed, + memory_order_release); } gcobject_.gcq_for_version_.emplace_back( - GCElement((*itr).storage_, (*itr).key_, (*itr).rcdptr_, (*itr).ver_, this->cstamp_)); + GCElement((*itr).storage_, (*itr).key_, (*itr).rcdptr_, (*itr).ver_, + this->cstamp_)); } // After pushing this commit's GCElements, expose the (possibly new) // queue front cstamp so other threads' gcRecord can advance safely. @@ -624,8 +621,7 @@ void TxExecutor::mainte() { bool TxExecutor::commit() { si_commit(); - if (status_ == TransactionStatus::aborted) - return false; + if (status_ == TransactionStatus::aborted) return false; /** * Maintenance phase @@ -634,9 +630,7 @@ bool TxExecutor::commit() { return true; } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { if (gcob.chkSecondRange()) { @@ -648,9 +642,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); @@ -659,10 +651,11 @@ void TxExecutor::reconnoiter_end() { begin(); } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/si/util.cc b/cc/si/util.cc index d356625b..5cce991e 100644 --- a/cc/si/util.cc +++ b/cc/si/util.cc @@ -2,9 +2,9 @@ #include #include #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include #include @@ -57,15 +57,13 @@ void chkArg() { } try { - TMT = new TransactionTable *[TotalThreadNum]; + TMT = new TransactionTable*[TotalThreadNum]; MinQueuedCstamp = new std::atomic[TotalThreadNum]; - } catch (const bad_alloc&) { - ERR; - } + } catch (const bad_alloc&) { ERR; } for (unsigned int i = 0; i < TotalThreadNum; ++i) { TMT[i] = - new TransactionTable(0, 0, UINT32_MAX, 0, TransactionStatus::inflight); + new TransactionTable(0, 0, UINT32_MAX, 0, TransactionStatus::inflight); MinQueuedCstamp[i].store(UINT32_MAX, std::memory_order_relaxed); } } @@ -113,8 +111,10 @@ void displayParameter() { cout << "#FLAGS_extime:\t\t\t\t" << FLAGS_extime << endl; cout << "#FLAGS_gc_inter_us:\t\t\t" << FLAGS_gc_inter_us << endl; cout << "#FLAGS_max_ope:\t\t\t\t" << FLAGS_max_ope << endl; - cout << "#FLAGS_pre_reserve_tmt_element:\t\t" << FLAGS_pre_reserve_tmt_element << endl; - cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version << endl; + cout << "#FLAGS_pre_reserve_tmt_element:\t\t" << FLAGS_pre_reserve_tmt_element + << endl; + cout << "#FLAGS_pre_reserve_version:\t\t" << FLAGS_pre_reserve_version + << endl; cout << "#FLAGS_rmw:\t\t\t\t" << FLAGS_rmw << endl; cout << "#FLAGS_rratio:\t\t\t\t" << FLAGS_rratio << endl; cout << "#FLAGS_thread_num:\t\t\t" << FLAGS_thread_num << endl; @@ -176,8 +176,8 @@ void displayParameter() { // for (auto &th : thv) th.join(); // } -void naiveGarbageCollection(const bool &quit) { - TransactionTable *tmt; +void naiveGarbageCollection(const bool& quit) { + TransactionTable* tmt; uint32_t mintxID = UINT32_MAX; for (unsigned int i = 1; i < TotalThreadNum; ++i) { @@ -203,7 +203,7 @@ void naiveGarbageCollection(const bool &quit) { uint64_t verCstamp = verTmp->cstamp_.load(memory_order_acquire); while (mintxID < (verCstamp >> 1) || verTmp->status_.load(memory_order_acquire) != - VersionStatus::committed) { + VersionStatus::committed) { verTmp = verTmp->prev_; if (verTmp == nullptr) break; verCstamp = verTmp->cstamp_.load(memory_order_acquire); @@ -233,7 +233,7 @@ void naiveGarbageCollection(const bool &quit) { } } -void siLeaderWork(GarbageCollection &gcob) { +void siLeaderWork(GarbageCollection& gcob) { if (gcob.chkSecondRange()) { gcob.decideGcThreshold(); gcob.mvSecondRangeToFirstRange(); diff --git a/cc/si/ycsb_si.cc b/cc/si/ycsb_si.cc index 187e1d4b..4ad28f56 100644 --- a/cc/si/ycsb_si.cc +++ b/cc/si/ycsb_si.cc @@ -1,13 +1,13 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include -#include //string +#include //string #define GLOBAL_VALUE_DEFINE @@ -33,9 +33,9 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Backoff backoff(FLAGS_clocks_per_us); // Cicada's backoff opt. - TxExecutor trans(thid, backoff, (Result *) &SIResult[thid], quit); + TxExecutor trans(thid, backoff, (Result*) &SIResult[thid], quit); YcsbWorkload workload; #if MASSTREE_USE @@ -47,7 +47,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%zu: on CPU %d\n", thid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); if (trans.isLeader()) trans.gcob.decideFirstRange(); @@ -56,17 +56,17 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); trans.gcstart_ = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("SI benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -79,15 +79,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SIResult[0].addLocalAllResult(SIResult[i]); @@ -95,10 +93,8 @@ int main(int argc, char *argv[]) try { ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; SIResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, - TotalThreadNum, - FLAGS_max_ope, FLAGS_batch_max_ope); + TotalThreadNum, FLAGS_max_ope, + FLAGS_batch_max_ope); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/silo/bomb_silo.cc b/cc/silo/bomb_silo.cc index ef7d1f5f..7a6f0763 100644 --- a/cc/silo/bomb_silo.cc +++ b/cc/silo/bomb_silo.cc @@ -35,10 +35,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SiloResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - BombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SiloResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + BombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -77,18 +77,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB Silo benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -96,25 +96,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SiloResult[0].addLocalAllResult(SiloResult[i]); @@ -122,11 +120,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SiloResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/silo/include/atomic_tool.hh b/cc/silo/include/atomic_tool.hh index 0b627438..85a2c9a0 100644 --- a/cc/silo/include/atomic_tool.hh +++ b/cc/silo/include/atomic_tool.hh @@ -20,7 +20,7 @@ INLINE void atomicAddGE() { INLINE uint64_t atomicLoadGE() { uint64_t_64byte result = - __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); return result.obj_; } diff --git a/cc/silo/include/common.hh b/cc/silo/include/common.hh index cbe57727..c75e77dc 100644 --- a/cc/silo/include/common.hh +++ b/cc/silo/include/common.hh @@ -42,8 +42,10 @@ DEFINE_uint64(batch_ratio, 0, "ratio of batch transaction."); DEFINE_uint64(batch_max_ope, 1000, "Total number of operations per single batch transaction."); DEFINE_uint64(batch_rratio, 100, "read ratio of single batch transaction."); -DEFINE_uint64(batch_tuples, 0, "Number of update-only records for batch transaction."); -DEFINE_bool(batch_simple_rr, false, "No one touches update-only records of batch transaction."); +DEFINE_uint64(batch_tuples, 0, + "Number of update-only records for batch transaction."); +DEFINE_bool(batch_simple_rr, false, + "No one touches update-only records of batch transaction."); #else DECLARE_uint64(clocks_per_us); DECLARE_uint64(epoch_time); @@ -66,5 +68,5 @@ DECLARE_bool(batch_simple_rr); alignas(CACHE_LINE_SIZE) GLOBAL uint32_t TotalThreadNum; alignas(CACHE_LINE_SIZE) GLOBAL uint32_t ReclamationEpoch; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThLocalEpoch; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *CTIDW; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThLocalEpoch; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* CTIDW; diff --git a/cc/silo/include/log.hh b/cc/silo/include/log.hh index b0da9a6e..8f1331c2 100644 --- a/cc/silo/include/log.hh +++ b/cc/silo/include/log.hh @@ -34,12 +34,10 @@ public: // goes through a void* because LogRecord is non-trivial (it holds a // std::string_view) — clearing it as raw bytes is intentional here and // -Wclass-memaccess would otherwise flag the typed pointer. - LogRecord() { - memset(static_cast(this), 0, sizeof(LogRecord)); - } + LogRecord() { memset(static_cast(this), 0, sizeof(LogRecord)); } - LogRecord(uint64_t tid, std::string_view key, char *val) { - memset(static_cast(this), 0, sizeof(LogRecord)); + LogRecord(uint64_t tid, std::string_view key, char* val) { + memset(static_cast(this), 0, sizeof(LogRecord)); tid_ = tid; key_ = key; memcpy(this->val_, val, VAL_SIZE); @@ -48,7 +46,7 @@ public: int computeChkSum() { // compute checksum int chkSum = 0; - int *itr = (int *) this; + int* itr = (int*) this; for (unsigned int i = 0; i < sizeof(LogRecord) / sizeof(int); ++i) { chkSum += (*itr); ++itr; diff --git a/cc/silo/include/result.hh b/cc/silo/include/result.hh index 40f2e0ff..9625120b 100644 --- a/cc/silo/include/result.hh +++ b/cc/silo/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector SiloResult; +extern std::vector SiloResult; extern void initResult(); diff --git a/cc/silo/include/scan_callback.hh b/cc/silo/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/silo/include/scan_callback.hh +++ b/cc/silo/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/silo/include/silo_op_element.hh b/cc/silo/include/silo_op_element.hh index db3aae0a..10c72b9d 100644 --- a/cc/silo/include/silo_op_element.hh +++ b/cc/silo/include/silo_op_element.hh @@ -4,46 +4,49 @@ #include "../../../include/op_element.hh" -template +template class ReadElement : public OpElement { public: using OpElement::OpElement; TupleBody body_; - ReadElement(Storage s, std::string_view key, T *rcdptr, char *val, Tidword tidword) - : OpElement::OpElement(s, key, rcdptr) { + ReadElement(Storage s, std::string_view key, T* rcdptr, char* val, + Tidword tidword) + : OpElement::OpElement(s, key, rcdptr) { tidword_.obj_ = tidword.obj_; memcpy(this->val_, val, VAL_SIZE); } - ReadElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, Tidword tidword) - : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { + ReadElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + Tidword tidword) + : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { tidword_.obj_ = tidword.obj_; } - bool operator<(const ReadElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const ReadElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } - Tidword get_tidword() { - return tidword_; - } + Tidword get_tidword() { return tidword_; } private: Tidword tidword_; char val_[VAL_SIZE]; }; -template +template class WriteElement : public OpElement { public: using OpElement::OpElement; TupleBody body_; - WriteElement(Storage s, std::string_view key, T *rcdptr, std::string_view val, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { - static_assert(std::string_view("").size() == 0, "Expected behavior was broken."); + WriteElement(Storage s, std::string_view key, T* rcdptr, std::string_view val, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { + static_assert(std::string_view("").size() == 0, + "Expected behavior was broken."); if (val.size() != 0) { val_ptr_ = std::make_unique(val.size()); memcpy(val_ptr_.get(), val.data(), val.size()); @@ -55,25 +58,21 @@ public: } WriteElement(Storage s, std::string_view key, T* rcdptr, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { - } + : OpElement::OpElement(s, key, rcdptr, op) {} - WriteElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, OpType op) - : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) { - } + WriteElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + OpType op) + : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) {} - bool operator<(const WriteElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const WriteElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } - char *get_val_ptr() { - return val_ptr_.get(); - } + char* get_val_ptr() { return val_ptr_.get(); } - std::size_t get_val_length() { - return val_length_; - } + std::size_t get_val_length() { return val_length_; } private: std::unique_ptr val_ptr_; // NOLINT diff --git a/cc/silo/include/transaction.hh b/cc/silo/include/transaction.hh index c9d4f4c7..f0c8976d 100644 --- a/cc/silo/include/transaction.hh +++ b/cc/silo/include/transaction.hh @@ -46,7 +46,7 @@ public: /* lock_num_ ... * the number of locks in local write set. */ - Result *result_; + Result* result_; uint64_t epoch_timer_start, epoch_timer_stop; Backoff backoff_; const bool& quit_; // for thread termination control @@ -65,9 +65,9 @@ public: // // used by fast approach for benchmark // char return_val_[VAL_SIZE]; - TxExecutor(int thid, Result *res, const bool &quit) - : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit), - callback_(TxScanCallback(this)) { + TxExecutor(int thid, Result* res, const bool& quit) + : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit), + callback_(TxScanCallback(this)) { // latest_log_header_.init(); max_rset_.obj_ = 0; max_wset_.obj_ = 0; @@ -89,7 +89,7 @@ public: void displayWriteSet(); - Tuple *get_tuple(Tuple *table, std::uint64_t key) { return &table[key]; } + Tuple* get_tuple(Tuple* table, std::uint64_t key) { return &table[key]; } Status insert(Storage s, std::string_view key, TupleBody&& body); @@ -105,15 +105,13 @@ public: Status read_internal(Storage s, std::string_view key, Tuple* tuple); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); /** * @brief Search xxx set @@ -124,7 +122,7 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - ReadElement *searchReadSet(Storage s, std::string_view key); + ReadElement* searchReadSet(Storage s, std::string_view key); /** * @brief Search xxx set @@ -135,7 +133,7 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - WriteElement *searchWriteSet(Storage s, std::string_view key); + WriteElement* searchWriteSet(Storage s, std::string_view key); void unlockWriteSet(); @@ -155,8 +153,8 @@ public: bool commit(); - void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_begin(); + void reconnoiter_end(); bool isLeader(); diff --git a/cc/silo/include/tuple.hh b/cc/silo/include/tuple.hh index d9b000e8..31931744 100644 --- a/cc/silo/include/tuple.hh +++ b/cc/silo/include/tuple.hh @@ -13,21 +13,21 @@ struct Tidword { union { uint64_t obj_; struct { - bool lock: 1; - bool latest: 1; - bool absent: 1; - uint64_t tid: 29; - uint64_t epoch: 32; + bool lock : 1; + bool latest : 1; + bool absent : 1; + uint64_t tid : 29; + uint64_t epoch : 32; }; }; - Tidword() : obj_(0) {}; + Tidword() : obj_(0){}; - bool operator==(const Tidword &right) const { return obj_ == right.obj_; } + bool operator==(const Tidword& right) const { return obj_ == right.obj_; } - bool operator!=(const Tidword &right) const { return !operator==(right); } + bool operator!=(const Tidword& right) const { return !operator==(right); } - bool operator<(const Tidword &right) const { return this->obj_ < right.obj_; } + bool operator<(const Tidword& right) const { return this->obj_ < right.obj_; } }; class Tuple { @@ -37,7 +37,8 @@ public: Tuple() {} - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* p) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* p) { // for initializer tidword_.epoch = 1; tidword_.latest = true; diff --git a/cc/silo/include/util.hh b/cc/silo/include/util.hh index 94c7ff43..7671800d 100644 --- a/cc/silo/include/util.hh +++ b/cc/silo/include/util.hh @@ -8,9 +8,10 @@ extern void displayDB(); extern void displayParameter(); -extern void genLogFile(std::string &logpath, const int thid); +extern void genLogFile(std::string& logpath, const int thid); -extern void siloLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void siloLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); extern void makeDB(); @@ -21,6 +22,6 @@ extern void ShowOptParameters(); class DefaultInitializer { public: - DefaultInitializer() {} - void makeDB(); + DefaultInitializer() {} + void makeDB(); }; diff --git a/cc/silo/replayTest.cc b/cc/silo/replayTest.cc index ceba2e15..c172f781 100644 --- a/cc/silo/replayTest.cc +++ b/cc/silo/replayTest.cc @@ -11,7 +11,7 @@ using std::cout; using std::endl; -extern void genLogFile(std::string &logpath, const int thid); +extern void genLogFile(std::string& logpath, const int thid); int main() { std::string logpath; @@ -21,13 +21,13 @@ int main() { LogHeader loadhd; LogRecord logrec; - loadfile.read((void *) &loadhd, sizeof(LogHeader)); + loadfile.read((void*) &loadhd, sizeof(LogHeader)); cout << "chkSum_ : " << loadhd.chkSum_ << endl; cout << "logRecNum_ : " << loadhd.logRecNum_ << endl; int chkSum_ = 0; for (unsigned int i = 0; i < loadhd.logRecNum_; ++i) { - loadfile.read((void *) &logrec, sizeof(LogRecord)); + loadfile.read((void*) &logrec, sizeof(LogRecord)); chkSum_ += logrec.computeChkSum(); cout << "tid : " << logrec.tid_ << endl; cout << "key : " << logrec.key_ << endl; diff --git a/cc/silo/sbomb_silo.cc b/cc/silo/sbomb_silo.cc index 01195bd1..b4e36917 100644 --- a/cc/silo/sbomb_silo.cc +++ b/cc/silo/sbomb_silo.cc @@ -35,10 +35,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SiloResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - StaticBombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SiloResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + StaticBombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -77,18 +77,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB Silo benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); - StaticBombWorkload::makeDB(nullptr); + StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -101,15 +101,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SiloResult[0].addLocalAllResult(SiloResult[i]); @@ -117,11 +115,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SiloResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/silo/silo.cc b/cc/silo/silo.cc index bb365b2c..c55585f1 100644 --- a/cc/silo/silo.cc +++ b/cc/silo/silo.cc @@ -35,11 +35,11 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SiloResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SiloResult[thid]); // Xoroshiro128Plus rnd; // rnd.init(); - TxExecutor trans(thid, (Result *) &myres, quit); + TxExecutor trans(thid, (Result*) &myres, quit); Workload workload; // FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); // uint64_t epoch_timer_start, epoch_timer_stop; @@ -85,107 +85,107 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); -// #if PARTITION_TABLE -// makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, -// FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, -// thid, myres); -// #else -// auto r = rnd.next() % 100; -// if ((FLAGS_thread_num && thid >= FLAGS_thread_num) -// || (r < FLAGS_batch_ratio)) { -// trans.is_batch_ = true; -// makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, -// FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, -// myres); -// } else if (r >= FLAGS_batch_ratio -// && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { -// trans.is_batch_ = false; -// makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, -// FLAGS_max_ope, myres); -// } else { -// trans.is_batch_ = false; -// makeProcedure(trans.pro_set_, rnd, zipf, tuples, FLAGS_max_ope, -// FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, -// false, thid, myres); -// } -// #endif - -// #if PROCEDURE_SORT -// sort(trans.pro_set_.begin(), trans.pro_set_.end()); -// #endif - -// RETRY: -// if (thid == 0) { -// leaderWork(epoch_timer_start, epoch_timer_stop); -// #if BACK_OFF -// leaderBackoffWork(backoff, SiloResult); -// #endif -// // printf("Thread #%d: on CPU %d\n", thid, sched_getcpu()); -// } - -// if (loadAcquire(quit)) break; - -// trans.begin(); -// for (auto itr = trans.pro_set_.begin(); itr != trans.pro_set_.end(); -// ++itr) { -// if ((*itr).ope_ == Ope::READ) { -// trans.read((*itr).key_); -// #ifdef INSERT_READ_DELAY_MS -// sleepMs(INSERT_READ_DELAY_MS); -// #endif -// } else if ((*itr).ope_ == Ope::WRITE) { -// trans.update((*itr).key_); -// } else if ((*itr).ope_ == Ope::READ_MODIFY_WRITE) { -// trans.read((*itr).key_); -// #ifdef INSERT_READ_DELAY_MS -// sleepMs(INSERT_READ_DELAY_MS); -// #endif -// trans.update((*itr).key_); -// } else { -// ERR; -// } -// } - -// #ifdef INSERT_BATCH_DELAY_MS -// if (trans.is_batch_) { -// sleepMs(INSERT_BATCH_DELAY_MS); -// } -// #endif - -// if (trans.validationPhase()) { -// trans.writePhase(); -// /** -// * local_commit_counts is used at ../include/backoff.hh to calcurate about -// * backoff. -// */ -// if (trans.is_batch_) { -// storeRelease(myres.local_batch_commit_counts_, -// loadAcquire(myres.local_batch_commit_counts_) + 1); -// } else { -// storeRelease(myres.local_commit_counts_, -// loadAcquire(myres.local_commit_counts_) + 1); -// } -// } else { -// trans.abort(); -// if (trans.is_batch_) { -// ++myres.local_batch_abort_counts_; -// } else { -// ++myres.local_abort_counts_; -// } -// goto RETRY; -// } + workload.run(trans); + // #if PARTITION_TABLE + // makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, + // FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, true, + // thid, myres); + // #else + // auto r = rnd.next() % 100; + // if ((FLAGS_thread_num && thid >= FLAGS_thread_num) + // || (r < FLAGS_batch_ratio)) { + // trans.is_batch_ = true; + // makeBatchProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, + // FLAGS_batch_max_ope, FLAGS_batch_rratio, FLAGS_rmw, + // myres); + // } else if (r >= FLAGS_batch_ratio + // && r < FLAGS_batch_ratio + FLAGS_ronly_ratio) { + // trans.is_batch_ = false; + // makeProcedure(trans.pro_set_, rnd, FLAGS_tuple_num, FLAGS_batch_tuples, + // FLAGS_max_ope, myres); + // } else { + // trans.is_batch_ = false; + // makeProcedure(trans.pro_set_, rnd, zipf, tuples, FLAGS_max_ope, + // FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, + // false, thid, myres); + // } + // #endif + + // #if PROCEDURE_SORT + // sort(trans.pro_set_.begin(), trans.pro_set_.end()); + // #endif + + // RETRY: + // if (thid == 0) { + // leaderWork(epoch_timer_start, epoch_timer_stop); + // #if BACK_OFF + // leaderBackoffWork(backoff, SiloResult); + // #endif + // // printf("Thread #%d: on CPU %d\n", thid, sched_getcpu()); + // } + + // if (loadAcquire(quit)) break; + + // trans.begin(); + // for (auto itr = trans.pro_set_.begin(); itr != trans.pro_set_.end(); + // ++itr) { + // if ((*itr).ope_ == Ope::READ) { + // trans.read((*itr).key_); + // #ifdef INSERT_READ_DELAY_MS + // sleepMs(INSERT_READ_DELAY_MS); + // #endif + // } else if ((*itr).ope_ == Ope::WRITE) { + // trans.update((*itr).key_); + // } else if ((*itr).ope_ == Ope::READ_MODIFY_WRITE) { + // trans.read((*itr).key_); + // #ifdef INSERT_READ_DELAY_MS + // sleepMs(INSERT_READ_DELAY_MS); + // #endif + // trans.update((*itr).key_); + // } else { + // ERR; + // } + // } + + // #ifdef INSERT_BATCH_DELAY_MS + // if (trans.is_batch_) { + // sleepMs(INSERT_BATCH_DELAY_MS); + // } + // #endif + + // if (trans.validationPhase()) { + // trans.writePhase(); + // /** + // * local_commit_counts is used at ../include/backoff.hh to calcurate about + // * backoff. + // */ + // if (trans.is_batch_) { + // storeRelease(myres.local_batch_commit_counts_, + // loadAcquire(myres.local_batch_commit_counts_) + 1); + // } else { + // storeRelease(myres.local_commit_counts_, + // loadAcquire(myres.local_commit_counts_) + 1); + // } + // } else { + // trans.abort(); + // if (trans.is_batch_) { + // ++myres.local_batch_abort_counts_; + // } else { + // ++myres.local_abort_counts_; + // } + // goto RETRY; + // } } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("Silo benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); Workload::displayWorkloadParameter(); - Workload::makeDB(nullptr); + Workload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -198,24 +198,21 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SiloResult[0].addLocalAllResult(SiloResult[i]); } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/silo/tpcc_silo.cc b/cc/silo/tpcc_silo.cc index cb24ac4d..803435e3 100644 --- a/cc/silo/tpcc_silo.cc +++ b/cc/silo/tpcc_silo.cc @@ -35,10 +35,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SiloResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - TPCCWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SiloResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + TPCCWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -77,18 +77,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C Silo benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -101,15 +101,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SiloResult[0].addLocalAllResult(SiloResult[i]); @@ -117,11 +115,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SiloResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/silo/transaction.cc b/cc/silo/transaction.cc index 2f83e216..cffa661a 100644 --- a/cc/silo/transaction.cc +++ b/cc/silo/transaction.cc @@ -9,7 +9,8 @@ extern std::vector SiloResult; extern void displayDB(); -extern void siloLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void siloLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); void TxExecutor::gc_records() { const auto r_epoch = ReclamationEpoch; @@ -77,22 +78,21 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(std::move(body)); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -123,23 +123,17 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple == nullptr) { - return Status::WARN_NOT_FOUND; - } + if (tuple == nullptr) { return Status::WARN_NOT_FOUND; } tidw.obj_ = loadAcquire(tuple->tidword_.obj_); - if (tidw.absent) { - return Status::WARN_NOT_FOUND; - } + if (tidw.absent) { return Status::WARN_NOT_FOUND; } write_set_.emplace_back(s, key, tuple, OpType::DELETE); #if ADD_ANALYSIS @@ -151,9 +145,8 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { void TxExecutor::lockWriteSet() { Tidword expected, desired; -[[maybe_unused]] retry - : - for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { + [[maybe_unused]] retry + : for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if (itr->op_ == OpType::INSERT) continue; expected.obj_ = loadAcquire((*itr).rcdptr_->tidword_.obj_); for (;;) { @@ -214,7 +207,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -222,9 +215,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { if (tuple == nullptr) return Status::WARN_NOT_FOUND; stat = read_internal(s, key, tuple); - if (stat != Status::OK) { - return stat; - } + if (stat != Status::OK) { return stat; } *body = &(read_set_.back().body_); FINISH_READ: @@ -234,7 +225,8 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { return Status::OK; } -Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Status TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { TupleBody body; Tidword expected, check; @@ -245,16 +237,12 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) // spinning until the lock is clear for (;;) { - while (expected.lock) { - expected.obj_ = loadAcquire(tuple->tidword_.obj_); - } + while (expected.lock) { expected.obj_ = loadAcquire(tuple->tidword_.obj_); } //(b) checks whether the record is the latest version // omit. because this is implemented by single version - if (expected.absent) { - return Status::WARN_NOT_FOUND; - } + if (expected.absent) { return Status::WARN_NOT_FOUND; } //(c) reads the data body = TupleBody(key, tuple->body_.get_val(), tuple->body_.get_val_align()); @@ -279,28 +267,26 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { ReadElement* re = searchReadSet(s, itr->body_.get_key()); if (re) { result.emplace_back(&(re->body_)); @@ -314,14 +300,12 @@ Status TxExecutor::scan(const Storage s, } Status stat = read_internal(s, itr->body_.get_key(), itr); - if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { - return stat; - } + if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { return stat; } } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).body_)); } } @@ -329,12 +313,10 @@ Status TxExecutor::scan(const Storage s, return Status::OK; } -void tx_delete([[maybe_unused]]std::uint64_t key) { - -} +void tx_delete([[maybe_unused]] std::uint64_t key) {} -ReadElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { +ReadElement* TxExecutor::searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -342,8 +324,9 @@ ReadElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { return nullptr; } -WriteElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { +WriteElement* TxExecutor::searchWriteSet(Storage s, + std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -364,7 +347,7 @@ void TxExecutor::unlockWriteSet() { } void TxExecutor::unlockWriteSet( - std::vector>::iterator end) { + std::vector>::iterator end) { Tidword expected, desired; for (auto itr = write_set_.begin(); itr != end; ++itr) { @@ -387,9 +370,9 @@ bool TxExecutor::validationPhase() { // Validation Phase lockWriteSet(); if (this->status_ == TransactionStatus::aborted) return false; - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); atomicStoreThLocalEpoch(thid_, atomicLoadGE()); - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); /* Phase 2 abort if any condition of below is satisfied. * 1. tid of read_set_ changed from it that was got in Read Phase. @@ -426,7 +409,7 @@ bool TxExecutor::validationPhase() { // Validation Phase // node validation for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *)it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { this->status_ = TransactionStatus::aborted; unlockWriteSet(); @@ -444,7 +427,7 @@ bool TxExecutor::validationPhase() { // Validation Phase void TxExecutor::wal(std::uint64_t ctid) { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { - LogRecord log(ctid, (*itr).key_, (char*)"FIXME"); // TODO: logging + LogRecord log(ctid, (*itr).key_, (char*) "FIXME"); // TODO: logging log_set_.emplace_back(log); latest_log_header_.chkSum_ += log.computeChkSum(); ++latest_log_header_.logRecNum_; @@ -455,12 +438,12 @@ void TxExecutor::wal(std::uint64_t ctid) { latest_log_header_.convertChkSumIntoComplementOnTwo(); // write header - logfile_.write((void *) &latest_log_header_, sizeof(LogHeader)); + logfile_.write((void*) &latest_log_header_, sizeof(LogHeader)); // write log record // for (auto itr = log_set_.begin(); itr != log_set_.end(); ++itr) // logfile_.write((void *)&(*itr), sizeof(LogRecord)); - logfile_.write((void *) &(log_set_[0]), + logfile_.write((void*) &(log_set_[0]), sizeof(LogRecord) * latest_log_header_.logRecNum_); // logfile_.fdatasync(); @@ -481,8 +464,8 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * Search tuple from data structure. */ - Tuple *tuple; - ReadElement *re; + Tuple* tuple; + ReadElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -540,8 +523,8 @@ void TxExecutor::writePhase() { // update and unlock switch ((*itr).op_) { case OpType::UPDATE: { - memcpy((*itr).rcdptr_->body_.get_val_ptr(), - (*itr).body_.get_val_ptr(), (*itr).body_.get_val_size()); + memcpy((*itr).rcdptr_->body_.get_val_ptr(), (*itr).body_.get_val_ptr(), + (*itr).body_.get_val_size()); storeRelease((*itr).rcdptr_->tidword_.obj_, maxtid.obj_); break; } @@ -554,7 +537,8 @@ void TxExecutor::writePhase() { maxtid.absent = true; // Return value intentionally ignored: a missing key still needs the // tid bump and gc_records_ push below. - Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present( + (*itr).key_); storeRelease((*itr).rcdptr_->tidword_.obj_, maxtid.obj_); // create information for garbage collection gc_records_.push_back((*itr).rcdptr_); @@ -580,9 +564,7 @@ bool TxExecutor::commit() { } } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { siloLeaderWork(this->epoch_timer_start, this->epoch_timer_stop); @@ -591,9 +573,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); @@ -602,10 +582,11 @@ void TxExecutor::reconnoiter_end() { begin(); } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/silo/util.cc b/cc/silo/util.cc index 6baae7a8..38d2c3b1 100644 --- a/cc/silo/util.cc +++ b/cc/silo/util.cc @@ -1,8 +1,8 @@ #include -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include @@ -49,10 +49,10 @@ void chkArg() { // ERR; // } - if (posix_memalign((void **) &ThLocalEpoch, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThLocalEpoch, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; - if (posix_memalign((void **) &CTIDW, CACHE_LINE_SIZE, + if (posix_memalign((void**) &CTIDW, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; @@ -103,7 +103,7 @@ void displayParameter() { } } -void genLogFile(std::string &logpath, const int thid) { +void genLogFile(std::string& logpath, const int thid) { genLogFileName(logpath, thid); createEmptyFile(logpath); } @@ -147,7 +147,7 @@ void genLogFile(std::string &logpath, const int thid) { // for (auto &th : thv) th.join(); // } -void siloLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop) { +void siloLeaderWork(uint64_t& epoch_timer_start, uint64_t& epoch_timer_stop) { epoch_timer_stop = rdtscp(); if (chkClkSpan(epoch_timer_start, epoch_timer_stop, FLAGS_epoch_time * FLAGS_clocks_per_us * 1000) && diff --git a/cc/silo/ycsb_silo.cc b/cc/silo/ycsb_silo.cc index 867eaf61..5909b89d 100644 --- a/cc/silo/ycsb_silo.cc +++ b/cc/silo/ycsb_silo.cc @@ -35,9 +35,9 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SiloResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SiloResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); YcsbWorkload workload; #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -76,18 +76,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { while (!loadAcquire(start)) _mm_pause(); if (thid == 0) trans.epoch_timer_start = rdtscp(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("YCSB Silo benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -100,24 +100,21 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SiloResult[0].addLocalAllResult(SiloResult[i]); } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SiloResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ss2pl/bomb_ss2pl.cc b/cc/ss2pl/bomb_ss2pl.cc index c45352c8..dc2aa923 100644 --- a/cc/ss2pl/bomb_ss2pl.cc +++ b/cc/ss2pl/bomb_ss2pl.cc @@ -24,10 +24,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SS2PLResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - BombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SS2PLResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + BombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -65,18 +65,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB SS2PL benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -84,25 +84,23 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SS2PLResult[0].addLocalAllResult(SS2PLResult[i]); @@ -110,11 +108,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SS2PLResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ss2pl/include/result.hh b/cc/ss2pl/include/result.hh index 9b0d2f0f..45ffc035 100644 --- a/cc/ss2pl/include/result.hh +++ b/cc/ss2pl/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector SS2PLResult; +extern std::vector SS2PLResult; extern void initResult(); diff --git a/cc/ss2pl/include/ss2pl_op_element.hh b/cc/ss2pl/include/ss2pl_op_element.hh index 46350279..ce7ae300 100644 --- a/cc/ss2pl/include/ss2pl_op_element.hh +++ b/cc/ss2pl/include/ss2pl_op_element.hh @@ -2,26 +2,28 @@ #include "../../../include/op_element.hh" -template +template class SetElement : public OpElement { - public: +public: using OpElement::OpElement; TupleBody body_; - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body) + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body) : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) {} - SetElement(Storage s, std::string_view key, T *rcdptr) + SetElement(Storage s, std::string_view key, T* rcdptr) : OpElement::OpElement(s, key, rcdptr) {} - SetElement(Storage s, std::string_view key, T *rcdptr, OpType op) + SetElement(Storage s, std::string_view key, T* rcdptr, OpType op) : OpElement::OpElement(s, key, rcdptr, op) {} - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body, OpType op) + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + OpType op) : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) {} - bool operator<(const SetElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const SetElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; diff --git a/cc/ss2pl/include/transaction.hh b/cc/ss2pl/include/transaction.hh index d9fd46ec..78b7930b 100644 --- a/cc/ss2pl/include/transaction.hh +++ b/cc/ss2pl/include/transaction.hh @@ -22,19 +22,19 @@ enum class TransactionStatus : uint8_t { aborted, }; -extern void writeValGenerator(char *writeVal, size_t val_size, size_t thid); +extern void writeValGenerator(char* writeVal, size_t val_size, size_t thid); class TxExecutor { public: alignas(CACHE_LINE_SIZE) int thid_; - std::vector r_lock_list_; - std::vector w_lock_list_; + std::vector r_lock_list_; + std::vector w_lock_list_; TransactionStatus status_ = TransactionStatus::inflight; - Result *result_; + Result* result_; Backoff backoff_; - vector > read_set_; - vector > write_set_; - vector pro_set_; + vector> read_set_; + vector> write_set_; + vector pro_set_; std::deque gc_records_; const bool& quit_; // for thread termination control @@ -42,20 +42,20 @@ public: bool is_ronly_ = false; bool is_batch_ = false; - TxExecutor(int thid, Result *res, const bool &quit) - : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit) { -// read_set_.reserve(FLAGS_max_ope); -// write_set_.reserve(FLAGS_max_ope); -// pro_set_.reserve(FLAGS_max_ope); -// r_lock_list_.reserve(FLAGS_max_ope); -// w_lock_list_.reserve(FLAGS_max_ope); -// -// genStringRepeatedNumber(write_val_, VAL_SIZE, thid); + TxExecutor(int thid, Result* res, const bool& quit) + : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit) { + // read_set_.reserve(FLAGS_max_ope); + // write_set_.reserve(FLAGS_max_ope); + // pro_set_.reserve(FLAGS_max_ope); + // r_lock_list_.reserve(FLAGS_max_ope); + // w_lock_list_.reserve(FLAGS_max_ope); + // + // genStringRepeatedNumber(write_val_, VAL_SIZE, thid); } - SetElement *searchReadSet(Storage s, std::string_view key); + SetElement* searchReadSet(Storage s, std::string_view key); - SetElement *searchWriteSet(Storage s, std::string_view key); + SetElement* searchWriteSet(Storage s, std::string_view key); void begin(); @@ -63,15 +63,13 @@ public: Status read(Storage s, std::string_view key, TupleBody** body); void read_internal(Storage s, std::string_view key, Tuple* tuple); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); void write(uint64_t key); Status update(Storage s, std::string_view key, TupleBody&& body); @@ -99,7 +97,7 @@ public: void leaderWork(); // inline - Tuple *get_tuple(Tuple *table, uint64_t key) { return &table[key]; } + Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } }; static_assert(TxExecutorLike); diff --git a/cc/ss2pl/include/tuple.hh b/cc/ss2pl/include/tuple.hh index 4374fc5b..d670266e 100644 --- a/cc/ss2pl/include/tuple.hh +++ b/cc/ss2pl/include/tuple.hh @@ -11,13 +11,14 @@ using namespace std; class Tuple { - public: +public: alignas(CACHE_LINE_SIZE) ReaderWriteLock lock_; TupleBody body_; Tuple() {} - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* p) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* p) { body_ = std::move(body); } diff --git a/cc/ss2pl/include/util.hh b/cc/ss2pl/include/util.hh index 547508fa..a768dac1 100644 --- a/cc/ss2pl/include/util.hh +++ b/cc/ss2pl/include/util.hh @@ -8,6 +8,7 @@ extern void displayParameter(); extern void makeDB(); -extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, uint64_t end); +extern void partTableInit([[maybe_unused]] size_t thid, uint64_t start, + uint64_t end); extern void ShowOptParameters(); diff --git a/cc/ss2pl/ss2pl.cc b/cc/ss2pl/ss2pl.cc index c66a8ae9..bbdc4366 100644 --- a/cc/ss2pl/ss2pl.cc +++ b/cc/ss2pl/ss2pl.cc @@ -1,14 +1,14 @@ -#include //isdigit, +#include //isdigit, #include -#include //strlen, -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), -#include //syscall(SYS_gettid), +#include //strlen, +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), +#include //syscall(SYS_gettid), #include #include -#include //string +#include //string #include #define GLOBAL_VALUE_DEFINE @@ -31,11 +31,11 @@ #include "include/transaction.hh" #include "include/util.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SS2PLResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SS2PLResult[thid]); Xoroshiro128Plus rnd; rnd.init(); - TxExecutor trans(thid, (Result *) &myres); + TxExecutor trans(thid, (Result*) &myres); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); Backoff backoff(FLAGS_clocks_per_us); @@ -48,14 +48,15 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { // printf("Thread #%d: on CPU %d\n", *myid, sched_getcpu()); // printf("sysconf(_SC_NPROCESSORS_CONF) %ld\n", // sysconf(_SC_NPROCESSORS_CONF)); -#endif // Linux +#endif // Linux storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, - FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, thid, myres); -RETRY: + makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, + FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, + thid, myres); + RETRY: if (loadAcquire(quit)) break; if (thid == 0) leaderBackoffWork(backoff, SS2PLResult); @@ -90,7 +91,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("2PL benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); @@ -106,19 +107,16 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { SS2PLResult[0].addLocalAllResult(SS2PLResult[i]); } ShowOptParameters(); - SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, FLAGS_thread_num); + SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + FLAGS_thread_num); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/ss2pl/test/make_db_test.cpp b/cc/ss2pl/test/make_db_test.cpp index 7bdc6c98..bf0dc382 100644 --- a/cc/ss2pl/test/make_db_test.cpp +++ b/cc/ss2pl/test/make_db_test.cpp @@ -14,27 +14,27 @@ namespace ccbench::testing { class make_db_test : public ::testing::Test { public: - static void call_once_f() { - google::InitGoogleLogging("make_db_test_log"); - FLAGS_stderrthreshold = 0; - } + static void call_once_f() { + google::InitGoogleLogging("make_db_test_log"); + FLAGS_stderrthreshold = 0; + } - void SetUp() override { std::call_once(init_, call_once_f); } + void SetUp() override { std::call_once(init_, call_once_f); } - void TearDown() override {} + void TearDown() override {} private: - static inline std::once_flag init_; // NOLINT + static inline std::once_flag init_; // NOLINT }; TEST_F(make_db_test, simple) { // NOLINT - makeDB(); - // verify effect makeDb - for (std::uint64_t i = 0; i < FLAGS_tuple_num; ++i) { - ASSERT_EQ(Table[i].val_[0], 'a'); - ASSERT_EQ(Table[i].val_[1], '\0'); - ASSERT_EQ(Table[i].lock_.counter.load(std::memory_order_acquire), 0); - } + makeDB(); + // verify effect makeDb + for (std::uint64_t i = 0; i < FLAGS_tuple_num; ++i) { + ASSERT_EQ(Table[i].val_[0], 'a'); + ASSERT_EQ(Table[i].val_[1], '\0'); + ASSERT_EQ(Table[i].lock_.counter.load(std::memory_order_acquire), 0); + } } } // namespace ccbench::testing \ No newline at end of file diff --git a/cc/ss2pl/tpcc_ss2pl.cc b/cc/ss2pl/tpcc_ss2pl.cc index 169d809b..99a858d8 100644 --- a/cc/ss2pl/tpcc_ss2pl.cc +++ b/cc/ss2pl/tpcc_ss2pl.cc @@ -34,10 +34,10 @@ using namespace std; -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(SS2PLResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - TPCCWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(SS2PLResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + TPCCWorkload workload; workload.prepare(trans, nullptr); #ifdef Linux @@ -51,18 +51,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C SS2PL benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -75,15 +75,13 @@ int main(int argc, char *argv[]) try { waitForReady(readys); uint64_t start_tsc = rdtscp(); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); uint64_t end_tsc = rdtscp(); - long double actual_extime = round( - (end_tsc-start_tsc) / - ((long double)FLAGS_clocks_per_us * powl(10.0, 6.0))); + long double actual_extime = + round((end_tsc - start_tsc) / + ((long double) FLAGS_clocks_per_us * powl(10.0, 6.0))); for (unsigned int i = 0; i < TotalThreadNum; ++i) { SS2PLResult[0].addLocalAllResult(SS2PLResult[i]); @@ -91,11 +89,10 @@ int main(int argc, char *argv[]) try { } ShowOptParameters(); std::cout << "actual_extime:\t" << actual_extime << std::endl; - SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, TotalThreadNum); + SS2PLResult[0].displayAllResult(FLAGS_clocks_per_us, FLAGS_extime, + TotalThreadNum); std::cout << "Details per transaction type:" << std::endl; SS2PLResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/ss2pl/transaction.cc b/cc/ss2pl/transaction.cc index 5c05fe3d..8d67387e 100644 --- a/cc/ss2pl/transaction.cc +++ b/cc/ss2pl/transaction.cc @@ -13,10 +13,11 @@ using namespace std; -extern void display_procedure_vector(std::vector &pro); +extern void display_procedure_vector(std::vector& pro); -inline SetElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { +inline SetElement* TxExecutor::searchReadSet(Storage s, + std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -24,8 +25,9 @@ inline SetElement *TxExecutor::searchReadSet(Storage s, std::string_view return nullptr; } -inline SetElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { +inline SetElement* TxExecutor::searchWriteSet(Storage s, + std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -75,8 +77,8 @@ bool TxExecutor::commit() { for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { switch ((*itr).op_) { case OpType::UPDATE: { - memcpy((*itr).rcdptr_->body_.get_val_ptr(), - (*itr).body_.get_val_ptr(), (*itr).body_.get_val_size()); + memcpy((*itr).rcdptr_->body_.get_val_ptr(), (*itr).body_.get_val_ptr(), + (*itr).body_.get_val_size()); break; } case OpType::INSERT: { @@ -85,7 +87,8 @@ bool TxExecutor::commit() { case OpType::DELETE: { // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present( + (*itr).key_); // create information for garbage collection gc_records_.push_back((*itr).rcdptr_); break; @@ -123,7 +126,7 @@ void TxExecutor::begin() { this->status_ = TransactionStatus::inflight; } Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { #if ADD_ANALYSIS uint64_t start = rdtscp(); -#endif // ADD_ANALYSIS +#endif // ADD_ANALYSIS TupleBody b; SetElement* e; @@ -144,7 +147,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -185,24 +188,24 @@ void TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { #endif FINISH_READ_LOCK: - body = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), tuple->body_.get_val_align()); + body = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), + tuple->body_.get_val_align()); read_set_.emplace_back(s, key, tuple, std::move(body)); FINISH_READ: return; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); @@ -212,7 +215,7 @@ Status TxExecutor::scan(const Storage s, l_exclusive, right_key.empty() ? nullptr : right_key.data(), right_key.size(), r_exclusive, &scan_res, limit); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { SetElement* e = searchReadSet(s, itr->body_.get_key()); if (e) { result.emplace_back(&(e->body_)); @@ -232,8 +235,8 @@ Status TxExecutor::scan(const Storage s, } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).body_)); } } @@ -256,7 +259,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { for (auto rItr = read_set_.begin(); rItr != read_set_.end(); ++rItr) { if ((*rItr).storage_ != s) continue; - if ((*rItr).key_ == key) { // hit + if ((*rItr).key_ == key) { // hit #if DLR0 // Workaround for handling static BoMB properly if (!(*rItr).rcdptr_->lock_.tryupgrade()) { @@ -275,7 +278,8 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { for (auto lItr = r_lock_list_.begin(); lItr != r_lock_list_.end(); ++lItr) { if (*lItr == &((*rItr).rcdptr_->lock_)) { - write_set_.emplace_back(s, key, (*rItr).rcdptr_, std::move(body), OpType::UPDATE); + write_set_.emplace_back(s, key, (*rItr).rcdptr_, std::move(body), + OpType::UPDATE); w_lock_list_.emplace_back(&(*rItr).rcdptr_->lock_); r_lock_list_.erase(lItr); break; @@ -295,7 +299,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -326,7 +330,7 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { FINISH_WRITE: #if ADD_ANALYSIS result_->local_write_latency_ += rdtscp() - start; -#endif // ADD_ANALYSIS +#endif // ADD_ANALYSIS return Status::OK; } @@ -341,9 +345,7 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(std::move(body)); @@ -371,18 +373,14 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } Tuple* tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple == nullptr) { - return Status::WARN_NOT_FOUND; - } + if (tuple == nullptr) { return Status::WARN_NOT_FOUND; } write_set_.emplace_back(s, key, tuple, OpType::DELETE); @@ -393,27 +391,21 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { } Status TxExecutor::read_lock(Storage s, std::string_view key) { - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif if (reconnoitering_) return Status::OK; - if (tuple == nullptr) { - return Status::WARN_NOT_FOUND; - } + if (tuple == nullptr) { return Status::WARN_NOT_FOUND; } for (auto& r_lock : r_lock_list_) { - if (r_lock == &tuple->lock_) { - return Status::OK; - } + if (r_lock == &tuple->lock_) { return Status::OK; } } for (auto& w_lock : w_lock_list_) { - if (w_lock == &tuple->lock_) { - return Status::OK; - } + if (w_lock == &tuple->lock_) { return Status::OK; } } #ifdef DLR0 @@ -430,7 +422,7 @@ Status TxExecutor::read_lock(Storage s, std::string_view key) { } Status TxExecutor::write_lock(Storage s, std::string_view key) { - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -438,9 +430,7 @@ Status TxExecutor::write_lock(Storage s, std::string_view key) { if (tuple == nullptr) return Status::WARN_NOT_FOUND; for (auto& w_lock : w_lock_list_) { - if (w_lock == &tuple->lock_) { - return Status::OK; - } + if (w_lock == &tuple->lock_) { return Status::OK; } } #if DLR0 @@ -475,9 +465,7 @@ void TxExecutor::unlockList() { w_lock_list_.clear(); } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { unlockList(); @@ -486,9 +474,7 @@ void TxExecutor::reconnoiter_end() { begin(); } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { #if BACK_OFF diff --git a/cc/ss2pl/util.cc b/cc/ss2pl/util.cc index 731c6390..a2b20f4e 100644 --- a/cc/ss2pl/util.cc +++ b/cc/ss2pl/util.cc @@ -1,8 +1,8 @@ #include -#include // syscall(SYS_gettid), -#include // syscall(SSY_gettid), -#include // syscall(SSY_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SSY_gettid), +#include // syscall(SSY_gettid), #include #include @@ -28,9 +28,7 @@ void chkArg() { displayParameter(); - if (FLAGS_rratio > 100) { - ERR; - } + if (FLAGS_rratio > 100) { ERR; } TotalThreadNum = FLAGS_thread_num; @@ -60,19 +58,14 @@ void partTableInit([[maybe_unused]] size_t thid, void makeDB() {} -void -ShowOptParameters() { +void ShowOptParameters() { cout << "#ShowOptParameters()" - << ": ADD_ANALYSIS " << ADD_ANALYSIS - << ": BACK_OFF " << BACK_OFF - #ifdef DLR0 + << ": ADD_ANALYSIS " << ADD_ANALYSIS << ": BACK_OFF " << BACK_OFF +#ifdef DLR0 << ": DLR0 " - #elif defined DLR1 +#elif defined DLR1 << ": DLR1 " - #endif - << ": MASSTREE_USE " << MASSTREE_USE - << ": KEY_SIZE " << KEY_SIZE - << ": KEY_SORT " << KEY_SORT - << ": VAL_SIZE " << VAL_SIZE - << endl; +#endif + << ": MASSTREE_USE " << MASSTREE_USE << ": KEY_SIZE " << KEY_SIZE + << ": KEY_SORT " << KEY_SORT << ": VAL_SIZE " << VAL_SIZE << endl; } diff --git a/cc/tictoc/bomb_tictoc.cc b/cc/tictoc/bomb_tictoc.cc index 544f226f..ac26e64f 100644 --- a/cc/tictoc/bomb_tictoc.cc +++ b/cc/tictoc/bomb_tictoc.cc @@ -31,10 +31,10 @@ #include "../../include/util.hh" #include "../../include/zipf.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(TicTocResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - BombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(TicTocResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + BombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF @@ -58,18 +58,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB TicToc benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - BombWorkload::displayWorkloadParameter(); - BombWorkload::makeDB(nullptr); + BombWorkload::displayWorkloadParameter(); + BombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -77,20 +77,18 @@ int main(int argc, char *argv[]) try { std::vector readys(TotalThreadNum + (FLAGS_bomb_mixed_mode ? 1 : 0)); std::vector thv; for (size_t i = 0; i < TotalThreadNum; ++i) - thv.emplace_back(worker, i, std::ref(readys[i]), - std::ref(start), std::ref(quit)); + thv.emplace_back(worker, i, std::ref(readys[i]), std::ref(start), + std::ref(quit)); if (FLAGS_bomb_mixed_mode) { - thv.emplace_back(BombWorkload::request_dispatcher, + thv.emplace_back(BombWorkload::request_dispatcher, TotalThreadNum, std::ref(readys[TotalThreadNum]), std::ref(start), std::ref(quit)); } waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { TicTocResult[0].addLocalAllResult(TicTocResult[i]); @@ -103,6 +101,4 @@ int main(int argc, char *argv[]) try { TicTocResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/tictoc/include/atomic_tool.hh b/cc/tictoc/include/atomic_tool.hh index 0b627438..85a2c9a0 100644 --- a/cc/tictoc/include/atomic_tool.hh +++ b/cc/tictoc/include/atomic_tool.hh @@ -20,7 +20,7 @@ INLINE void atomicAddGE() { INLINE uint64_t atomicLoadGE() { uint64_t_64byte result = - __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&(GlobalEpoch.obj_), __ATOMIC_ACQUIRE); return result.obj_; } diff --git a/cc/tictoc/include/common.hh b/cc/tictoc/include/common.hh index 7098bac0..ae6d2d84 100644 --- a/cc/tictoc/include/common.hh +++ b/cc/tictoc/include/common.hh @@ -59,4 +59,4 @@ DECLARE_double(zipf_skew); GLOBAL uint64_t TotalThreadNum; alignas(CACHE_LINE_SIZE) GLOBAL uint32_t ReclamationEpoch; -alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte *ThLocalEpoch; +alignas(CACHE_LINE_SIZE) GLOBAL uint64_t_64byte* ThLocalEpoch; diff --git a/cc/tictoc/include/result.hh b/cc/tictoc/include/result.hh index e19b36a2..a8bc639a 100644 --- a/cc/tictoc/include/result.hh +++ b/cc/tictoc/include/result.hh @@ -4,6 +4,6 @@ #include "../../../include/result.hh" -extern std::vector TicTocResult; +extern std::vector TicTocResult; extern void initResult(); diff --git a/cc/tictoc/include/scan_callback.hh b/cc/tictoc/include/scan_callback.hh index fdf932ca..227b94b4 100644 --- a/cc/tictoc/include/scan_callback.hh +++ b/cc/tictoc/include/scan_callback.hh @@ -3,15 +3,16 @@ class TxExecutor; class TxScanCallback : public MasstreeWrapper::ScanCallback { - public: +public: TxExecutor* tx_; - TxScanCallback(TxExecutor *tx) : tx_(tx) {}; + TxScanCallback(TxExecutor* tx) : tx_(tx){}; - void on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version); + void on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version); - bool invoke(const std::string_view & /*k*/, Tuple /*v*/, - const MasstreeWrapper::node_type * /*n*/, + bool invoke(const std::string_view& /*k*/, Tuple /*v*/, + const MasstreeWrapper::node_type* /*n*/, uint64_t /*version*/) { return true; } diff --git a/cc/tictoc/include/tictoc_op_element.hh b/cc/tictoc/include/tictoc_op_element.hh index 49caf76d..d30c4cc6 100644 --- a/cc/tictoc/include/tictoc_op_element.hh +++ b/cc/tictoc/include/tictoc_op_element.hh @@ -2,7 +2,7 @@ #include "../../../include/op_element.hh" -template +template class SetElement : public OpElement { public: using OpElement::OpElement; @@ -10,35 +10,38 @@ public: TupleBody body_; TsWord tsw_; - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body, TsWord tsw, OpType op) - : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) { + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + TsWord tsw, OpType op) + : OpElement::OpElement(s, key, rcdptr, op), body_(std::move(body)) { this->tsw_.obj_ = tsw.obj_; } - SetElement(Storage s, std::string_view key, T *rcdptr, TupleBody&& body, TsWord tsw) - : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { + SetElement(Storage s, std::string_view key, T* rcdptr, TupleBody&& body, + TsWord tsw) + : OpElement::OpElement(s, key, rcdptr), body_(std::move(body)) { this->tsw_.obj_ = tsw.obj_; } - SetElement(Storage s, std::string_view key, T *rcdptr, TsWord tsw, OpType op) - : OpElement::OpElement(s, key, rcdptr, op) { + SetElement(Storage s, std::string_view key, T* rcdptr, TsWord tsw, OpType op) + : OpElement::OpElement(s, key, rcdptr, op) { this->tsw_.obj_ = tsw.obj_; } - bool operator<(const SetElement &right) const { - if (this->storage_ != right.storage_) return this->storage_ < right.storage_; + bool operator<(const SetElement& right) const { + if (this->storage_ != right.storage_) + return this->storage_ < right.storage_; return this->key_ < right.key_; } }; -template +template class GCElement : public OpElement { public: using OpElement::OpElement; uint64_t epoch_; - GCElement(Storage s, std::string_view key, T *rcdptr, uint64_t epoch) - : OpElement::OpElement(s, key, rcdptr) { + GCElement(Storage s, std::string_view key, T* rcdptr, uint64_t epoch) + : OpElement::OpElement(s, key, rcdptr) { this->epoch_ = epoch; } }; diff --git a/cc/tictoc/include/transaction.hh b/cc/tictoc/include/transaction.hh index 53aa57c5..3de28358 100644 --- a/cc/tictoc/include/transaction.hh +++ b/cc/tictoc/include/transaction.hh @@ -28,7 +28,7 @@ enum class TransactionStatus : uint8_t { using namespace std; -extern void write_val_Generator(char *write_val_, size_t val_size, size_t thid); +extern void write_val_Generator(char* write_val_, size_t val_size, size_t thid); class TxScanCallback; @@ -37,24 +37,24 @@ public: int thid_; uint64_t commit_ts_; uint64_t appro_commit_ts_; - Result *result_; + Result* result_; Backoff backoff_; const bool& quit_; // for thread termination control bool reconnoitering_ = false; bool is_batch_ = false; bool is_ronly_ = false; bool is_wonly_ = false; - vector pro_set_; + vector pro_set_; TransactionStatus status_; - vector > read_set_; - vector > write_set_; - std::deque > gc_records_; + vector> read_set_; + vector> write_set_; + std::deque> gc_records_; std::unordered_map node_map_; uint64_t epoch_timer_start, epoch_timer_stop; TxScanCallback callback_; - TxExecutor(int thid, Result *res, const bool &quit) + TxExecutor(int thid, Result* res, const bool& quit) : thid_(thid), result_(res), backoff_(FLAGS_clocks_per_us), quit_(quit), callback_(TxScanCallback(this)) { epoch_timer_start = rdtsc(); @@ -81,7 +81,7 @@ public: */ void dispWS(); - Tuple *get_tuple(Tuple *table, uint64_t key) { return &table[key]; } + Tuple* get_tuple(Tuple* table, uint64_t key) { return &table[key]; } /** * @brief lock records in local write set. @@ -99,7 +99,7 @@ public: * @return true early abort * @return false not abort */ - bool preemptiveAborts(const TsWord &v1); + bool preemptiveAborts(const TsWord& v1); /** * @brief Search xxx set @@ -110,7 +110,7 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - SetElement *searchWriteSet(Storage s, std::string_view key); + SetElement* searchWriteSet(Storage s, std::string_view key); /** * @brief Search xxx set @@ -121,7 +121,7 @@ public: * @param Key [in] the key of key-value * @return Corresponding element of local set */ - SetElement *searchReadSet(Storage s, std::string_view key); + SetElement* searchReadSet(Storage s, std::string_view key); /** * @brief Transaction read function. @@ -130,15 +130,13 @@ public: Status read(Storage s, std::string_view key, TupleBody** body); Status read_internal(Storage s, std::string_view key, Tuple* tuple); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result); + std::vector& result); - Status scan(Storage s, - std::string_view left_key, bool l_exclusive, + Status scan(Storage s, std::string_view left_key, bool l_exclusive, std::string_view right_key, bool r_exclusive, - std::vector&result, int64_t limit); + std::vector& result, int64_t limit); /** * @brief unlock all elements of write set. @@ -174,8 +172,8 @@ public: void gc_records(); - void reconnoiter_begin(); - void reconnoiter_end(); + void reconnoiter_begin(); + void reconnoiter_end(); bool isLeader(); diff --git a/cc/tictoc/include/tuple.hh b/cc/tictoc/include/tuple.hh index 0d47093c..7f4b2695 100644 --- a/cc/tictoc/include/tuple.hh +++ b/cc/tictoc/include/tuple.hh @@ -14,18 +14,18 @@ struct TsWord { union { uint64_t obj_; struct { - bool lock: 1; - bool absent: 1; - uint16_t delta: 15; - uint64_t wts: 47; + bool lock : 1; + bool absent : 1; + uint16_t delta : 15; + uint64_t wts : 47; }; }; TsWord() { obj_ = 0; } - bool operator==(const TsWord &right) const { return obj_ == right.obj_; } + bool operator==(const TsWord& right) const { return obj_ == right.obj_; } - bool operator!=(const TsWord &right) const { return !operator==(right); } + bool operator!=(const TsWord& right) const { return !operator==(right); } bool isLocked() { if (lock) @@ -46,7 +46,8 @@ public: Tuple() {} - void init([[maybe_unused]] size_t thid, TupleBody&& body, [[maybe_unused]] void* p) { + void init([[maybe_unused]] size_t thid, TupleBody&& body, + [[maybe_unused]] void* p) { // for initializer tsw_.obj_ = 0; pre_tsw_.obj_ = 0; diff --git a/cc/tictoc/sbomb_tictoc.cc b/cc/tictoc/sbomb_tictoc.cc index 16cde3de..088c3b26 100644 --- a/cc/tictoc/sbomb_tictoc.cc +++ b/cc/tictoc/sbomb_tictoc.cc @@ -31,10 +31,10 @@ #include "../../include/util.hh" #include "../../include/zipf.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(TicTocResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - StaticBombWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(TicTocResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + StaticBombWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF @@ -58,18 +58,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("BOMB TicToc benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - StaticBombWorkload::displayWorkloadParameter(); - StaticBombWorkload::makeDB(nullptr); + StaticBombWorkload::displayWorkloadParameter(); + StaticBombWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -81,11 +81,9 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { TicTocResult[0].addLocalAllResult(TicTocResult[i]); @@ -98,6 +96,4 @@ int main(int argc, char *argv[]) try { TicTocResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/tictoc/tictoc.cc b/cc/tictoc/tictoc.cc index cce209dd..c7b28efa 100644 --- a/cc/tictoc/tictoc.cc +++ b/cc/tictoc/tictoc.cc @@ -29,14 +29,14 @@ #include "include/transaction.hh" #include "include/util.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { Xoroshiro128Plus rnd; rnd.init(); FastZipf zipf(&rnd, FLAGS_zipf_skew, FLAGS_tuple_num); - Result &myres = std::ref(TicTocResult[thid]); - TxExecutor trans(thid, (Result *) &TicTocResult[thid]); + Result& myres = std::ref(TicTocResult[thid]); + TxExecutor trans(thid, (Result*) &TicTocResult[thid]); #if BACK_OFF Backoff backoff(FLAGS_clocks_per_us); @@ -62,7 +62,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { makeProcedure(trans.pro_set_, rnd, zipf, FLAGS_tuple_num, FLAGS_max_ope, FLAGS_thread_num, FLAGS_rratio, FLAGS_rmw, FLAGS_ycsb, false, thid, myres); -RETRY: + RETRY: #if BACK_OFF if (thid == 0) leaderBackoffWork(std::ref(backoff), TicTocResult); #endif @@ -105,7 +105,7 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TicToc benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); @@ -121,11 +121,9 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { TicTocResult[0].addLocalAllResult(TicTocResult[i]); @@ -135,6 +133,4 @@ int main(int argc, char *argv[]) try { FLAGS_thread_num); return 0; -} catch (bad_alloc) { - ERR; -} +} catch (bad_alloc) { ERR; } diff --git a/cc/tictoc/tpcc_tictoc.cc b/cc/tictoc/tpcc_tictoc.cc index 6ebcea80..71c4a1ed 100644 --- a/cc/tictoc/tpcc_tictoc.cc +++ b/cc/tictoc/tpcc_tictoc.cc @@ -31,10 +31,10 @@ #include "../../include/util.hh" #include "../../include/zipf.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(TicTocResult[thid]); - TxExecutor trans(thid, (Result *) &myres, quit); - TPCCWorkload workload; +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(TicTocResult[thid]); + TxExecutor trans(thid, (Result*) &myres, quit); + TPCCWorkload workload; workload.prepare(trans, nullptr); #if BACK_OFF @@ -58,18 +58,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("TPC-C TicToc benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); - TPCCWorkload::displayWorkloadParameter(); - TPCCWorkload::makeDB(nullptr); + TPCCWorkload::displayWorkloadParameter(); + TPCCWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -81,11 +81,9 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { TicTocResult[0].addLocalAllResult(TicTocResult[i]); @@ -98,6 +96,4 @@ int main(int argc, char *argv[]) try { TicTocResult[0].displayPerTxResult(TxTypes); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/cc/tictoc/transaction.cc b/cc/tictoc/transaction.cc index c0460e7f..2b9f2838 100644 --- a/cc/tictoc/transaction.cc +++ b/cc/tictoc/transaction.cc @@ -16,10 +16,11 @@ using namespace std; extern std::vector TicTocResult; -extern void tictocLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop); +extern void tictocLeaderWork(uint64_t& epoch_timer_start, + uint64_t& epoch_timer_stop); -SetElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { - for (auto &re : read_set_) { +SetElement* TxExecutor::searchReadSet(Storage s, std::string_view key) { + for (auto& re : read_set_) { if (re.storage_ != s) continue; if (re.key_ == key) return &re; } @@ -27,8 +28,8 @@ SetElement *TxExecutor::searchReadSet(Storage s, std::string_view key) { return nullptr; } -SetElement *TxExecutor::searchWriteSet(Storage s, std::string_view key) { - for (auto &we : write_set_) { +SetElement* TxExecutor::searchWriteSet(Storage s, std::string_view key) { + for (auto& we : write_set_) { if (we.storage_ != s) continue; if (we.key_ == key) return &we; } @@ -43,7 +44,7 @@ void TxExecutor::begin() { atomicStoreThLocalEpoch(thid_, atomicLoadGE()); } -bool TxExecutor::preemptiveAborts(const TsWord &v1) { +bool TxExecutor::preemptiveAborts(const TsWord& v1) { if (v1.rts() < this->appro_commit_ts_) { /** * it must check whether this write set include the tuple, @@ -96,7 +97,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { /** * Search tuple from data structure. */ - Tuple *tuple; + Tuple* tuple; tuple = Masstrees[get_storage(s)].get_value(key); #if ADD_ANALYSIS ++result_->local_tree_traversal_; @@ -104,9 +105,7 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { if (tuple == nullptr) return Status::WARN_NOT_FOUND; stat = read_internal(s, key, tuple); - if (stat != Status::OK) { - return stat; - } + if (stat != Status::OK) { return stat; } *body = &(read_set_.back().body_); FINISH_READ: @@ -117,7 +116,8 @@ Status TxExecutor::read(Storage s, std::string_view key, TupleBody** body) { return Status::OK; } -Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) { +Status TxExecutor::read_internal(Storage s, std::string_view key, + Tuple* tuple) { /** * these variable cause error (-fpermissive) * "crosses initialization of ..." @@ -139,14 +139,13 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) continue; } - if (v1.absent) { - return Status::WARN_NOT_FOUND; - } + if (v1.absent) { return Status::WARN_NOT_FOUND; } /** * read payload. */ - b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), tuple->body_.get_val_align()); + b = TupleBody(tuple->body_.get_key(), tuple->body_.get_val(), + tuple->body_.get_val_align()); v2.obj_ = __atomic_load_n(&(tuple->tsw_.obj_), __ATOMIC_ACQUIRE); if (v1 == v2 && !v1.lock) break; @@ -165,28 +164,26 @@ Status TxExecutor::read_internal(Storage s, std::string_view key, Tuple* tuple) return Status::OK; } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result) { return scan(s, left_key, l_exclusive, right_key, r_exclusive, result, -1); } -Status TxExecutor::scan(const Storage s, - std::string_view left_key, bool l_exclusive, - std::string_view right_key, bool r_exclusive, - std::vector& result, int64_t limit) { +Status TxExecutor::scan(const Storage s, std::string_view left_key, + bool l_exclusive, std::string_view right_key, + bool r_exclusive, std::vector& result, + int64_t limit) { result.clear(); auto rset_init_size = read_set_.size(); std::vector scan_res; Masstrees[get_storage(s)].scan( - left_key.empty() ? nullptr : left_key.data(), left_key.size(), - l_exclusive, right_key.empty() ? nullptr : right_key.data(), - right_key.size(), r_exclusive, &scan_res, limit, - callback_); + left_key.empty() ? nullptr : left_key.data(), left_key.size(), + l_exclusive, right_key.empty() ? nullptr : right_key.data(), + right_key.size(), r_exclusive, &scan_res, limit, callback_); - for (auto &&itr : scan_res) { + for (auto&& itr : scan_res) { SetElement* e = searchReadSet(s, itr->body_.get_key()); if (e) { result.emplace_back(&(e->body_)); @@ -200,14 +197,12 @@ Status TxExecutor::scan(const Storage s, } Status stat = read_internal(s, itr->body_.get_key(), itr); - if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { - return stat; - } + if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { return stat; } } if (rset_init_size != read_set_.size()) { - for (auto itr = read_set_.begin() + rset_init_size; - itr != read_set_.end(); ++itr) { + for (auto itr = read_set_.begin() + rset_init_size; itr != read_set_.end(); + ++itr) { result.emplace_back(&((*itr).body_)); } } @@ -230,8 +225,8 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { /** * Search tuple from data structure. */ - Tuple *tuple; - SetElement *re; + Tuple* tuple; + SetElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -245,7 +240,8 @@ Status TxExecutor::update(Storage s, std::string_view key, TupleBody&& body) { tsword.obj_ = __atomic_load_n(&(tuple->tsw_.obj_), __ATOMIC_ACQUIRE); this->appro_commit_ts_ = max(this->appro_commit_ts_, tsword.rts() + 1); - write_set_.emplace_back(s, key, tuple, std::move(body), tsword, OpType::UPDATE); + write_set_.emplace_back(s, key, tuple, std::move(body), tsword, + OpType::UPDATE); FINISH_WRITE:; #if ADD_ANALYSIS @@ -265,22 +261,21 @@ Status TxExecutor::insert(Storage s, std::string_view key, TupleBody&& body) { #if ADD_ANALYSIS ++result_->local_tree_traversal_; #endif - if (tuple != nullptr) { - return Status::WARN_ALREADY_EXISTS; - } + if (tuple != nullptr) { return Status::WARN_ALREADY_EXISTS; } tuple = new Tuple(); tuple->init(std::move(body)); typename MasstreeWrapper::insert_info_t insert_info; - Status stat = Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); + Status stat = + Masstrees[get_storage(s)].insert_value(key, tuple, &insert_info); if (stat == Status::WARN_ALREADY_EXISTS) { delete tuple; return stat; } if (insert_info.node) { if (!node_map_.empty()) { - auto it = node_map_.find((void*)insert_info.node); + auto it = node_map_.find((void*) insert_info.node); if (it != node_map_.end()) { if (unlikely(it->second != insert_info.old_version)) { status_ = TransactionStatus::aborted; @@ -311,13 +306,11 @@ Status TxExecutor::delete_record(Storage s, std::string_view key) { // cancel previous write for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if ((*itr).storage_ != s) continue; - if ((*itr).key_ == key) { - write_set_.erase(itr); - } + if ((*itr).key_ == key) { write_set_.erase(itr); } } - Tuple *tuple; - SetElement *re; + Tuple* tuple; + SetElement* re; re = searchReadSet(s, key); if (re) { tuple = re->rcdptr_; @@ -360,7 +353,7 @@ bool TxExecutor::validationPhase() { * it. */ - asm volatile("":: : "memory"); + asm volatile("" ::: "memory"); // step2, compute the commit timestamp for (auto itr = read_set_.begin(); itr != read_set_.end(); ++itr) { @@ -414,7 +407,7 @@ bool TxExecutor::validationPhase() { return false; } - SetElement *inW = searchWriteSet((*itr).storage_, (*itr).key_); + SetElement* inW = searchWriteSet((*itr).storage_, (*itr).key_); if ((v1.rts()) < commit_ts_ && v1.lock) { if (inW == nullptr) { /** @@ -460,7 +453,7 @@ bool TxExecutor::validationPhase() { } // step 4, validate the node set for (auto it : node_map_) { - auto node = (MasstreeWrapper::node_type *) it.first; + auto node = (MasstreeWrapper::node_type*) it.first; if (node->full_version_value() != it.second) { this->status_ = TransactionStatus::aborted; unlockWriteSet(); @@ -511,10 +504,11 @@ void TxExecutor::writePhase() { switch ((*itr).op_) { case OpType::UPDATE: { result.absent = false; - memcpy((*itr).rcdptr_->body_.get_val_ptr(), - (*itr).body_.get_val_ptr(), (*itr).body_.get_val_size()); + memcpy((*itr).rcdptr_->body_.get_val_ptr(), (*itr).body_.get_val_ptr(), + (*itr).body_.get_val_size()); #if TIMESTAMP_HISTORY - __atomic_store_n(&((*itr).rcdptr_->pre_tsw_.obj_), (*itr).tsw_.obj_, __ATOMIC_RELAXED); + __atomic_store_n(&((*itr).rcdptr_->pre_tsw_.obj_), (*itr).tsw_.obj_, + __ATOMIC_RELAXED); #endif break; } @@ -526,8 +520,10 @@ void TxExecutor::writePhase() { result.absent = true; // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); - gc_records_.emplace_back((*itr).storage_, (*itr).key_, (*itr).rcdptr_, ThLocalEpoch[thid_].obj_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present( + (*itr).key_); + gc_records_.emplace_back((*itr).storage_, (*itr).key_, (*itr).rcdptr_, + ThLocalEpoch[thid_].obj_); break; } default: @@ -536,7 +532,8 @@ void TxExecutor::writePhase() { result.wts = this->commit_ts_; result.delta = 0; result.lock = 0; - __atomic_store_n(&((*itr).rcdptr_->tsw_.obj_), result.obj_, __ATOMIC_RELEASE); + __atomic_store_n(&((*itr).rcdptr_->tsw_.obj_), result.obj_, + __ATOMIC_RELEASE); } gc_records(); @@ -557,12 +554,11 @@ void TxExecutor::lockWriteSet() { */ sort(write_set_.begin(), write_set_.end()); -[[maybe_unused]] retry - : - for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { + [[maybe_unused]] retry + : for (auto itr = write_set_.begin(); itr != write_set_.end(); ++itr) { if (itr->op_ == OpType::INSERT) continue; expected.obj_ = - __atomic_load_n(&((*itr).rcdptr_->tsw_.obj_), __ATOMIC_ACQUIRE); + __atomic_load_n(&((*itr).rcdptr_->tsw_.obj_), __ATOMIC_ACQUIRE); for (;;) { if (expected.lock) { if (this->is_wonly_ == false) { @@ -574,9 +570,7 @@ void TxExecutor::lockWriteSet() { /** * unlock locked record. */ - if (itr != write_set_.begin()) { - unlockWriteSet(itr); - } + if (itr != write_set_.begin()) { unlockWriteSet(itr); } return; #elif NO_WAIT_OF_TICTOC if (itr != write_set_.begin()) unlockWriteSet(itr); @@ -625,7 +619,7 @@ void TxExecutor::lockWriteSet() { /** * end pre-verify */ - sleepTics(FLAGS_clocks_per_us); // sleep 1us. + sleepTics(FLAGS_clocks_per_us); // sleep 1us. if (thid_ == 0) std::cout << "lock retry" << std::endl; goto retry; #endif @@ -708,9 +702,7 @@ void TxExecutor::gc_records() { } } -bool TxExecutor::isLeader() { - return this->thid_ == 0; -} +bool TxExecutor::isLeader() { return this->thid_ == 0; } void TxExecutor::leaderWork() { tictocLeaderWork(this->epoch_timer_start, this->epoch_timer_stop); @@ -719,9 +711,7 @@ void TxExecutor::leaderWork() { #endif } -void TxExecutor::reconnoiter_begin() { - reconnoitering_ = true; -} +void TxExecutor::reconnoiter_begin() { reconnoitering_ = true; } void TxExecutor::reconnoiter_end() { read_set_.clear(); @@ -730,10 +720,11 @@ void TxExecutor::reconnoiter_end() { begin(); } -void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type *n, uint64_t version) { - auto it = tx_->node_map_.find((void*)n); +void TxScanCallback::on_resp_node(const MasstreeWrapper::node_type* n, + uint64_t version) { + auto it = tx_->node_map_.find((void*) n); if (it == tx_->node_map_.end()) { - tx_->node_map_.emplace_hint(it, (void*)n, version); + tx_->node_map_.emplace_hint(it, (void*) n, version); } else if ((*it).second != version) { tx_->status_ = TransactionStatus::aborted; } diff --git a/cc/tictoc/util.cc b/cc/tictoc/util.cc index aa94a015..f194ac7c 100644 --- a/cc/tictoc/util.cc +++ b/cc/tictoc/util.cc @@ -1,8 +1,8 @@ -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include -#include // syscall(SYS_gettid), -#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), +#include // syscall(SYS_gettid), #include #include @@ -42,7 +42,7 @@ void chkArg() { ERR; } - if (posix_memalign((void **) &ThLocalEpoch, CACHE_LINE_SIZE, + if (posix_memalign((void**) &ThLocalEpoch, CACHE_LINE_SIZE, TotalThreadNum * sizeof(uint64_t_64byte)) != 0) ERR; @@ -139,7 +139,7 @@ bool chkEpochLoaded() { return true; } -void tictocLeaderWork(uint64_t &epoch_timer_start, uint64_t &epoch_timer_stop) { +void tictocLeaderWork(uint64_t& epoch_timer_start, uint64_t& epoch_timer_stop) { epoch_timer_stop = rdtscp(); if (chkClkSpan(epoch_timer_start, epoch_timer_stop, FLAGS_gc_epoch_time * FLAGS_clocks_per_us * 1000) && diff --git a/cc/tictoc/ycsb_tictoc.cc b/cc/tictoc/ycsb_tictoc.cc index 9a8b20b8..ad9c114f 100644 --- a/cc/tictoc/ycsb_tictoc.cc +++ b/cc/tictoc/ycsb_tictoc.cc @@ -31,8 +31,8 @@ #include "../../include/ycsb.hh" #include "../../include/zipf.hh" -void worker(size_t thid, char &ready, const bool &start, const bool &quit) { - Result &myres = std::ref(TicTocResult[thid]); +void worker(size_t thid, char& ready, const bool& start, const bool& quit) { + Result& myres = std::ref(TicTocResult[thid]); TxExecutor trans(thid, &myres, quit); YcsbWorkload workload; @@ -57,18 +57,18 @@ void worker(size_t thid, char &ready, const bool &start, const bool &quit) { storeRelease(ready, 1); while (!loadAcquire(start)) _mm_pause(); while (!loadAcquire(quit)) { - workload.run(trans); + workload.run(trans); } return; } -int main(int argc, char *argv[]) try { +int main(int argc, char* argv[]) try { gflags::SetUsageMessage("YCSB TicToc benchmark."); gflags::ParseCommandLineFlags(&argc, &argv, true); chkArg(); YcsbWorkload::displayWorkloadParameter(); - YcsbWorkload::makeDB(nullptr); + YcsbWorkload::makeDB(nullptr); alignas(CACHE_LINE_SIZE) bool start = false; alignas(CACHE_LINE_SIZE) bool quit = false; @@ -80,11 +80,9 @@ int main(int argc, char *argv[]) try { std::ref(quit)); waitForReady(readys); storeRelease(start, true); - for (size_t i = 0; i < FLAGS_extime; ++i) { - sleepMs(1000); - } + for (size_t i = 0; i < FLAGS_extime; ++i) { sleepMs(1000); } storeRelease(quit, true); - for (auto &th : thv) th.join(); + for (auto& th : thv) th.join(); for (unsigned int i = 0; i < FLAGS_thread_num; ++i) { TicTocResult[0].addLocalAllResult(TicTocResult[i]); @@ -94,6 +92,4 @@ int main(int argc, char *argv[]) try { FLAGS_thread_num); return 0; -} catch (const bad_alloc&) { - ERR; -} +} catch (const bad_alloc&) { ERR; } diff --git a/common/result.cc b/common/result.cc index 11d1d8bc..2101ac33 100644 --- a/common/result.cc +++ b/common/result.cc @@ -38,14 +38,16 @@ void Result::displayCommitCounts() { } void Result::displayTps(size_t extime, size_t thread_num) { - uint64_t result = (total_commit_counts_ + total_batch_commit_counts_) / extime; + uint64_t result = + (total_commit_counts_ + total_batch_commit_counts_) / extime; cout << "latency[ns]:\t" << powl(10.0, 9.0) / result * thread_num << endl; cout << "throughput[tps]:\t" << result << endl; } void Result::displayOps(size_t extime, size_t op_num, size_t batch_op_num) { - uint64_t result = (total_commit_counts_*op_num - + total_batch_commit_counts_*batch_op_num) / extime; + uint64_t result = (total_commit_counts_ * op_num + + total_batch_commit_counts_ * batch_op_num) / + extime; cout << "throughput[ops]:\t" << result << endl; } @@ -53,8 +55,8 @@ void Result::displayOps(size_t extime, size_t op_num, size_t batch_op_num) { void Result::displayAbortByOperationRate() { if (total_abort_by_operation_) { long double rate; - rate = (long double)total_abort_by_operation_ / - (long double)total_abort_counts_; + rate = (long double) total_abort_by_operation_ / + (long double) total_abort_counts_; cout << "abort_by_operation:\t" << total_abort_by_operation_ << endl; cout << fixed << setprecision(4) << "abort_by_operation_rate:\t" << rate << endl; @@ -64,7 +66,7 @@ void Result::displayAbortByOperationRate() { void Result::displayAbortByValidationRate() { if (total_abort_by_validation_) { long double rate; - rate = (double)total_abort_by_validation_ / (double)total_abort_counts_; + rate = (double) total_abort_by_validation_ / (double) total_abort_counts_; cout << "abort_by_validation:\t" << total_abort_by_validation_ << endl; cout << fixed << setprecision(4) << "abort_by_validation_rate:\t" << rate << endl; @@ -72,15 +74,14 @@ void Result::displayAbortByValidationRate() { } void Result::displayAbortLatencyRate(size_t clocks_per_us, size_t extime, - size_t thread_num) { + size_t thread_num) { if (total_abort_latency_) { long double rate; rate = - (long double)total_abort_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_abort_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; - cout << fixed << setprecision(4) << "abort_latency_rate:\t" << rate - << endl; + cout << fixed << setprecision(4) << "abort_latency_rate:\t" << rate << endl; } } @@ -89,8 +90,8 @@ void Result::displayCommitLatencyRate(size_t clocks_per_us, size_t extime, if (total_commit_latency_) { long double rate; rate = - (long double)total_commit_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_commit_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "commit_latency_rate:\t" << rate << endl; @@ -102,8 +103,8 @@ void Result::displayBackoffLatencyRate(size_t clocks_per_us, size_t extime, if (total_backoff_latency_) { long double rate; rate = - (long double)total_backoff_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_backoff_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "backoff_latency_rate:\t" << rate << endl; @@ -113,7 +114,8 @@ void Result::displayBackoffLatencyRate(size_t clocks_per_us, size_t extime, void Result::displayEarlyAbortRate() { if (total_early_aborts_) { cout << fixed << setprecision(4) << "early_abort_rate:\t" - << (long double)total_early_aborts_ / (long double)total_abort_counts_ + << (long double) total_early_aborts_ / + (long double) total_abort_counts_ << endl; } } @@ -131,8 +133,8 @@ void Result::displayGCLatencyRate(size_t clocks_per_us, size_t extime, if (total_gc_latency_) { long double rate; rate = - (long double)total_gc_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_gc_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "gc_latency_rate:\t" << rate << endl; } @@ -154,8 +156,8 @@ void Result::displayMakeProcedureLatencyRate(size_t clocks_per_us, if (total_make_procedure_latency_) { long double rate; rate = - (long double)total_make_procedure_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_make_procedure_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "make_procedure_latency_rate:\t" << rate << endl; @@ -163,9 +165,7 @@ void Result::displayMakeProcedureLatencyRate(size_t clocks_per_us, } void Result::displayMemcpys() { - if (total_memcpys) { - cout << "memcpys:\t" << total_memcpys << endl; - } + if (total_memcpys) { cout << "memcpys:\t" << total_memcpys << endl; } } void Result::displayOtherWorkLatencyRate(size_t clocks_per_us, size_t extime, @@ -174,44 +174,44 @@ void Result::displayOtherWorkLatencyRate(size_t clocks_per_us, size_t extime, if (total_make_procedure_latency_) { sum_rate += - (long double)total_make_procedure_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_make_procedure_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_read_latency_) { sum_rate += - (long double)total_read_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_read_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_write_latency_) { sum_rate += - (long double)total_write_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_write_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_vali_latency_) { sum_rate += - (long double)total_vali_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_vali_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_abort_latency_) { sum_rate += - (long double)total_abort_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_abort_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_gc_latency_) { sum_rate += - (long double)total_gc_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_gc_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } if (total_commit_latency_) { sum_rate += - (long double)total_commit_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_commit_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; } @@ -229,7 +229,7 @@ void Result::displayRatioOfPreemptiveAbortToTotalAbort() { if (total_preemptive_aborts_counts_) { long double rate; rate = - (double)total_preemptive_aborts_counts_ / (double)total_abort_counts_; + (double) total_preemptive_aborts_counts_ / (double) total_abort_counts_; cout << fixed << setprecision(4) << "ratio_of_preemptive_abort_to_total_abort:\t" << rate << endl; } @@ -240,8 +240,8 @@ void Result::displayReadLatencyRate(size_t clocks_per_us, size_t extime, if (total_read_latency_) { long double rate; rate = - (long double)total_read_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_read_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "read_latency_rate:\t" << rate << endl; } @@ -250,8 +250,8 @@ void Result::displayReadLatencyRate(size_t clocks_per_us, size_t extime, void Result::displayRtsupdRate() { if (total_rtsupd_chances_) { long double rate; - rate = (double)total_rtsupd_ / - ((double)total_rtsupd_ + (double)total_rtsupd_chances_); + rate = (double) total_rtsupd_ / + ((double) total_rtsupd_ + (double) total_rtsupd_chances_); cout << fixed << setprecision(4) << "rtsupd_rate:\t" << rate << endl; } } @@ -293,8 +293,8 @@ void Result::displayValiLatencyRate(size_t clocks_per_us, size_t extime, if (total_vali_latency_) { long double rate; rate = - (long double)total_vali_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_vali_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "vali_latency_rate:\t" << rate << endl; } @@ -303,8 +303,8 @@ void Result::displayValiLatencyRate(size_t clocks_per_us, size_t extime, void Result::displayValidationFailureByTidRate() { if (total_validation_failure_by_tid_) { long double rate; - rate = (double)total_validation_failure_by_tid_ / - (double)total_abort_by_validation_; + rate = (double) total_validation_failure_by_tid_ / + (double) total_abort_by_validation_; cout << "validation_failure_by_tid:\t" << total_validation_failure_by_tid_ << endl; cout << fixed << setprecision(4) << "validation_failure_by_tid_rate:\t" @@ -315,8 +315,8 @@ void Result::displayValidationFailureByTidRate() { void Result::displayValidationFailureByWritelockRate() { if (total_validation_failure_by_writelock_) { long double rate; - rate = (double)total_validation_failure_by_writelock_ / - (double)total_abort_by_validation_; + rate = (double) total_validation_failure_by_writelock_ / + (double) total_abort_by_validation_; cout << "validation_failure_by_writelock:\t" << total_validation_failure_by_writelock_ << endl; cout << fixed << setprecision(4) @@ -338,65 +338,71 @@ void Result::displayWriteLatencyRate(size_t clocks_per_us, size_t extime, if (total_write_latency_) { long double rate; rate = - (long double)total_write_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_write_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; cout << fixed << setprecision(4) << "write_latency_rate:\t" << rate << endl; } } -void Result::displayReadValidationRate(size_t clocks_per_us, size_t extime, size_t thread_num) { +void Result::displayReadValidationRate(size_t clocks_per_us, size_t extime, + size_t thread_num) { if (total_read_validation_latency_) { long double rate; rate = - (long double)total_read_validation_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_read_validation_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; - cout << fixed << setprecision(4) << "read_validation_lat_rate:\t" << rate << endl; + cout << fixed << setprecision(4) << "read_validation_lat_rate:\t" << rate + << endl; } } -void Result::displayWriteValidationRate(size_t clocks_per_us, size_t extime, size_t thread_num) { +void Result::displayWriteValidationRate(size_t clocks_per_us, size_t extime, + size_t thread_num) { if (total_write_validation_latency_) { long double rate; rate = - (long double)total_write_validation_latency_ / - ((long double)clocks_per_us * powl(10.0, 6.0) * (long double)extime) / + (long double) total_write_validation_latency_ / + ((long double) clocks_per_us * powl(10.0, 6.0) * (long double) extime) / thread_num; - cout << fixed << setprecision(4) << "write_validation_lat_rate:\t" << rate << endl; + cout << fixed << setprecision(4) << "write_validation_lat_rate:\t" << rate + << endl; } } void Result::displayPropagatePages() { uint64_t num_txns = total_commit_counts_ + total_abort_counts_; if (total_propagate_pages_) { - long double n = (long double)total_propagate_pages_/(long double)num_txns; + long double n = + (long double) total_propagate_pages_ / (long double) num_txns; cout << fixed << setprecision(2) << "propagate_pages_per_tx: " << n << endl; } } void Result::displayGraphSize() { if (total_graph_size_ && total_cycle_check_count_) { - long double n = (long double)total_graph_size_/(long double)total_cycle_check_count_; - cout << fixed << setprecision(2) << "avg_graph_size_in_cycle_check: " << n << endl; + long double n = (long double) total_graph_size_ / + (long double) total_cycle_check_count_; + cout << fixed << setprecision(2) << "avg_graph_size_in_cycle_check: " << n + << endl; } } void Result::displayCycleCheckCount() { uint64_t num_txns = total_commit_counts_ + total_abort_counts_; if (total_cycle_check_count_) { - long double n = (long double)total_cycle_check_count_/(long double)num_txns; + long double n = + (long double) total_cycle_check_count_ / (long double) num_txns; cout << fixed << setprecision(2) << "cycle_check_per_tx: " << n << endl; } } void Result::displayForwardingCount() { uint64_t num_txns = total_commit_counts_ + total_abort_counts_; - auto n = - total_forwarding1_count_; // / (long double)num_txns; + auto n = total_forwarding1_count_; // / (long double)num_txns; cout << "1st_forwarding_count: " << n << endl; - auto m = - total_forwarding2_count_; // / (long double)num_txns; + auto m = total_forwarding2_count_; // / (long double)num_txns; cout << "2nd_forwarding_count: " << m << endl; } #endif @@ -535,13 +541,27 @@ void Result::addLocalWriteLatency(const uint64_t count) { } // only for oze -void Result::addLocalReadValidationLatency(const uint64_t count) { total_read_validation_latency_ += count; } -void Result::addLocalWriteValidationLatency(const uint64_t count) { total_write_validation_latency_ += count; } -void Result::addLocalPropagatePages(const uint64_t count) { total_propagate_pages_ += count; } -void Result::addLocalGraphSize(const uint64_t count) { total_graph_size_ += count; } -void Result::addLocalCycleCheckCount(const uint64_t count) { total_cycle_check_count_ += count; } -void Result::addLocalForwarding1Count(const uint64_t count) { total_forwarding1_count_ += count; } -void Result::addLocalForwarding2Count(const uint64_t count) { total_forwarding1_count_ += count; } +void Result::addLocalReadValidationLatency(const uint64_t count) { + total_read_validation_latency_ += count; +} +void Result::addLocalWriteValidationLatency(const uint64_t count) { + total_write_validation_latency_ += count; +} +void Result::addLocalPropagatePages(const uint64_t count) { + total_propagate_pages_ += count; +} +void Result::addLocalGraphSize(const uint64_t count) { + total_graph_size_ += count; +} +void Result::addLocalCycleCheckCount(const uint64_t count) { + total_cycle_check_count_ += count; +} +void Result::addLocalForwarding1Count(const uint64_t count) { + total_forwarding1_count_ += count; +} +void Result::addLocalForwarding2Count(const uint64_t count) { + total_forwarding1_count_ += count; +} #endif void Result::displayOzeAnalysisResult([[maybe_unused]] size_t clocks_per_us, @@ -604,8 +624,7 @@ void Result::displayAllResult([[maybe_unused]] size_t clocks_per_us, } void Result::displayAllResult([[maybe_unused]] size_t clocks_per_us, - size_t extime, - [[maybe_unused]] size_t thread_num, + size_t extime, [[maybe_unused]] size_t thread_num, size_t op_num, size_t batch_op_num) { #if ADD_ANALYSIS displayAbortByOperationRate(); @@ -648,7 +667,7 @@ void Result::displayAllResult([[maybe_unused]] size_t clocks_per_us, displayOps(extime, op_num, batch_op_num); } -void Result::addLocalAllResult(const Result &other) { +void Result::addLocalAllResult(const Result& other) { addLocalAbortCounts(other.local_abort_counts_); addLocalBatchAbortCounts(other.local_batch_abort_counts_); addLocalCommitCounts(other.local_commit_counts_); @@ -698,41 +717,46 @@ void Result::addLocalAllResult(const Result &other) { #endif } -void Result::displayPerTxResult(std::map tx_types) { +void Result::displayPerTxResult(std::map tx_types) { for (auto& [type, name] : tx_types) { long double rate = (double) total_abort_counts_per_tx_[type] / - (double) (total_commit_counts_per_tx_[type] + total_abort_counts_per_tx_[type]); + (double) (total_commit_counts_per_tx_[type] + + total_abort_counts_per_tx_[type]); long double latency; if (total_commit_counts_per_tx_[type]) { - latency = (double) total_latency_per_tx_[type] / (double) total_commit_counts_per_tx_[type]; + latency = (double) total_latency_per_tx_[type] / + (double) total_commit_counts_per_tx_[type]; } else { latency = 0; } std::cout << " Transaction type: " << name << std::endl; - std::cout << " commits: " << total_commit_counts_per_tx_[type] << std::endl; - std::cout << " aborts: " << total_abort_counts_per_tx_[type] << std::endl; - std::cout << " abort rate: " << std::fixed << setprecision(4) << rate << std::endl; - std::cout << " latency[us]: " << std::fixed << setprecision(2) << latency << std::endl; + std::cout << " commits: " << total_commit_counts_per_tx_[type] + << std::endl; + std::cout << " aborts: " << total_abort_counts_per_tx_[type] + << std::endl; + std::cout << " abort rate: " << std::fixed << setprecision(4) << rate + << std::endl; + std::cout << " latency[us]: " << std::fixed << setprecision(2) << latency + << std::endl; } std::cout << " Summary: "; for (auto& [type, name] : tx_types) { - std::cout << total_commit_counts_per_tx_[type] - << "," - << total_abort_counts_per_tx_[type] - << ","; + std::cout << total_commit_counts_per_tx_[type] << "," + << total_abort_counts_per_tx_[type] << ","; } std::cout << std::endl; std::cout << " All transaction total latencies: "; for (auto& [type, name] : tx_types) { - std::cout << total_latency_per_tx_[type] - << ","; + std::cout << total_latency_per_tx_[type] << ","; } std::cout << std::endl; } -void Result::addLocalPerTxResult(const Result &other, std::map tx_types) { +void Result::addLocalPerTxResult(const Result& other, + std::map tx_types) { for (auto& [type, name] : tx_types) { - total_commit_counts_per_tx_[type] += other.local_commit_counts_per_tx_[type]; + total_commit_counts_per_tx_[type] += + other.local_commit_counts_per_tx_[type]; total_abort_counts_per_tx_[type] += other.local_abort_counts_per_tx_[type]; total_latency_per_tx_[type] += other.local_latency_per_tx_[type]; } diff --git a/common/util.cc b/common/util.cc index efcac77a..83ab6682 100644 --- a/common/util.cc +++ b/common/util.cc @@ -2,7 +2,7 @@ #include "./../include/atomic_wrapper.hh" #include "./../include/util.hh" -bool chkSpan(struct timeval &start, struct timeval &stop, long threshold) { +bool chkSpan(struct timeval& start, struct timeval& stop, long threshold) { long diff = 0; diff += (stop.tv_sec - start.tv_sec) * 1000 * 1000 + (stop.tv_usec - start.tv_usec); @@ -18,9 +18,7 @@ size_t decideParallelBuildNumber(size_t tuple_num) { // else for (size_t i = std::thread::hardware_concurrency(); i > 0; --i) { - if (tuple_num % i == 0) { - return i; - } + if (tuple_num % i == 0) { return i; } if (i == 1) ERR; } @@ -44,32 +42,30 @@ size_t decideParallelBuildNumber(size_t tuple_num) { // } void displayRusageRUMaxrss() { - struct rusage r{}; + struct rusage r {}; if (getrusage(RUSAGE_SELF, &r) != 0) ERR; printf("maxrss:\t%ld kB\n", r.ru_maxrss); } -void readyAndWaitForReadyOfAllThread(std::atomic &running, +void readyAndWaitForReadyOfAllThread(std::atomic& running, const size_t thnm) { running++; while (running.load(std::memory_order_acquire) != thnm) _mm_pause(); } -void waitForReadyOfAllThread(std::atomic &running, const size_t thnm) { +void waitForReadyOfAllThread(std::atomic& running, const size_t thnm) { while (running.load(std::memory_order_acquire) != thnm) _mm_pause(); } -bool isReady(const std::vector &readys) { - for (const char &b : readys) { +bool isReady(const std::vector& readys) { + for (const char& b : readys) { if (!loadAcquire(b)) return false; } return true; } -void waitForReady(const std::vector &readys) { - while (!isReady(readys)) { - _mm_pause(); - } +void waitForReady(const std::vector& readys) { + while (!isReady(readys)) { _mm_pause(); } } void sleepMs(size_t ms) { diff --git a/include/atomic_wrapper.hh b/include/atomic_wrapper.hh index bfe1fa32..9e0cfdae 100644 --- a/include/atomic_wrapper.hh +++ b/include/atomic_wrapper.hh @@ -9,67 +9,67 @@ /** * @brief atomic relaxed load. */ -template -[[maybe_unused]] static T load(T &ptr) { +template +[[maybe_unused]] static T load(T& ptr) { return __atomic_load_n(&ptr, __ATOMIC_RELAXED); } -template -[[maybe_unused]] static T load(T *ptr) { +template +[[maybe_unused]] static T load(T* ptr) { return __atomic_load_n(ptr, __ATOMIC_RELAXED); } -template -[[maybe_unused]] static T loadRelaxed(T &ptr) { +template +[[maybe_unused]] static T loadRelaxed(T& ptr) { return __atomic_load_n(&ptr, __ATOMIC_RELAXED); } -template -[[maybe_unused]] static T loadRelaxed(T *ptr) { +template +[[maybe_unused]] static T loadRelaxed(T* ptr) { return __atomic_load_n(ptr, __ATOMIC_RELAXED); } -template -static T loadAcquire(T &ptr) { +template +static T loadAcquire(T& ptr) { return __atomic_load_n(&ptr, __ATOMIC_ACQUIRE); } /** * @brief atomic relaxed store. */ -template -[[maybe_unused]] static void store(T &ptr, T2 val) { +template +[[maybe_unused]] static void store(T& ptr, T2 val) { __atomic_store_n(&ptr, (T) val, __ATOMIC_RELAXED); } -template -[[maybe_unused]] static void storeRelaxed(T &ptr, T2 val) { - __atomic_store_n(&ptr, (T) val, __ATOMIC_RELAXED); // NOLINT +template +[[maybe_unused]] static void storeRelaxed(T& ptr, T2 val) { + __atomic_store_n(&ptr, (T) val, __ATOMIC_RELAXED); // NOLINT } -template -[[maybe_unused]] static void storeRelaxed(T *ptr, T2 val) { - __atomic_store_n(ptr, (T) val, __ATOMIC_RELAXED); // NOLINT +template +[[maybe_unused]] static void storeRelaxed(T* ptr, T2 val) { + __atomic_store_n(ptr, (T) val, __ATOMIC_RELAXED); // NOLINT } /** * @brief atomic release store. */ -template -static void storeRelease(T &ptr, T2 val) { - __atomic_store_n(&ptr, (T) val, __ATOMIC_RELEASE); // NOLINT +template +static void storeRelease(T& ptr, T2 val) { + __atomic_store_n(&ptr, (T) val, __ATOMIC_RELEASE); // NOLINT } /** * @brief atomic acq-rel cas. */ -template -static bool compareExchange(T &m, T &before, T2 after) { +template +static bool compareExchange(T& m, T& before, T2 after) { return __atomic_compare_exchange_n(&m, &before, (T) after, false, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); } -template -static Int1 fetchAdd(Int1 &m, Int2 v, int memorder = __ATOMIC_ACQ_REL) { +template +static Int1 fetchAdd(Int1& m, Int2 v, int memorder = __ATOMIC_ACQ_REL) { return __atomic_fetch_add(&m, v, memorder); } diff --git a/include/backoff.hh b/include/backoff.hh index b8c97982..3db8c08f 100644 --- a/include/backoff.hh +++ b/include/backoff.hh @@ -27,9 +27,7 @@ public: uint64_t last_time_ = 0; size_t clocks_per_us_; - Backoff(size_t clocks_per_us) { - init(clocks_per_us); - } + Backoff(size_t clocks_per_us) { init(clocks_per_us); } void init(size_t clocks_per_us) { last_time_ = rdtscp(); @@ -80,7 +78,7 @@ public: new_backoff += kIncrBackoff; else { if ((committed_txs & 1) == 0 || - new_backoff == kMaxBackoff) // 確率はおよそ 1/2, すなわちランダム. + new_backoff == kMaxBackoff) // 確率はおよそ 1/2, すなわちランダム. new_backoff -= kIncrBackoff; else if ((committed_txs & 1) == 1 || new_backoff == kMinBackoff) new_backoff += kIncrBackoff; @@ -111,10 +109,11 @@ public: }; [[maybe_unused]] inline void -leaderBackoffWork([[maybe_unused]] Backoff &backoff, [[maybe_unused]] std::vector &res) { +leaderBackoffWork([[maybe_unused]] Backoff& backoff, + [[maybe_unused]] std::vector& res) { if (backoff.check_update_backoff()) { uint64_t sum_committed_txs(0); - for (auto &th : res) { + for (auto& th : res) { sum_committed_txs += loadAcquire(th.local_commit_counts_); } backoff.update_backoff(sum_committed_txs); diff --git a/include/bomb.hh b/include/bomb.hh index cf54d423..5c77aca2 100644 --- a/include/bomb.hh +++ b/include/bomb.hh @@ -20,11 +20,17 @@ #include "gflags/gflags.h" #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint32(bomb_l1_thread_num, 1, "Number of threads for batch (update-product-cost-master) transaction"); -DEFINE_uint32(bomb_s1_thread_num, 1, "Number of threads for update-material-cost-master transaction"); -DEFINE_uint32(bomb_s2_thread_num, 1, "Number of threads for issue-journal-voucher transaction"); -DEFINE_uint32(bomb_s3_thread_num, 0, "Number of threads for add-new-product transaction"); -DEFINE_uint32(bomb_s4_thread_num, 0, "Number of threads for change-raw-material transaction"); +DEFINE_uint32( + bomb_l1_thread_num, 1, + "Number of threads for batch (update-product-cost-master) transaction"); +DEFINE_uint32(bomb_s1_thread_num, 1, + "Number of threads for update-material-cost-master transaction"); +DEFINE_uint32(bomb_s2_thread_num, 1, + "Number of threads for issue-journal-voucher transaction"); +DEFINE_uint32(bomb_s3_thread_num, 0, + "Number of threads for add-new-product transaction"); +DEFINE_uint32(bomb_s4_thread_num, 0, + "Number of threads for change-raw-material transaction"); DEFINE_uint32(bomb_mixed_short_rate, 500, "Request rate of short transactions"); DEFINE_bool(bomb_mixed_short_rate_tps, false, "Use request rate as per-second"); DEFINE_bool(bomb_mixed_mode, false, "Enable mixed-workload mode"); @@ -43,26 +49,27 @@ DEFINE_uint64(bomb_perc_s4, 0, "The percentage of S4 transactions"); DEFINE_uint32(bomb_req_batch_size, 1, "Request batch size"); DEFINE_uint32(bomb_factory_size, 8, "Total number of factories"); DEFINE_uint32(bomb_product_size, 72000, "Total number of finished products"); -DEFINE_uint32(bomb_work_size, 198000, "Total number of root work in progress (root WIP)"); +DEFINE_uint32(bomb_work_size, 198000, + "Total number of root work in progress (root WIP)"); DEFINE_uint32(bomb_material_size, 75000, "Total number of raw materials"); DEFINE_uint32(bomb_tree_num_per_product, 5, ""); DEFINE_uint32(bomb_base_tree_size, 10, ""); DEFINE_uint32(bomb_material_per_wip, 3, ""); DEFINE_uint32(bomb_base_product_size_per_factory, 100, ""); -DEFINE_uint32(bomb_mc_update_size, 1, "Number of update materials in update-material-cost-master transaction"); -DEFINE_uint32(bomb_interactive_ms, 0, "Sleep microseconds per SQL(-equivalent) unit"); +DEFINE_uint32( + bomb_mc_update_size, 1, + "Number of update materials in update-material-cost-master transaction"); +DEFINE_uint32(bomb_interactive_ms, 0, + "Sleep microseconds per SQL(-equivalent) unit"); #else DECLARE_uint32(bomb_l1_thread_num); DECLARE_uint32(bomb_s1_thread_num); DECLARE_uint32(bomb_s2_thread_num); DECLARE_uint32(bomb_s3_thread_num); DECLARE_uint32(bomb_s4_thread_num); -DECLARE_uint32(bomb_mixed_short_rate) -DECLARE_bool(bomb_mixed_short_rate_tps) -DECLARE_bool(bomb_mixed_mode) -DECLARE_bool(bomb_use_cache) -DECLARE_bool(bomb_rate_control) -DECLARE_uint32(bomb_l1_rate); +DECLARE_uint32(bomb_mixed_short_rate) DECLARE_bool(bomb_mixed_short_rate_tps) + DECLARE_bool(bomb_mixed_mode) DECLARE_bool(bomb_use_cache) + DECLARE_bool(bomb_rate_control) DECLARE_uint32(bomb_l1_rate); DECLARE_uint32(bomb_s1_rate); DECLARE_uint32(bomb_s2_rate); DECLARE_uint32(bomb_s3_rate); @@ -89,7 +96,7 @@ DECLARE_uint32(bomb_interactive_ms); typedef std::chrono::high_resolution_clock::time_point timepoint; GLOBAL std::atomic ItemIdCounter; -GLOBAL ConcurrentQueue> *requestQueues; +GLOBAL ConcurrentQueue>* requestQueues; enum class Storage : std::uint32_t { ItemConstructionMaster = 0, @@ -111,81 +118,84 @@ enum class TxType : std::uint32_t { }; struct ItemConstructionMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t ic_parent_i_id; + alignas(CACHE_LINE_SIZE) std::uint32_t ic_parent_i_id; std::uint32_t ic_i_id; double ic_material_quantity; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t ic_parent_i_id, uint32_t ic_i_id, char *out) { + static void CreateKey(uint32_t ic_parent_i_id, uint32_t ic_i_id, char* out) { assign_as_bigendian(ic_parent_i_id, &out[0]); assign_as_bigendian(ic_i_id, &out[4]); } - void createKey(char *out) const { return CreateKey(ic_parent_i_id, ic_i_id, out); } + void createKey(char* out) const { + return CreateKey(ic_parent_i_id, ic_i_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct MaterialCostMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t mc_f_id; // factory - std::uint32_t mc_i_id; // item + alignas(CACHE_LINE_SIZE) std::uint32_t mc_f_id; // factory + std::uint32_t mc_i_id; // item double mc_stock_quantity; double mc_stock_price; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t mc_f_id, uint32_t mc_i_id, char *out) { + static void CreateKey(uint32_t mc_f_id, uint32_t mc_i_id, char* out) { assign_as_bigendian(mc_f_id, &out[0]); assign_as_bigendian(mc_i_id, &out[4]); } - void createKey(char *out) const { return CreateKey(mc_f_id, mc_i_id, out); } + void createKey(char* out) const { return CreateKey(mc_f_id, mc_i_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ItemManufacturingMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t im_factory_id; + alignas(CACHE_LINE_SIZE) std::uint32_t im_factory_id; std::uint32_t im_product_id; double im_quantity; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t im_factory_id, uint32_t im_product_id, char *out) { + static void CreateKey(uint32_t im_factory_id, uint32_t im_product_id, + char* out) { assign_as_bigendian(im_factory_id, &out[0]); assign_as_bigendian(im_product_id, &out[4]); } - void createKey(char *out) const { return CreateKey(im_factory_id, im_product_id, out); } + void createKey(char* out) const { + return CreateKey(im_factory_id, im_product_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ProductCostMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t pc_factory_id; + alignas(CACHE_LINE_SIZE) std::uint32_t pc_factory_id; std::uint32_t pc_product_id; double pc_cost; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t pc_factory_id, uint32_t pc_product_id, char *out) { + static void CreateKey(uint32_t pc_factory_id, uint32_t pc_product_id, + char* out) { assign_as_bigendian(pc_factory_id, &out[0]); assign_as_bigendian(pc_product_id, &out[4]); } - void createKey(char *out) const { return CreateKey(pc_factory_id, pc_product_id, out); } + void createKey(char* out) const { + return CreateKey(pc_factory_id, pc_product_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct JournalVoucher { - alignas(CACHE_LINE_SIZE) - std::uint64_t jv_voucher_id; + alignas(CACHE_LINE_SIZE) std::uint64_t jv_voucher_id; std::uint64_t jv_date; std::uint32_t jv_debit; std::uint32_t jv_credit; @@ -193,11 +203,11 @@ struct JournalVoucher { //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint64_t jv_voucher_id, char *out) { + static void CreateKey(uint64_t jv_voucher_id, char* out) { assign_as_bigendian(jv_voucher_id, &out[0]); } - void createKey(char *out) const { return CreateKey(jv_voucher_id, out); } + void createKey(char* out) const { return CreateKey(jv_voucher_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; @@ -222,41 +232,26 @@ public: void assign_id(std::atomic& i_id) { // skip root WIP to assign i_id in reserved range (<= FLAGS_bomb_work_size) - if (parent_ != nullptr) - i_id_ = i_id++; - for (auto& child : childs_) { - child->assign_id(i_id); - } + if (parent_ != nullptr) i_id_ = i_id++; + for (auto& child : childs_) { child->assign_id(i_id); } } - bool is_leaf() { - return childs_.empty(); - } + bool is_leaf() { return childs_.empty(); } - void get_all_nodes(std::vector& nodes) { - collect_nodes(nodes); - } + void get_all_nodes(std::vector& nodes) { collect_nodes(nodes); } void collect_nodes(std::vector& nodes) { nodes.push_back(this); - for (auto& child : childs_) { - child->collect_nodes(nodes); - } + for (auto& child : childs_) { child->collect_nodes(nodes); } } void get_all_leafs(std::vector& nodes) { - for (auto& child : childs_) { - child->collect_leafs(nodes); - } + for (auto& child : childs_) { child->collect_leafs(nodes); } } void collect_leafs(std::vector& nodes) { - if (this->is_leaf()) { - nodes.push_back(this); - } - for (auto& child : childs_) { - child->collect_nodes(nodes); - } + if (this->is_leaf()) { nodes.push_back(this); } + for (auto& child : childs_) { child->collect_nodes(nodes); } } double calculate_cost() { @@ -265,9 +260,7 @@ public: return unit_cost_ * quantity_; } double subtotal = 0; - for (auto& child : childs_) { - subtotal += child->calculate_cost(); - } + for (auto& child : childs_) { subtotal += child->calculate_cost(); } // std::cout << "subtotal: [" << i_id_ << "] " << subtotal << std::endl; return subtotal * quantity_; } @@ -277,1167 +270,1224 @@ struct JVID { union { uint64_t obj_; struct { - uint64_t thid: 8; - uint64_t vid: 56; + uint64_t thid : 8; + uint64_t vid : 56; }; }; - JVID() : obj_(0) {}; + JVID() : obj_(0){}; }; template class BombWorkload { public: - Param* param_; - Xoroshiro128Plus rnd_; - uint64_t jv_counter_ = 0; - std::vector s3_counters_; // to stabilize # of target products for L1 - uint32_t i_id_wip_end_; - uint32_t s5_thread_num; - std::map bom_cache_; - - BombWorkload() { - rnd_.init(); - - if (!FLAGS_bomb_mixed_mode) { - uint64_t total_threads = FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num; - if (FLAGS_bomb_l1_thread_num && FLAGS_thread_num < total_threads) { - std::cerr << "Total number of threads must be " << FLAGS_thread_num << std::endl; - ERR; - } - s5_thread_num = FLAGS_thread_num - ( - FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num); - } - - s3_counters_.resize(FLAGS_bomb_factory_size, 0); + Param* param_; + Xoroshiro128Plus rnd_; + uint64_t jv_counter_ = 0; + std::vector + s3_counters_; // to stabilize # of target products for L1 + uint32_t i_id_wip_end_; + uint32_t s5_thread_num; + std::map bom_cache_; + + BombWorkload() { + rnd_.init(); + + if (!FLAGS_bomb_mixed_mode) { + uint64_t total_threads = + FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num; + if (FLAGS_bomb_l1_thread_num && FLAGS_thread_num < total_threads) { + std::cerr << "Total number of threads must be " << FLAGS_thread_num + << std::endl; + ERR; + } + s5_thread_num = FLAGS_thread_num - + (FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num); } - static std::chrono::nanoseconds get_request_interval_nano() { - // use FLAGS_bomb_mixed_short_rate as request per seconds - return std::chrono::nanoseconds(1000*1000*1000/FLAGS_bomb_mixed_short_rate); - } + s3_counters_.resize(FLAGS_bomb_factory_size, 0); + } + + static std::chrono::nanoseconds get_request_interval_nano() { + // use FLAGS_bomb_mixed_short_rate as request per seconds + return std::chrono::nanoseconds(1000 * 1000 * 1000 / + FLAGS_bomb_mixed_short_rate); + } - static std::chrono::microseconds get_request_interval_micro() { - // use FLAGS_bomb_mixed_short_rate as request per minute - return std::chrono::microseconds(60*1000*1000/FLAGS_bomb_mixed_short_rate); + static std::chrono::microseconds get_request_interval_micro() { + // use FLAGS_bomb_mixed_short_rate as request per minute + return std::chrono::microseconds(60 * 1000 * 1000 / + FLAGS_bomb_mixed_short_rate); + } + + std::chrono::microseconds get_request_interval(TxType type) { + uint32_t rate; + switch (type) { + case TxType::UpdateProductCostMaster: + // L1 + rate = FLAGS_bomb_l1_rate / FLAGS_bomb_l1_thread_num; + break; + case TxType::UpdateMaterialCostMaster: + // S1 + rate = FLAGS_bomb_s1_rate / FLAGS_bomb_s1_thread_num; + break; + case TxType::IssueJournalVoucher: + // S2 + rate = FLAGS_bomb_s2_rate / FLAGS_bomb_s2_thread_num; + break; + case TxType::AddNewProduct: + // S3 + rate = FLAGS_bomb_s3_rate / FLAGS_bomb_s3_thread_num; + break; + case TxType::ChangeRawMaterial: + // S4 + rate = FLAGS_bomb_s4_rate / FLAGS_bomb_s4_thread_num; + break; + case TxType::ChangeProductQuantity: + // S5 + rate = FLAGS_bomb_s5_rate / s5_thread_num; + break; + default: + ERR; + break; } + return std::chrono::microseconds(60 * 1000 * 1000 / rate); + } + + class TxArgs { + public: + uint32_t f_id; + uint32_t p_id; + uint32_t i_id; + uint32_t m_id; + std::set i_id_set; + bool add; - std::chrono::microseconds get_request_interval(TxType type) { - uint32_t rate; + void generate(BombWorkload* w, TxExecutor& tx, TxType type) { switch (type) { + case TxType::IssueJournalVoucher: case TxType::UpdateProductCostMaster: - // L1 - rate = FLAGS_bomb_l1_rate / FLAGS_bomb_l1_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); break; case TxType::UpdateMaterialCostMaster: - // S1 - rate = FLAGS_bomb_s1_rate / FLAGS_bomb_s1_thread_num; - break; - case TxType::IssueJournalVoucher: - // S2 - rate = FLAGS_bomb_s2_rate / FLAGS_bomb_s2_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); + while (i_id_set.size() < FLAGS_bomb_mc_update_size) { + uint32_t m_id = w->rnd_.random_int( + get_i_id_material_start(), + get_i_id_material_start() + FLAGS_bomb_material_size - 1); + i_id_set.emplace(m_id); + } break; case TxType::AddNewProduct: - // S3 - rate = FLAGS_bomb_s3_rate / FLAGS_bomb_s3_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); + p_id = ItemIdCounter.fetch_add(1) + 1; + while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { + uint32_t i_id = w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + + FLAGS_bomb_work_size - 1); + i_id_set.emplace(i_id); + } +#ifdef ADD_OR_DELETE + // if switch add and delete in turn for each factory + add = w->s3_counters_.at(f_id - 1) % 2 == 0 ? true : false; + if (add) { + p_id = ItemIdCounter.fetch_add(1) + 1; + while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { + uint32_t i_id = w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + + FLAGS_bomb_work_size - 1); + i_id_set.emplace(i_id); + } + } + w->s3_counters_.at(f_id - 1)++; +#endif break; case TxType::ChangeRawMaterial: - // S4 - rate = FLAGS_bomb_s4_rate / FLAGS_bomb_s4_thread_num; + // get a root_wip item id randomly (deleted item is selected from the tree) + i_id = + w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + FLAGS_bomb_work_size); + // get a material item id to insert + m_id = w->rnd_.random_int(get_i_id_material_start(), + get_i_id_material_start() + + FLAGS_bomb_material_size - 1); break; case TxType::ChangeProductQuantity: - // S5 - rate = FLAGS_bomb_s5_rate / s5_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); break; default: + if (loadAcquire(tx.quit_)) break; ERR; - break; } - return std::chrono::microseconds(60*1000*1000/rate); } + }; - class TxArgs { - public: - uint32_t f_id; - uint32_t p_id; - uint32_t i_id; - uint32_t m_id; - std::set i_id_set; - bool add; - - void generate(BombWorkload* w, TxExecutor& tx, TxType type) { - switch (type) { - case TxType::IssueJournalVoucher: - case TxType::UpdateProductCostMaster: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - break; - case TxType::UpdateMaterialCostMaster: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - while (i_id_set.size() < FLAGS_bomb_mc_update_size) { - uint32_t m_id = w->rnd_.random_int( - get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1); - i_id_set.emplace(m_id); - } - break; - case TxType::AddNewProduct: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - p_id = ItemIdCounter.fetch_add(1) + 1; - while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { - uint32_t i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size - 1); - i_id_set.emplace(i_id); - } -#ifdef ADD_OR_DELETE - // if switch add and delete in turn for each factory - add = w->s3_counters_.at(f_id-1) % 2 == 0 ? true : false; - if (add) { - p_id = ItemIdCounter.fetch_add(1) + 1; - while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { - uint32_t i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size - 1); - i_id_set.emplace(i_id); - } - } - w->s3_counters_.at(f_id-1)++; -#endif - break; - case TxType::ChangeRawMaterial: - // get a root_wip item id randomly (deleted item is selected from the tree) - i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size); - // get a material item id to insert - m_id = w->rnd_.random_int( - get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1); - break; - case TxType::ChangeProductQuantity: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - break; - default: - if (loadAcquire(tx.quit_)) break; - ERR; - } + class Query { + public: + TxType type; + TxArgs args; + + TxType decideType(TxExecutor& tx, [[maybe_unused]] Xoroshiro128Plus& r) { + // tx.thid_ is a non-negative thread index whose underlying type varies + // between protocols (int / size_t / uint8_t / unsigned int). Cast it + // to uint32_t once so each comparison against FLAGS_bomb_*_thread_num + // (declared as uint32) is sign-clean. + const uint32_t thid = static_cast(tx.thid_); + TxType txType; + if (thid < FLAGS_bomb_l1_thread_num) { + txType = TxType::UpdateProductCostMaster; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num) { + txType = TxType::UpdateMaterialCostMaster; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num) { + txType = TxType::IssueJournalVoucher; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + + FLAGS_bomb_s3_thread_num) { + txType = TxType::AddNewProduct; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num) { + txType = TxType::ChangeRawMaterial; + } else { + txType = TxType::ChangeProductQuantity; } - }; - - class Query { - public: - TxType type; - TxArgs args; - - TxType decideType(TxExecutor& tx, [[maybe_unused]] Xoroshiro128Plus& r) { - // tx.thid_ is a non-negative thread index whose underlying type varies - // between protocols (int / size_t / uint8_t / unsigned int). Cast it - // to uint32_t once so each comparison against FLAGS_bomb_*_thread_num - // (declared as uint32) is sign-clean. - const uint32_t thid = static_cast(tx.thid_); - TxType txType; - if (thid < FLAGS_bomb_l1_thread_num) { - txType = TxType::UpdateProductCostMaster; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num) { - txType = TxType::UpdateMaterialCostMaster; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num) { - txType = TxType::IssueJournalVoucher; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num) { - txType = TxType::AddNewProduct; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num) { - txType = TxType::ChangeRawMaterial; - } else { - txType = TxType::ChangeProductQuantity; - } - return txType; - } + return txType; + } - std::pair getRequest(TxExecutor& tx) { - if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { - timepoint start = std::chrono::high_resolution_clock::now();; - return make_pair(TxType::UpdateProductCostMaster, start); - } else { - int queueIndex = tx.thid_ - FLAGS_bomb_l1_thread_num; - std::pair ret; - while (!loadAcquire(tx.quit_)) { - try { - ret = requestQueues[queueIndex].pop(); - break; - } catch (const std::out_of_range& e) { - std::this_thread::sleep_for(std::chrono::nanoseconds(100)); - } + std::pair getRequest(TxExecutor& tx) { + if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { + timepoint start = std::chrono::high_resolution_clock::now(); + ; + return make_pair(TxType::UpdateProductCostMaster, start); + } else { + int queueIndex = tx.thid_ - FLAGS_bomb_l1_thread_num; + std::pair ret; + while (!loadAcquire(tx.quit_)) { + try { + ret = requestQueues[queueIndex].pop(); + break; + } catch (const std::out_of_range& e) { + std::this_thread::sleep_for(std::chrono::nanoseconds(100)); } - return ret; } + return ret; } + } - timepoint generate(BombWorkload* workload, TxExecutor& tx) { - timepoint start; - if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { - type = TxType::UpdateProductCostMaster; - start = std::chrono::high_resolution_clock::now(); - } else if (!FLAGS_bomb_mixed_mode) { - type = decideType(tx, workload->rnd_); - start = std::chrono::high_resolution_clock::now(); - } else { - auto ret = getRequest(tx); - type = ret.first; - start = ret.second; - } - args.generate(workload, tx, type); - return start; + timepoint generate(BombWorkload* workload, TxExecutor& tx) { + timepoint start; + if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { + type = TxType::UpdateProductCostMaster; + start = std::chrono::high_resolution_clock::now(); + } else if (!FLAGS_bomb_mixed_mode) { + type = decideType(tx, workload->rnd_); + start = std::chrono::high_resolution_clock::now(); + } else { + auto ret = getRequest(tx); + type = ret.first; + start = ret.second; } - }; - - static uint32_t get_i_id_product_start() { - return 1; + args.generate(workload, tx, type); + return start; } + }; - static uint32_t get_i_id_material_start() { - return get_i_id_product_start() + FLAGS_bomb_product_size; - } + static uint32_t get_i_id_product_start() { return 1; } - static uint32_t get_i_id_work_start() { - return get_i_id_material_start() + FLAGS_bomb_material_size; - } + static uint32_t get_i_id_material_start() { + return get_i_id_product_start() + FLAGS_bomb_product_size; + } - template - static inline auto select_random(Xoroshiro128Plus& r, const S &s) { - assert(!s.empty()); - auto itr = std::begin(s); - std::advance(itr, r.random_int(0, s.size()-1)); - return itr; - } + static uint32_t get_i_id_work_start() { + return get_i_id_material_start() + FLAGS_bomb_material_size; + } - template - inline T select_random(const std::set &s) { - assert(!s.empty()); - auto itr = std::begin(s); - std::advance(itr, rnd_.random_int(0, s.size()-1)); - return *itr; - } + template + static inline auto select_random(Xoroshiro128Plus& r, const S& s) { + assert(!s.empty()); + auto itr = std::begin(s); + std::advance(itr, r.random_int(0, s.size() - 1)); + return itr; + } - template - inline T select_random(const std::vector &v) { - assert(!v.empty()); - auto itr = std::begin(v); - std::advance(itr, rnd_.random_int(0, v.size()-1)); - return *itr; - } + template + inline T select_random(const std::set& s) { + assert(!s.empty()); + auto itr = std::begin(s); + std::advance(itr, rnd_.random_int(0, s.size() - 1)); + return *itr; + } - void prepare(TxExecutor& tx, Param *p) { - // for CC specific initialization parameter - this->param_ = p; - this->i_id_wip_end_ = ItemIdCounter.load(); - - if (FLAGS_bomb_use_cache) { - tx.reconnoiter_begin(); - std::vector product_ids; - // Return value intentionally discarded: the reconnaissance pass - // populates product_ids, which is all we need here. - (void)BombWorkload::select_im_by_factory(tx, 1, product_ids); - for (auto& p_id : product_ids) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - bom_cache_.emplace(p_id, root); - } - tx.reconnoiter_end(); - dump(tx.thid_, "[INFO] BoM cache creation done"); - } - } + template + inline T select_random(const std::vector& v) { + assert(!v.empty()); + auto itr = std::begin(v); + std::advance(itr, rnd_.random_int(0, v.size() - 1)); + return *itr; + } - Status update_product_cost_master(TxExecutor& tx, uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& pc = obj.ref(); - pc.pc_factory_id = f_id; - pc.pc_product_id = p_id; - pc.pc_cost = cost; - Status status = tx.update(Storage::ProductCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return status; - } + void prepare(TxExecutor& tx, Param* p) { + // for CC specific initialization parameter + this->param_ = p; + this->i_id_wip_end_ = ItemIdCounter.load(); - Node* build_bom_tree(TxExecutor& tx, uint32_t id) { - SimpleKey<8> low, up; - std::vector result; - Node* root = new Node(id); - std::vector next; - next.push_back(root); - while (next.size() != 0) { - auto node = next.back(); - next.pop_back(); - ItemConstructionMaster::CreateKey(node->i_id_, 0, low.ptr()); - ItemConstructionMaster::CreateKey(node->i_id_ + 1, 0, up.ptr()); - tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms && !tx.reconnoitering_) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) return nullptr; // TODO: clean up tree - for (auto& tuple : result) { - const ItemConstructionMaster& ic = tuple->get_value().cast_to(); - // std::cout << " PID: " << ic.ic_parent_i_id - // << " ID: " << ic.ic_i_id - // << " Q: " << ic.ic_material_quantity << std::endl; - Node* n = new Node(ic.ic_i_id, ic.ic_material_quantity); - node->add_child(n); - next.push_back(n); - } + if (FLAGS_bomb_use_cache) { + tx.reconnoiter_begin(); + std::vector product_ids; + // Return value intentionally discarded: the reconnaissance pass + // populates product_ids, which is all we need here. + (void) BombWorkload::select_im_by_factory(tx, 1, + product_ids); + for (auto& p_id : product_ids) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + bom_cache_.emplace(p_id, root); } - return root; - } - - void insert_journal_voucher(TxExecutor& tx, uint32_t debit, uint32_t credit, double amount) { - JVID jv_id; - jv_id.thid = tx.thid_; - jv_id.vid = jv_counter_++; - SimpleKey<8> key; - JournalVoucher::CreateKey(jv_id.obj_, key.ptr()); - HeapObject obj; - obj.allocate(); - JournalVoucher& jv_tuple = obj.ref(); - jv_tuple.jv_voucher_id = jv_id.obj_; - jv_tuple.jv_date = 20220101235959; - jv_tuple.jv_debit = debit; - jv_tuple.jv_credit = credit; - jv_tuple.jv_amount = amount; - tx.insert(Storage::JournalVoucher, key.view(), TupleBody(key.view(), std::move(obj))); + tx.reconnoiter_end(); + dump(tx.thid_, "[INFO] BoM cache creation done"); } + } - void run_issue_journal_voucher(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - SimpleKey<8> low, up; - std::vector result; - ProductCostMaster::CreateKey(f_id, 0, low.ptr()); - ProductCostMaster::CreateKey(f_id+1, 0, up.ptr()); - tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) return; + Status update_product_cost_master(TxExecutor& tx, uint32_t f_id, + uint32_t p_id, double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& pc = obj.ref(); + pc.pc_factory_id = f_id; + pc.pc_product_id = p_id; + pc.pc_cost = cost; + Status status = tx.update(Storage::ProductCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return status; + } - uint32_t debit = 0; // product - uint32_t credit = 1; // work in progress + Node* build_bom_tree(TxExecutor& tx, uint32_t id) { + SimpleKey<8> low, up; + std::vector result; + Node* root = new Node(id); + std::vector next; + next.push_back(root); + while (next.size() != 0) { + auto node = next.back(); + next.pop_back(); + ItemConstructionMaster::CreateKey(node->i_id_, 0, low.ptr()); + ItemConstructionMaster::CreateKey(node->i_id_ + 1, 0, up.ptr()); + tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), + true, result); + if (FLAGS_bomb_interactive_ms && !tx.reconnoitering_) + sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) + return nullptr; // TODO: clean up tree for (auto& tuple : result) { - const ProductCostMaster& pm = tuple->get_value().cast_to(); - double manufactured_quantity = 99.9; - insert_journal_voucher(tx, debit, credit, manufactured_quantity*pm.pc_cost); - if (tx.status_ == TransactionStatus::aborted) return; + const ItemConstructionMaster& ic = + tuple->get_value().cast_to(); + // std::cout << " PID: " << ic.ic_parent_i_id + // << " ID: " << ic.ic_i_id + // << " Q: " << ic.ic_material_quantity << std::endl; + Node* n = new Node(ic.ic_i_id, ic.ic_material_quantity); + node->add_child(n); + next.push_back(n); } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch } + return root; + } - void run_update_material_cost_master(TxExecutor& tx, Query& query) { - for (auto& m_id : query.args.i_id_set) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); - TupleBody* body; - tx.read(Storage::MaterialCostMaster, key.view(), &body); - MaterialCostMaster& old = body->get_value().cast_to(); - HeapObject obj; - obj.template allocate(); - MaterialCostMaster& mc = obj.ref(); - mc.mc_f_id = old.mc_f_id; - mc.mc_i_id = old.mc_i_id; - mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; - mc.mc_stock_price = old.mc_stock_price + 1.0; - tx.update(Storage::MaterialCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + void insert_journal_voucher(TxExecutor& tx, uint32_t debit, uint32_t credit, + double amount) { + JVID jv_id; + jv_id.thid = tx.thid_; + jv_id.vid = jv_counter_++; + SimpleKey<8> key; + JournalVoucher::CreateKey(jv_id.obj_, key.ptr()); + HeapObject obj; + obj.allocate(); + JournalVoucher& jv_tuple = obj.ref(); + jv_tuple.jv_voucher_id = jv_id.obj_; + jv_tuple.jv_date = 20220101235959; + jv_tuple.jv_debit = debit; + jv_tuple.jv_credit = credit; + jv_tuple.jv_amount = amount; + tx.insert(Storage::JournalVoucher, key.view(), + TupleBody(key.view(), std::move(obj))); + } + + void run_issue_journal_voucher(TxExecutor& tx, Query& query) { + uint32_t f_id = query.args.f_id; + SimpleKey<8> low, up; + std::vector result; + ProductCostMaster::CreateKey(f_id, 0, low.ptr()); + ProductCostMaster::CreateKey(f_id + 1, 0, up.ptr()); + tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, + result); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) return; + + uint32_t debit = 0; // product + uint32_t credit = 1; // work in progress + for (auto& tuple : result) { + const ProductCostMaster& pm = + tuple->get_value().cast_to(); + double manufactured_quantity = 99.9; + insert_journal_voucher(tx, debit, credit, + manufactured_quantity * pm.pc_cost); + if (tx.status_ == TransactionStatus::aborted) return; } + if (FLAGS_bomb_interactive_ms) + sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + } - void _run_update_product_cost_master_using_cache(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - std::map costs; - for (const auto& [p_id, root] : bom_cache_) { - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } - } - costs.emplace(p_id, root->calculate_cost()); - } - for (const auto& [p_id, cost] : costs) { - update_product_cost_master(tx, f_id, p_id, cost); - if (tx.status_ == TransactionStatus::aborted) return; - if (tx.quit_) { // for long read phase - tx.abort(); - tx.status_ = TransactionStatus::invalid; - return; + void run_update_material_cost_master(TxExecutor& tx, Query& query) { + for (auto& m_id : query.args.i_id_set) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); + TupleBody* body; + tx.read(Storage::MaterialCostMaster, key.view(), &body); + MaterialCostMaster& old = body->get_value().cast_to(); + HeapObject obj; + obj.template allocate(); + MaterialCostMaster& mc = obj.ref(); + mc.mc_f_id = old.mc_f_id; + mc.mc_i_id = old.mc_i_id; + mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; + mc.mc_stock_price = old.mc_stock_price + 1.0; + tx.update(Storage::MaterialCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) + sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + } + + void _run_update_product_cost_master_using_cache(TxExecutor& tx, + Query& query) { + uint32_t f_id = query.args.f_id; + std::map costs; + for (const auto& [p_id, root] : bom_cache_) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) + return; } } + costs.emplace(p_id, root->calculate_cost()); } - - void _run_update_product_cost_master(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - std::vector product_ids; - Status stat = select_im_by_factory(tx, f_id, product_ids); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) return; - if (product_ids.size() == 0) { - dump(tx.thid_, "ERROR: No target records."); - ERR; + for (const auto& [p_id, cost] : costs) { + update_product_cost_master(tx, f_id, p_id, cost); + if (tx.status_ == TransactionStatus::aborted) return; + if (tx.quit_) { // for long read phase + tx.abort(); + tx.status_ = TransactionStatus::invalid; + return; } + } + } - std::map costs; - for (auto& p_id : product_ids) { - Node* root = build_bom_tree(tx, p_id); - if (root == nullptr) return; - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } + void _run_update_product_cost_master(TxExecutor& tx, Query& query) { + uint32_t f_id = query.args.f_id; + std::vector product_ids; + Status stat = select_im_by_factory(tx, f_id, product_ids); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) return; + if (product_ids.size() == 0) { + dump(tx.thid_, "ERROR: No target records."); + ERR; + } + + std::map costs; + for (auto& p_id : product_ids) { + Node* root = build_bom_tree(tx, p_id); + if (root == nullptr) return; + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) + return; } - costs.emplace(p_id, root->calculate_cost()); } - for (const auto& [p_id, cost] : costs) { - Status status = update_product_cost_master(tx, f_id, p_id, cost); - if (status == Status::WARN_NOT_FOUND) { - status = insert_product_cost_master(tx, f_id, p_id, 0.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - std::stringstream ss; - ss << "ERROR: insert product cost master fails " << f_id << " " << p_id; - dump(tx.thid_, ss.str()); - ERR; - } - } - if (tx.status_ == TransactionStatus::aborted) return; - if (tx.quit_) { // for long read phase - tx.abort(); - tx.status_ = TransactionStatus::invalid; - return; + costs.emplace(p_id, root->calculate_cost()); + } + for (const auto& [p_id, cost] : costs) { + Status status = update_product_cost_master(tx, f_id, p_id, cost); + if (status == Status::WARN_NOT_FOUND) { + status = insert_product_cost_master(tx, f_id, p_id, 0.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { + std::stringstream ss; + ss << "ERROR: insert product cost master fails " << f_id << " " + << p_id; + dump(tx.thid_, ss.str()); + ERR; } } - } - - void run_update_product_cost_master(TxExecutor& tx, Query& query) { - if (FLAGS_bomb_use_cache) { - _run_update_product_cost_master_using_cache(tx, query); - } else { - _run_update_product_cost_master(tx, query); + if (tx.status_ == TransactionStatus::aborted) return; + if (tx.quit_) { // for long read phase + tx.abort(); + tx.status_ = TransactionStatus::invalid; + return; } } + } - Status insert_item_construction_master(TxExecutor& tx, - uint32_t parent_id, uint32_t id, double material_quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = id; - ic_tuple.ic_material_quantity = material_quantity; - return tx.insert(Storage::ItemConstructionMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - - Status insert_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - return tx.insert(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); + void run_update_product_cost_master(TxExecutor& tx, Query& query) { + if (FLAGS_bomb_use_cache) { + _run_update_product_cost_master_using_cache(tx, query); + } else { + _run_update_product_cost_master(tx, query); } + } - Status insert_product_cost_master(TxExecutor& tx, uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& p_tuple = obj.ref(); - p_tuple.pc_factory_id = f_id; - p_tuple.pc_product_id = p_id; - p_tuple.pc_cost = cost; - return tx.insert(Storage::ProductCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status insert_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t id, + double material_quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = id; + ic_tuple.ic_material_quantity = material_quantity; + return tx.insert(Storage::ItemConstructionMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status delete_item_construction_master(TxExecutor& tx, uint32_t parent_id, uint32_t material_id) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); - return tx.delete_record(Storage::ItemConstructionMaster, key.view()); - } + Status insert_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + return tx.insert(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status delete_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, uint32_t product_id) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - return tx.delete_record(Storage::ItemManufacturingMaster, key.view()); - } + Status insert_product_cost_master(TxExecutor& tx, uint32_t f_id, + uint32_t p_id, double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& p_tuple = obj.ref(); + p_tuple.pc_factory_id = f_id; + p_tuple.pc_product_id = p_id; + p_tuple.pc_cost = cost; + return tx.insert(Storage::ProductCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status update_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - return tx.update(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status delete_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t material_id) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); + return tx.delete_record(Storage::ItemConstructionMaster, key.view()); + } - Status upsert_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - TupleBody* body; + Status delete_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + return tx.delete_record(Storage::ItemManufacturingMaster, key.view()); + } - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im = obj.ref(); - im.im_factory_id = factory_id; - im.im_product_id= product_id; - im.im_quantity = quantity; - - Status stat = tx.read(Storage::ItemManufacturingMaster, key.view(), &body); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) return stat; - if (stat == Status::WARN_NOT_FOUND) { - // insert - stat = tx.insert(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } else { - // update - stat = tx.update(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; - } + Status update_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + return tx.update(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status update_item_construction_master(TxExecutor& tx, - uint32_t parent_id, uint32_t item_id, double quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, item_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = item_id; - ic_tuple.ic_material_quantity = quantity; - return tx.update(Storage::ItemConstructionMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status upsert_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + TupleBody* body; + + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im = obj.ref(); + im.im_factory_id = factory_id; + im.im_product_id = product_id; + im.im_quantity = quantity; + + Status stat = tx.read(Storage::ItemManufacturingMaster, key.view(), &body); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) return stat; + if (stat == Status::WARN_NOT_FOUND) { + // insert + stat = tx.insert(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } else { + // update + stat = tx.update(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - Status run_add_new_prodcut(TxExecutor& tx, Query& query) { - Status stat; - uint32_t f_id = query.args.f_id; - uint32_t p_id = query.args.p_id; - for (auto& i_id : query.args.i_id_set) { - stat = insert_item_construction_master(tx, p_id, i_id, 1.0); - if (stat != Status::OK) { - std::stringstream ss; - ss << "WARN: insert bom table fails " << f_id << " " << i_id; - dump(tx.thid_, ss.str()); - return stat; - } - } + Status update_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t item_id, double quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, item_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = item_id; + ic_tuple.ic_material_quantity = quantity; + return tx.update(Storage::ItemConstructionMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - stat = insert_item_manufacturing_master(tx, f_id, p_id, 10.0); + Status run_add_new_prodcut(TxExecutor& tx, Query& query) { + Status stat; + uint32_t f_id = query.args.f_id; + uint32_t p_id = query.args.p_id; + for (auto& i_id : query.args.i_id_set) { + stat = insert_item_construction_master(tx, p_id, i_id, 1.0); if (stat != Status::OK) { std::stringstream ss; - ss << "WARN: insert product table fails " << f_id << " " << p_id; + ss << "WARN: insert bom table fails " << f_id << " " << i_id; dump(tx.thid_, ss.str()); + return stat; } - - return stat; } - Status run_delete_product(TxExecutor& tx, Query& query) { - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - if (stat != Status::OK) return stat; - - uint32_t product_id = select_random(product_ids); - stat = delete_item_manufacturing_master(tx, query.args.f_id, product_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - dump(tx.thid_, "delete product fail"); - } - return stat; + stat = insert_item_manufacturing_master(tx, f_id, p_id, 10.0); + if (stat != Status::OK) { + std::stringstream ss; + ss << "WARN: insert product table fails " << f_id << " " << p_id; + dump(tx.thid_, ss.str()); } - void run_add_or_delete_product(TxExecutor& tx, Query& query) { - if (query.args.add) { - run_add_new_prodcut(tx, query); - } else { - run_delete_product(tx, query); - } - } + return stat; + } - void run_change_product(TxExecutor& tx, Query& query) { - Status stat = run_delete_product(tx, query); - if (stat != Status::OK) { - dump(tx.thid_, "delete product fail"); - return; - } else { - run_add_new_prodcut(tx, query); - } + Status run_delete_product(TxExecutor& tx, Query& query) { + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + if (stat != Status::OK) return stat; + + uint32_t product_id = select_random(product_ids); + stat = delete_item_manufacturing_master(tx, query.args.f_id, product_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { dump(tx.thid_, "delete product fail"); } + return stat; + } + + void run_add_or_delete_product(TxExecutor& tx, Query& query) { + if (query.args.add) { + run_add_new_prodcut(tx, query); + } else { + run_delete_product(tx, query); } + } - Status run_add_raw_material(TxExecutor& tx, Query& query) { - Status stat = insert_item_construction_master(tx, query.args.i_id, query.args.m_id, 1.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; + void run_change_product(TxExecutor& tx, Query& query) { + Status stat = run_delete_product(tx, query); + if (stat != Status::OK) { + dump(tx.thid_, "delete product fail"); + return; + } else { + run_add_new_prodcut(tx, query); } + } - Status run_delete_raw_material(TxExecutor& tx, Query& query) { - std::vector> material_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); - tx.reconnoiter_end(); - if (ret != Status::OK) return ret; + Status run_add_raw_material(TxExecutor& tx, Query& query) { + Status stat = insert_item_construction_master(tx, query.args.i_id, + query.args.m_id, 1.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - if (material_ids.size() == 1) { - dump(tx.thid_, "WARN: No target records, but continue by adding a new material"); - return run_add_raw_material(tx, query); - } + Status run_delete_raw_material(TxExecutor& tx, Query& query) { + std::vector> material_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); + tx.reconnoiter_end(); + if (ret != Status::OK) return ret; + + if (material_ids.size() == 1) { + dump(tx.thid_, + "WARN: No target records, but continue by adding a new material"); + return run_add_raw_material(tx, query); + } + + auto pair = select_random(material_ids); + auto parent_id = pair.first; + auto material_id = pair.second; + Status stat = delete_item_construction_master(tx, parent_id, material_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - auto pair = select_random(material_ids); - auto parent_id = pair.first; - auto material_id = pair.second; - Status stat = delete_item_construction_master(tx, parent_id, material_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; + Status run_add_or_delete_raw_material(TxExecutor& tx, Query& query) { + if (query.args.add) { + return run_add_raw_material(tx, query); + } else { + return run_delete_raw_material(tx, query); } + } - Status run_add_or_delete_raw_material(TxExecutor& tx, Query& query) { - if (query.args.add) { - return run_add_raw_material(tx, query); - } else { - return run_delete_raw_material(tx, query); - } - } + void run_change_raw_material(TxExecutor& tx, Query& query) { + std::vector> material_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); + tx.reconnoiter_end(); + if (ret != Status::OK) return; + + auto pair = select_random(material_ids); + auto parent_id = pair.first; + auto material_id = pair.second; + Status stat = delete_item_construction_master(tx, parent_id, material_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) return; + insert_item_construction_master(tx, parent_id, query.args.m_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + } - void run_change_raw_material(TxExecutor& tx, Query& query) { - std::vector> material_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); - tx.reconnoiter_end(); - if (ret != Status::OK) return; - - auto pair = select_random(material_ids); - auto parent_id = pair.first; - auto material_id = pair.second; - Status stat = delete_item_construction_master(tx, parent_id, material_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) return; - insert_item_construction_master(tx, parent_id, query.args.m_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + void run_change_product_quantity(TxExecutor& tx, Query& query) { + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + if (stat != Status::OK) return; + if (product_ids.size() == 0) { + dump(tx.thid_, "ERROR: No target records."); + ERR; } - void run_change_product_quantity(TxExecutor& tx, Query& query) { - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - if (stat != Status::OK) return; - if (product_ids.size() == 0) { - dump(tx.thid_, "ERROR: No target records."); - ERR; - } - - uint32_t product_id = select_random(product_ids); - update_item_manufacturing_master(tx, query.args.f_id, product_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - } + uint32_t product_id = select_random(product_ids); + update_item_manufacturing_master(tx, query.args.f_id, product_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + } - bool get_material_cost(TxExecutor& tx, uint32_t f_id, uint32_t m_id, double& cost) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); - TupleBody* body; - Status stat = tx.read(Storage::MaterialCostMaster, key.view(), &body); - if (tx.status_ == TransactionStatus::aborted) return false; - // Per CLAUDE.md: tx.read leaves *body unchanged on WARN_NOT_FOUND, - // so the cast_to below would dereference a stale pointer. - if (stat != Status::OK) return false; - MaterialCostMaster& mc = body->get_value().cast_to(); - cost = mc.mc_stock_price / mc.mc_stock_quantity; - return true; - } + bool get_material_cost(TxExecutor& tx, uint32_t f_id, uint32_t m_id, + double& cost) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); + TupleBody* body; + Status stat = tx.read(Storage::MaterialCostMaster, key.view(), &body); + if (tx.status_ == TransactionStatus::aborted) return false; + // Per CLAUDE.md: tx.read leaves *body unchanged on WARN_NOT_FOUND, + // so the cast_to below would dereference a stale pointer. + if (stat != Status::OK) return false; + MaterialCostMaster& mc = body->get_value().cast_to(); + cost = mc.mc_stock_price / mc.mc_stock_quantity; + return true; + } - Status select_materials_by_item_id(TxExecutor& tx, uint32_t i_id, - std::vector>& material_ids) { - // WIP with i_id may not have leaf nodes (materials), - // so recursively scan and get all materials - Node* parent = build_bom_tree(tx, i_id); - if (parent == nullptr) ERR; // TODO: retry? + Status select_materials_by_item_id( + TxExecutor& tx, uint32_t i_id, + std::vector>& material_ids) { + // WIP with i_id may not have leaf nodes (materials), + // so recursively scan and get all materials + Node* parent = build_bom_tree(tx, i_id); + if (parent == nullptr) ERR; // TODO: retry? - std::vector nodes; - parent->get_all_leafs(nodes); + std::vector nodes; + parent->get_all_leafs(nodes); - if (nodes.size() == 0) ERR; // TODO: retry? - for (auto& node : nodes) { - material_ids.emplace_back(node->parent_->i_id_, node->i_id_); - } - return Status::OK; + if (nodes.size() == 0) ERR; // TODO: retry? + for (auto& node : nodes) { + material_ids.emplace_back(node->parent_->i_id_, node->i_id_); } + return Status::OK; + } - void select_ic_by_product(TxExecutor& tx, uint32_t p_id) { - // for debug - SimpleKey<8> low, up; - std::vector result; - ItemConstructionMaster::CreateKey(p_id, 0, low.ptr()); - ItemConstructionMaster::CreateKey(p_id+1, 0, up.ptr()); - tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), false, result); - for (auto& tuple : result) { - const ItemConstructionMaster& ic = tuple->get_value().cast_to(); - std::cout << " PID: " << ic.ic_parent_i_id - << " ID: " << ic.ic_i_id - << " Q: " << ic.ic_material_quantity << std::endl; - } + void select_ic_by_product(TxExecutor& tx, uint32_t p_id) { + // for debug + SimpleKey<8> low, up; + std::vector result; + ItemConstructionMaster::CreateKey(p_id, 0, low.ptr()); + ItemConstructionMaster::CreateKey(p_id + 1, 0, up.ptr()); + tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), + false, result); + for (auto& tuple : result) { + const ItemConstructionMaster& ic = + tuple->get_value().cast_to(); + std::cout << " PID: " << ic.ic_parent_i_id << " ID: " << ic.ic_i_id + << " Q: " << ic.ic_material_quantity << std::endl; } + } - Status select_im_by_factory(TxExecutor& tx, uint32_t factory_id, std::vector& product_ids) { - SimpleKey<8> low, up; - std::vector result; - ItemManufacturingMaster::CreateKey(factory_id, 0, low.ptr()); - ItemManufacturingMaster::CreateKey(factory_id+1, 0, up.ptr()); - Status stat = tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), true, result); - if (tx.status_ == TransactionStatus::aborted) return stat; - for (auto& tuple : result) { - const ItemManufacturingMaster& im = tuple->get_value().cast_to(); - product_ids.emplace_back(im.im_product_id); - } - return stat; - } + Status select_im_by_factory(TxExecutor& tx, uint32_t factory_id, + std::vector& product_ids) { + SimpleKey<8> low, up; + std::vector result; + ItemManufacturingMaster::CreateKey(factory_id, 0, low.ptr()); + ItemManufacturingMaster::CreateKey(factory_id + 1, 0, up.ptr()); + Status stat = tx.scan(Storage::ItemManufacturingMaster, low.view(), false, + up.view(), true, result); + if (tx.status_ == TransactionStatus::aborted) return stat; + for (auto& tuple : result) { + const ItemManufacturingMaster& im = + tuple->get_value().cast_to(); + product_ids.emplace_back(im.im_product_id); + } + return stat; + } - void select_all_im_master(TxExecutor& tx) { - // for debug - SimpleKey<8> low, up; - std::vector result; - ItemManufacturingMaster::CreateKey(1, 0, low.ptr()); - ItemManufacturingMaster::CreateKey(FLAGS_bomb_factory_size, FLAGS_bomb_product_size, up.ptr()); - tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), false, result); - for (auto& tuple : result) { - const ItemManufacturingMaster& im = tuple->get_value().cast_to(); - std::cout << " FID: " << im.im_factory_id - << " PID: " << im.im_product_id - << " Q: " << im.im_quantity << std::endl; - } + void select_all_im_master(TxExecutor& tx) { + // for debug + SimpleKey<8> low, up; + std::vector result; + ItemManufacturingMaster::CreateKey(1, 0, low.ptr()); + ItemManufacturingMaster::CreateKey(FLAGS_bomb_factory_size, + FLAGS_bomb_product_size, up.ptr()); + tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), + false, result); + for (auto& tuple : result) { + const ItemManufacturingMaster& im = + tuple->get_value().cast_to(); + std::cout << " FID: " << im.im_factory_id << " PID: " << im.im_product_id + << " Q: " << im.im_quantity << std::endl; } + } - // void dump_all_ic_master() { - // // for debug (single-version CC only) - // SimpleKey<8> low, up; - // std::vector result; - // ItemConstructionMaster::CreateKey(1, 0, low.ptr()); - // ItemConstructionMaster::CreateKey(10000000, 0, up.ptr()); - // std::vector scan_res; - // Masstrees[get_storage(Storage::ItemConstructionMaster)].scan( - // low.view().data(), low.view().size(), false, - // up.view().data(), up.view().size(), true, - // &scan_res, false); - // for (auto& tuple : scan_res) { - // const ItemConstructionMaster& ic = tuple->body_.get_value().cast_to(); - // std::cout << " PID: " << ic.ic_parent_i_id - // << " ID: " << ic.ic_i_id - // << " Q: " << ic.ic_material_quantity - // << " TUPLE: " << tuple << std::endl; - // } - // } - - template - void run(TxExecutor& tx) { - Query query; - auto start = query.generate(this, tx); - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); - } - - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - - switch (query.type) { - case TxType::IssueJournalVoucher: - // dump(tx.thid_, "S2"); - run_issue_journal_voucher(tx, query); - break; - case TxType::UpdateMaterialCostMaster: - // dump(tx.thid_, "S1"); - run_update_material_cost_master(tx, query); - break; - case TxType::UpdateProductCostMaster: - run_update_product_cost_master(tx, query); - break; - case TxType::AddNewProduct: - run_change_product(tx, query); - break; - case TxType::ChangeRawMaterial: - run_change_raw_material(tx, query); - break; - case TxType::ChangeProductQuantity: - run_change_product_quantity(tx, query); - break; - default: - ERR; - break; - } + // void dump_all_ic_master() { + // // for debug (single-version CC only) + // SimpleKey<8> low, up; + // std::vector result; + // ItemConstructionMaster::CreateKey(1, 0, low.ptr()); + // ItemConstructionMaster::CreateKey(10000000, 0, up.ptr()); + // std::vector scan_res; + // Masstrees[get_storage(Storage::ItemConstructionMaster)].scan( + // low.view().data(), low.view().size(), false, + // up.view().data(), up.view().size(), true, + // &scan_res, false); + // for (auto& tuple : scan_res) { + // const ItemConstructionMaster& ic = tuple->body_.get_value().cast_to(); + // std::cout << " PID: " << ic.ic_parent_i_id + // << " ID: " << ic.ic_i_id + // << " Q: " << ic.ic_material_quantity + // << " TUPLE: " << tuple << std::endl; + // } + // } + + template + void run(TxExecutor& tx) { + Query query; + auto start = query.generate(this, tx); + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + + switch (query.type) { + case TxType::IssueJournalVoucher: + // dump(tx.thid_, "S2"); + run_issue_journal_voucher(tx, query); + break; + case TxType::UpdateMaterialCostMaster: + // dump(tx.thid_, "S1"); + run_update_material_cost_master(tx, query); + break; + case TxType::UpdateProductCostMaster: + run_update_product_cost_master(tx, query); + break; + case TxType::AddNewProduct: + run_change_product(tx, query); + break; + case TxType::ChangeRawMaterial: + run_change_raw_material(tx, query); + break; + case TxType::ChangeProductQuantity: + run_change_product_quantity(tx, query); + break; + default: + ERR; + break; + } - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start); - if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { - auto interval = get_request_interval(query.type); - if (elapsed < interval) { - std::this_thread::sleep_for((interval - elapsed) * 0.95); - } - } - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + elapsed.count(); - return; + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); + if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { + auto interval = get_request_interval(query.type); + if (elapsed < interval) { + std::this_thread::sleep_for((interval - elapsed) * 0.95); + } } + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + + elapsed.count(); + return; + } - static void insert_item_construction_master([[maybe_unused]] size_t thid, Param *param, - uint32_t parent_id, uint32_t id, - double material_quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = id; - ic_tuple.ic_material_quantity = material_quantity; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::ItemConstructionMaster)].insert_value(key.view(), tmp); - } + static void insert_item_construction_master([[maybe_unused]] size_t thid, + Param* param, uint32_t parent_id, + uint32_t id, + double material_quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = id; + ic_tuple.ic_material_quantity = material_quantity; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::ItemConstructionMaster)].insert_value( + key.view(), tmp); + } - static void insert_item_manufacturing_master([[maybe_unused]] size_t thid, Param *param, - uint32_t factory_id, uint32_t product_id, - double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::ItemManufacturingMaster)].insert_value(key.view(), tmp); - } + static void insert_item_manufacturing_master([[maybe_unused]] size_t thid, + Param* param, + uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::ItemManufacturingMaster)].insert_value( + key.view(), tmp); + } - static void insert_material_cost_master([[maybe_unused]] size_t thid, Param *p, - uint32_t f_id, uint32_t m_id, double quantity, double price) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); - HeapObject obj; - obj.allocate(); - MaterialCostMaster& m_tuple = obj.ref(); - m_tuple.mc_f_id = f_id; - m_tuple.mc_i_id = m_id; - m_tuple.mc_stock_quantity = quantity; - m_tuple.mc_stock_price = price; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); - Masstrees[get_storage(Storage::MaterialCostMaster)].insert_value(key.view(), tmp); - } + static void insert_material_cost_master([[maybe_unused]] size_t thid, + Param* p, uint32_t f_id, + uint32_t m_id, double quantity, + double price) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); + HeapObject obj; + obj.allocate(); + MaterialCostMaster& m_tuple = obj.ref(); + m_tuple.mc_f_id = f_id; + m_tuple.mc_i_id = m_id; + m_tuple.mc_stock_quantity = quantity; + m_tuple.mc_stock_price = price; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); + Masstrees[get_storage(Storage::MaterialCostMaster)].insert_value(key.view(), + tmp); + } - static void insert_product_cost_master([[maybe_unused]] size_t thid, Param *p, - uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& p_tuple = obj.ref(); - p_tuple.pc_factory_id = f_id; - p_tuple.pc_product_id = p_id; - p_tuple.pc_cost = cost; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); - Masstrees[get_storage(Storage::ProductCostMaster)].insert_value(key.view(), tmp); - } + static void insert_product_cost_master([[maybe_unused]] size_t thid, Param* p, + uint32_t f_id, uint32_t p_id, + double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& p_tuple = obj.ref(); + p_tuple.pc_factory_id = f_id; + p_tuple.pc_product_id = p_id; + p_tuple.pc_cost = cost; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); + Masstrees[get_storage(Storage::ProductCostMaster)].insert_value(key.view(), + tmp); + } - static void load_work_in_progress([[maybe_unused]] size_t thid, Param* param, - std::atomic& i_id, uint64_t start, uint64_t end) { + static void load_work_in_progress([[maybe_unused]] size_t thid, Param* param, + std::atomic& i_id, uint64_t start, + uint64_t end) { #if MASSTREE_USE - MasstreeWrapper::thread_init(thid); + MasstreeWrapper::thread_init(thid); #endif - Xoroshiro128Plus rand; - rand.init(); - for (auto i = start; i <= end; ++i) { - // TODO: randomized tree size (number of WIP nodes in the tree) - auto tree_size = FLAGS_bomb_base_tree_size; - - // create root - Node* root = new Node(); - std::vector nodes; - nodes.push_back(root); - - // add work in progress - while (nodes.size() < tree_size) { - assert(!nodes.empty()); - Node* node = new Node(); - Node* parent = nodes.at(rand.random_int(0, nodes.size()-1)); - parent->add_child(node); - nodes.push_back(node); - } + Xoroshiro128Plus rand; + rand.init(); + for (auto i = start; i <= end; ++i) { + // TODO: randomized tree size (number of WIP nodes in the tree) + auto tree_size = FLAGS_bomb_base_tree_size; + + // create root + Node* root = new Node(); + std::vector nodes; + nodes.push_back(root); + + // add work in progress + while (nodes.size() < tree_size) { + assert(!nodes.empty()); + Node* node = new Node(); + Node* parent = nodes.at(rand.random_int(0, nodes.size() - 1)); + parent->add_child(node); + nodes.push_back(node); + } - // assign i_id for work in progress recursively - root->i_id_ = get_i_id_work_start() + i; - root->assign_id(i_id); - - // assign raw materials - for (auto& node : nodes) { - if (!node->is_leaf()) continue; - auto material_size = FLAGS_bomb_material_per_wip; - std::set s; - while (s.size() < material_size) - s.emplace(rand.random_int(get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1)); - for (auto& i_id_material : s) - node->add_child(new Node(i_id_material)); - } + // assign i_id for work in progress recursively + root->i_id_ = get_i_id_work_start() + i; + root->assign_id(i_id); - // insert item construction master - nodes.clear(); - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->parent_ == nullptr) continue; - insert_item_construction_master(thid, param, node->parent_->i_id_, node->i_id_, 1.0); - } + // assign raw materials + for (auto& node : nodes) { + if (!node->is_leaf()) continue; + auto material_size = FLAGS_bomb_material_per_wip; + std::set s; + while (s.size() < material_size) + s.emplace(rand.random_int(get_i_id_material_start(), + get_i_id_material_start() + + FLAGS_bomb_material_size - 1)); + for (auto& i_id_material : s) node->add_child(new Node(i_id_material)); } - } - static void load_item_construction_master_product([[maybe_unused]] size_t thid, Param *param, - uint32_t p_id, std::set& wip_ids) { - for (auto& id : wip_ids) { - insert_item_construction_master(thid, param, p_id, id, 1.0); + // insert item construction master + nodes.clear(); + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->parent_ == nullptr) continue; + insert_item_construction_master(thid, param, node->parent_->i_id_, + node->i_id_, 1.0); } } + } - static void load_item_manufacturing_master([[maybe_unused]] size_t thid, Param *param, - Xoroshiro128Plus& rand, - std::set& product_ids, - std::vector>& pm_keys) { - for (uint32_t i = 0; i < FLAGS_bomb_base_product_size_per_factory; i++) { // all - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } - product_ids.erase(itr); - } + static void + load_item_construction_master_product([[maybe_unused]] size_t thid, + Param* param, uint32_t p_id, + std::set& wip_ids) { + for (auto& id : wip_ids) { + insert_item_construction_master(thid, param, p_id, id, 1.0); + } + } - // Disable different product size per factory to improve fairness - // when choosing a factory in long batch transaction -#ifdef USE_DIFFERENT_PRODUCT_SIZE_PER_FACTORY - for (uint32_t i = 0; i < 20; i++) { // 50% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 2 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } - } - product_ids.erase(itr); + static void load_item_manufacturing_master( + [[maybe_unused]] size_t thid, Param* param, Xoroshiro128Plus& rand, + std::set& product_ids, + std::vector>& pm_keys) { + for (uint32_t i = 0; i < FLAGS_bomb_base_product_size_per_factory; + i++) { // all + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } + product_ids.erase(itr); + } - for (uint32_t i = 0; i < 30; i++) { // 25% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 4 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } + // Disable different product size per factory to improve fairness + // when choosing a factory in long batch transaction +#ifdef USE_DIFFERENT_PRODUCT_SIZE_PER_FACTORY + for (uint32_t i = 0; i < 20; i++) { // 50% + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + if (f_id % 2 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } - product_ids.erase(itr); } + product_ids.erase(itr); + } - for (uint32_t i = 0; i < 40; i++) { // 10% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 10 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } + for (uint32_t i = 0; i < 30; i++) { // 25% + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + if (f_id % 4 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } - product_ids.erase(itr); } -#endif + product_ids.erase(itr); } - static void load_material_cost_master([[maybe_unused]] size_t thid, Param *param) { + for (uint32_t i = 0; i < 40; i++) { // 10% + auto itr = select_random(rand, product_ids); for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - for (uint32_t m_id = get_i_id_material_start(); - m_id < get_i_id_material_start() + FLAGS_bomb_material_size; m_id++) { - insert_material_cost_master(0, param, f_id, m_id, 1.0, 1.0); + if (f_id % 10 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } } + product_ids.erase(itr); } +#endif + } - static void load_product_cost_master([[maybe_unused]] size_t thid, Param *param, - std::vector>& pm_keys) { - for (auto& [f_id, p_id] : pm_keys) { - insert_product_cost_master(0, param, f_id, p_id, 0.0); + static void load_material_cost_master([[maybe_unused]] size_t thid, + Param* param) { + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + for (uint32_t m_id = get_i_id_material_start(); + m_id < get_i_id_material_start() + FLAGS_bomb_material_size; + m_id++) { + insert_material_cost_master(0, param, f_id, m_id, 1.0, 1.0); } } + } - static uint32_t getTableNum() { - return (uint32_t)Storage::Size; - } - - static void makeDB(Param* param) { - Xoroshiro128Plus rand; - rand.init(); - size_t maxthread = 64; - std::vector thv; - auto product_start = get_i_id_product_start(); - auto root_wip_start = get_i_id_work_start(); - auto non_root_wip_start = get_i_id_work_start() + FLAGS_bomb_work_size; - ItemIdCounter.store(non_root_wip_start); - - // TODO: move this codes to appropriate place - set_tx_name(TxType::UpdateMaterialCostMaster, "UpdateMaterialCostMaster"); - set_tx_name(TxType::UpdateProductCostMaster, "UpdateProductCostMaster"); - set_tx_name(TxType::IssueJournalVoucher, "IssueJournalVoucher"); - set_tx_name(TxType::AddNewProduct, "AddNewProduct"); - set_tx_name(TxType::ChangeRawMaterial, "ChangeRawMaterial"); - set_tx_name(TxType::ChangeProductQuantity, "ChangeProductQuantity"); - - // TODO: can we remove thid from loader function? - // load item construction master for work in progress - std::cout << "load item construction master for work in progress" << std::endl; - for (size_t i = 0; i < maxthread; i++) { - thv.emplace_back(load_work_in_progress, i, param, std::ref(ItemIdCounter), - i * (FLAGS_bomb_work_size / maxthread), - (i + 1) * ((FLAGS_bomb_work_size + maxthread - 1) / maxthread) - 1); - } - for (auto &th : thv) th.join(); - - // load item construction master for finished products - std::cout << "load item construction master for finished products" << std::endl; - std::set product_id_set; // for loading item manufacturing master - for (uint32_t p_id = product_start; - p_id < product_start + FLAGS_bomb_product_size; p_id++) { - auto tree_size = FLAGS_bomb_tree_num_per_product; - std::set s; - while (s.size() < tree_size) - s.emplace(rand.random_int(root_wip_start, - root_wip_start + FLAGS_bomb_work_size - 1)); - load_item_construction_master_product(0, param, p_id, s); - product_id_set.emplace(p_id); - } - - // load item manufacturing master - std::cout << "load item manufacturing master " << std::endl; - std::vector> pm_keys; // for load product cost master - load_item_manufacturing_master(0, param, rand, product_id_set, pm_keys); - - // load material cost master - std::cout << "load material cost master " << std::endl; - load_material_cost_master(0, param); - - // load product cost master - std::cout << "load product cost master " << std::endl; - load_product_cost_master(0, param, pm_keys); - - std::cout << "loading done" << std::endl; + static void load_product_cost_master( + [[maybe_unused]] size_t thid, Param* param, + std::vector>& pm_keys) { + for (auto& [f_id, p_id] : pm_keys) { + insert_product_cost_master(0, param, f_id, p_id, 0.0); } + } - static TxType decideType(Xoroshiro128Plus& r, uint64_t* thresholds) { - uint64_t x = r.random_int(1, 100); - if (x > thresholds[0]) return TxType::UpdateMaterialCostMaster; - if (x > thresholds[1]) return TxType::IssueJournalVoucher; - if (x > thresholds[2]) return TxType::AddNewProduct; - if (x > thresholds[3]) return TxType::ChangeRawMaterial; - return TxType::ChangeProductQuantity; - } + static uint32_t getTableNum() { return (uint32_t) Storage::Size; } + + static void makeDB(Param* param) { + Xoroshiro128Plus rand; + rand.init(); + size_t maxthread = 64; + std::vector thv; + auto product_start = get_i_id_product_start(); + auto root_wip_start = get_i_id_work_start(); + auto non_root_wip_start = get_i_id_work_start() + FLAGS_bomb_work_size; + ItemIdCounter.store(non_root_wip_start); + + // TODO: move this codes to appropriate place + set_tx_name(TxType::UpdateMaterialCostMaster, "UpdateMaterialCostMaster"); + set_tx_name(TxType::UpdateProductCostMaster, "UpdateProductCostMaster"); + set_tx_name(TxType::IssueJournalVoucher, "IssueJournalVoucher"); + set_tx_name(TxType::AddNewProduct, "AddNewProduct"); + set_tx_name(TxType::ChangeRawMaterial, "ChangeRawMaterial"); + set_tx_name(TxType::ChangeProductQuantity, "ChangeProductQuantity"); + + // TODO: can we remove thid from loader function? + // load item construction master for work in progress + std::cout << "load item construction master for work in progress" + << std::endl; + for (size_t i = 0; i < maxthread; i++) { + thv.emplace_back( + load_work_in_progress, i, param, std::ref(ItemIdCounter), + i * (FLAGS_bomb_work_size / maxthread), + (i + 1) * ((FLAGS_bomb_work_size + maxthread - 1) / maxthread) - 1); + } + for (auto& th : thv) th.join(); + + // load item construction master for finished products + std::cout << "load item construction master for finished products" + << std::endl; + std::set product_id_set; // for loading item manufacturing master + for (uint32_t p_id = product_start; + p_id < product_start + FLAGS_bomb_product_size; p_id++) { + auto tree_size = FLAGS_bomb_tree_num_per_product; + std::set s; + while (s.size() < tree_size) + s.emplace(rand.random_int(root_wip_start, + root_wip_start + FLAGS_bomb_work_size - 1)); + load_item_construction_master_product(0, param, p_id, s); + product_id_set.emplace(p_id); + } + + // load item manufacturing master + std::cout << "load item manufacturing master " << std::endl; + std::vector> + pm_keys; // for load product cost master + load_item_manufacturing_master(0, param, rand, product_id_set, pm_keys); + + // load material cost master + std::cout << "load material cost master " << std::endl; + load_material_cost_master(0, param); + + // load product cost master + std::cout << "load product cost master " << std::endl; + load_product_cost_master(0, param, pm_keys); + + std::cout << "loading done" << std::endl; + } - static void request_dispatcher([[maybe_unused]] size_t thid, char &ready, const bool &start, const bool &quit) { - // prepare queues for short transactions - int numQueues = TotalThreadNum - FLAGS_bomb_l1_thread_num; - requestQueues = new ConcurrentQueue>[numQueues]; + static TxType decideType(Xoroshiro128Plus& r, uint64_t* thresholds) { + uint64_t x = r.random_int(1, 100); + if (x > thresholds[0]) return TxType::UpdateMaterialCostMaster; + if (x > thresholds[1]) return TxType::IssueJournalVoucher; + if (x > thresholds[2]) return TxType::AddNewProduct; + if (x > thresholds[3]) return TxType::ChangeRawMaterial; + return TxType::ChangeProductQuantity; + } - uint64_t thresholds[4]; - int32_t perc_s5 = 100 - (FLAGS_bomb_perc_s1 + FLAGS_bomb_perc_s2 + FLAGS_bomb_perc_s3 + FLAGS_bomb_perc_s4); - if (perc_s5 < 0) { - std::cout << "Specify short transaction percentage to make the total 100" << std::endl; - ERR; - } - thresholds[3] = perc_s5; - thresholds[2] = thresholds[3] + FLAGS_bomb_perc_s4; - thresholds[1] = thresholds[2] + FLAGS_bomb_perc_s3; - thresholds[0] = thresholds[1] + FLAGS_bomb_perc_s2; - - Xoroshiro128Plus r; - storeRelease(ready, 1); - while (!loadAcquire(start)) _mm_pause(); - while (!loadAcquire(quit)) { - for (int i = 0; i < numQueues; i++) { - auto start = std::chrono::high_resolution_clock::now(); - for (uint32_t j = 0; j < FLAGS_bomb_req_batch_size; j++) { - requestQueues[i].push(make_pair(decideType(r, thresholds), start)); - } - if (FLAGS_bomb_mixed_short_rate_tps) { - std::this_thread::sleep_for(get_request_interval_nano()); - } else { - std::this_thread::sleep_for(get_request_interval_micro()); - } + static void request_dispatcher([[maybe_unused]] size_t thid, char& ready, + const bool& start, const bool& quit) { + // prepare queues for short transactions + int numQueues = TotalThreadNum - FLAGS_bomb_l1_thread_num; + requestQueues = + new ConcurrentQueue>[numQueues]; + + uint64_t thresholds[4]; + int32_t perc_s5 = 100 - (FLAGS_bomb_perc_s1 + FLAGS_bomb_perc_s2 + + FLAGS_bomb_perc_s3 + FLAGS_bomb_perc_s4); + if (perc_s5 < 0) { + std::cout << "Specify short transaction percentage to make the total 100" + << std::endl; + ERR; + } + thresholds[3] = perc_s5; + thresholds[2] = thresholds[3] + FLAGS_bomb_perc_s4; + thresholds[1] = thresholds[2] + FLAGS_bomb_perc_s3; + thresholds[0] = thresholds[1] + FLAGS_bomb_perc_s2; + + Xoroshiro128Plus r; + storeRelease(ready, 1); + while (!loadAcquire(start)) _mm_pause(); + while (!loadAcquire(quit)) { + for (int i = 0; i < numQueues; i++) { + auto start = std::chrono::high_resolution_clock::now(); + for (uint32_t j = 0; j < FLAGS_bomb_req_batch_size; j++) { + requestQueues[i].push(make_pair(decideType(r, thresholds), start)); + } + if (FLAGS_bomb_mixed_short_rate_tps) { + std::this_thread::sleep_for(get_request_interval_nano()); + } else { + std::this_thread::sleep_for(get_request_interval_micro()); } } - sleepMs(1000); - delete[] requestQueues; } + sleepMs(1000); + delete[] requestQueues; + } - static void displayWorkloadParameter() { - } + static void displayWorkloadParameter() {} - static void displayWorkloadResult() { - } + static void displayWorkloadResult() {} }; diff --git a/include/bomb_pessimistic.hh b/include/bomb_pessimistic.hh index 1a7bbb28..9e49e006 100644 --- a/include/bomb_pessimistic.hh +++ b/include/bomb_pessimistic.hh @@ -20,11 +20,17 @@ #include "gflags/gflags.h" #ifdef GLOBAL_VALUE_DEFINE -DEFINE_uint32(bomb_l1_thread_num, 1, "Number of threads for batch (update-product-cost-master) transaction"); -DEFINE_uint32(bomb_s1_thread_num, 1, "Number of threads for update-material-cost-master transaction"); -DEFINE_uint32(bomb_s2_thread_num, 1, "Number of threads for issue-journal-voucher transaction"); -DEFINE_uint32(bomb_s3_thread_num, 0, "Number of threads for add-new-product transaction"); -DEFINE_uint32(bomb_s4_thread_num, 0, "Number of threads for change-raw-material transaction"); +DEFINE_uint32( + bomb_l1_thread_num, 1, + "Number of threads for batch (update-product-cost-master) transaction"); +DEFINE_uint32(bomb_s1_thread_num, 1, + "Number of threads for update-material-cost-master transaction"); +DEFINE_uint32(bomb_s2_thread_num, 1, + "Number of threads for issue-journal-voucher transaction"); +DEFINE_uint32(bomb_s3_thread_num, 0, + "Number of threads for add-new-product transaction"); +DEFINE_uint32(bomb_s4_thread_num, 0, + "Number of threads for change-raw-material transaction"); DEFINE_uint32(bomb_mixed_short_rate, 500, "Request rate of short transactions"); DEFINE_bool(bomb_mixed_short_rate_tps, false, "Use request rate as per-second"); DEFINE_bool(bomb_mixed_mode, false, "Enable mixed-workload mode"); @@ -43,26 +49,27 @@ DEFINE_uint64(bomb_perc_s4, 0, "The percentage of S4 transactions"); DEFINE_uint32(bomb_req_batch_size, 1, "Request batch size"); DEFINE_uint32(bomb_factory_size, 8, "Total number of factories"); DEFINE_uint32(bomb_product_size, 72000, "Total number of finished products"); -DEFINE_uint32(bomb_work_size, 198000, "Total number of root work in progress (root WIP)"); +DEFINE_uint32(bomb_work_size, 198000, + "Total number of root work in progress (root WIP)"); DEFINE_uint32(bomb_material_size, 75000, "Total number of raw materials"); DEFINE_uint32(bomb_tree_num_per_product, 5, ""); DEFINE_uint32(bomb_base_tree_size, 10, ""); DEFINE_uint32(bomb_material_per_wip, 3, ""); DEFINE_uint32(bomb_base_product_size_per_factory, 100, ""); -DEFINE_uint32(bomb_mc_update_size, 1, "Number of update materials in update-material-cost-master transaction"); -DEFINE_uint32(bomb_interactive_ms, 0, "Sleep microseconds per SQL(-equivalent) unit"); +DEFINE_uint32( + bomb_mc_update_size, 1, + "Number of update materials in update-material-cost-master transaction"); +DEFINE_uint32(bomb_interactive_ms, 0, + "Sleep microseconds per SQL(-equivalent) unit"); #else DECLARE_uint32(bomb_l1_thread_num); DECLARE_uint32(bomb_s1_thread_num); DECLARE_uint32(bomb_s2_thread_num); DECLARE_uint32(bomb_s3_thread_num); DECLARE_uint32(bomb_s4_thread_num); -DECLARE_uint32(bomb_mixed_short_rate) -DECLARE_bool(bomb_mixed_short_rate_tps) -DECLARE_bool(bomb_mixed_mode) -DECLARE_bool(bomb_use_cache) -DECLARE_bool(bomb_rate_control) -DECLARE_uint32(bomb_l1_rate); +DECLARE_uint32(bomb_mixed_short_rate) DECLARE_bool(bomb_mixed_short_rate_tps) + DECLARE_bool(bomb_mixed_mode) DECLARE_bool(bomb_use_cache) + DECLARE_bool(bomb_rate_control) DECLARE_uint32(bomb_l1_rate); DECLARE_uint32(bomb_s1_rate); DECLARE_uint32(bomb_s2_rate); DECLARE_uint32(bomb_s3_rate); @@ -89,7 +96,7 @@ DECLARE_uint32(bomb_interactive_ms); typedef std::chrono::high_resolution_clock::time_point timepoint; GLOBAL std::atomic ItemIdCounter; -GLOBAL ConcurrentQueue> *requestQueues; +GLOBAL ConcurrentQueue>* requestQueues; enum class Storage : std::uint32_t { ItemConstructionMaster = 0, @@ -113,113 +120,114 @@ enum class TxType : std::uint32_t { }; struct Factory { - alignas(CACHE_LINE_SIZE) - std::uint32_t f_id; + alignas(CACHE_LINE_SIZE) std::uint32_t f_id; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t f_id, char *out) { + static void CreateKey(uint32_t f_id, char* out) { assign_as_bigendian(f_id, &out[0]); assign_as_bigendian(0, &out[4]); } - void createKey(char *out) const { return CreateKey(f_id, out); } + void createKey(char* out) const { return CreateKey(f_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ItemMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t i_id; + alignas(CACHE_LINE_SIZE) std::uint32_t i_id; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t i_id, char *out) { + static void CreateKey(uint32_t i_id, char* out) { assign_as_bigendian(i_id, &out[0]); assign_as_bigendian(0, &out[4]); } - void createKey(char *out) const { return CreateKey(i_id, out); } + void createKey(char* out) const { return CreateKey(i_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ItemConstructionMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t ic_parent_i_id; + alignas(CACHE_LINE_SIZE) std::uint32_t ic_parent_i_id; std::uint32_t ic_i_id; double ic_material_quantity; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t ic_parent_i_id, uint32_t ic_i_id, char *out) { + static void CreateKey(uint32_t ic_parent_i_id, uint32_t ic_i_id, char* out) { assign_as_bigendian(ic_parent_i_id, &out[0]); assign_as_bigendian(ic_i_id, &out[4]); } - void createKey(char *out) const { return CreateKey(ic_parent_i_id, ic_i_id, out); } + void createKey(char* out) const { + return CreateKey(ic_parent_i_id, ic_i_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct MaterialCostMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t mc_f_id; // factory - std::uint32_t mc_i_id; // item + alignas(CACHE_LINE_SIZE) std::uint32_t mc_f_id; // factory + std::uint32_t mc_i_id; // item double mc_stock_quantity; double mc_stock_price; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t mc_f_id, uint32_t mc_i_id, char *out) { + static void CreateKey(uint32_t mc_f_id, uint32_t mc_i_id, char* out) { assign_as_bigendian(mc_f_id, &out[0]); assign_as_bigendian(mc_i_id, &out[4]); } - void createKey(char *out) const { return CreateKey(mc_f_id, mc_i_id, out); } + void createKey(char* out) const { return CreateKey(mc_f_id, mc_i_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ItemManufacturingMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t im_factory_id; + alignas(CACHE_LINE_SIZE) std::uint32_t im_factory_id; std::uint32_t im_product_id; double im_quantity; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t im_factory_id, uint32_t im_product_id, char *out) { + static void CreateKey(uint32_t im_factory_id, uint32_t im_product_id, + char* out) { assign_as_bigendian(im_factory_id, &out[0]); assign_as_bigendian(im_product_id, &out[4]); } - void createKey(char *out) const { return CreateKey(im_factory_id, im_product_id, out); } + void createKey(char* out) const { + return CreateKey(im_factory_id, im_product_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct ProductCostMaster { - alignas(CACHE_LINE_SIZE) - std::uint32_t pc_factory_id; + alignas(CACHE_LINE_SIZE) std::uint32_t pc_factory_id; std::uint32_t pc_product_id; double pc_cost; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint32_t pc_factory_id, uint32_t pc_product_id, char *out) { + static void CreateKey(uint32_t pc_factory_id, uint32_t pc_product_id, + char* out) { assign_as_bigendian(pc_factory_id, &out[0]); assign_as_bigendian(pc_product_id, &out[4]); } - void createKey(char *out) const { return CreateKey(pc_factory_id, pc_product_id, out); } + void createKey(char* out) const { + return CreateKey(pc_factory_id, pc_product_id, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct JournalVoucher { - alignas(CACHE_LINE_SIZE) - std::uint64_t jv_voucher_id; + alignas(CACHE_LINE_SIZE) std::uint64_t jv_voucher_id; std::uint64_t jv_date; std::uint32_t jv_debit; std::uint32_t jv_credit; @@ -227,11 +235,11 @@ struct JournalVoucher { //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint64_t jv_voucher_id, char *out) { + static void CreateKey(uint64_t jv_voucher_id, char* out) { assign_as_bigendian(jv_voucher_id, &out[0]); } - void createKey(char *out) const { return CreateKey(jv_voucher_id, out); } + void createKey(char* out) const { return CreateKey(jv_voucher_id, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; @@ -256,41 +264,26 @@ public: void assign_id(std::atomic& i_id) { // skip root WIP to assign i_id in reserved range (<= FLAGS_bomb_work_size) - if (parent_ != nullptr) - i_id_ = i_id++; - for (auto& child : childs_) { - child->assign_id(i_id); - } + if (parent_ != nullptr) i_id_ = i_id++; + for (auto& child : childs_) { child->assign_id(i_id); } } - bool is_leaf() { - return childs_.empty(); - } + bool is_leaf() { return childs_.empty(); } - void get_all_nodes(std::vector& nodes) { - collect_nodes(nodes); - } + void get_all_nodes(std::vector& nodes) { collect_nodes(nodes); } void collect_nodes(std::vector& nodes) { nodes.push_back(this); - for (auto& child : childs_) { - child->collect_nodes(nodes); - } + for (auto& child : childs_) { child->collect_nodes(nodes); } } void get_all_leafs(std::vector& nodes) { - for (auto& child : childs_) { - child->collect_leafs(nodes); - } + for (auto& child : childs_) { child->collect_leafs(nodes); } } void collect_leafs(std::vector& nodes) { - if (this->is_leaf()) { - nodes.push_back(this); - } - for (auto& child : childs_) { - child->collect_nodes(nodes); - } + if (this->is_leaf()) { nodes.push_back(this); } + for (auto& child : childs_) { child->collect_nodes(nodes); } } double calculate_cost() { @@ -299,9 +292,7 @@ public: return unit_cost_ * quantity_; } double subtotal = 0; - for (auto& child : childs_) { - subtotal += child->calculate_cost(); - } + for (auto& child : childs_) { subtotal += child->calculate_cost(); } // std::cout << "subtotal: [" << i_id_ << "] " << subtotal << std::endl; return subtotal * quantity_; } @@ -311,1257 +302,1315 @@ struct JVID { union { uint64_t obj_; struct { - uint64_t thid: 8; - uint64_t vid: 56; + uint64_t thid : 8; + uint64_t vid : 56; }; }; - JVID() : obj_(0) {}; + JVID() : obj_(0){}; }; template class BombWorkload { public: - Param* param_; - Xoroshiro128Plus rnd_; - uint64_t jv_counter_ = 0; - std::vector s3_counters_; // to stabilize # of target products for L1 - uint32_t i_id_wip_end_; - uint32_t s5_thread_num; - std::map bom_cache_; - - BombWorkload() { - rnd_.init(); - - if (!FLAGS_bomb_mixed_mode) { - uint64_t total_threads = FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num; - if (FLAGS_bomb_l1_thread_num && FLAGS_thread_num < total_threads) { - std::cerr << "Total number of threads must be " << FLAGS_thread_num << std::endl; - ERR; - } - s5_thread_num = FLAGS_thread_num - ( - FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num); - } - - s3_counters_.resize(FLAGS_bomb_factory_size, 0); + Param* param_; + Xoroshiro128Plus rnd_; + uint64_t jv_counter_ = 0; + std::vector + s3_counters_; // to stabilize # of target products for L1 + uint32_t i_id_wip_end_; + uint32_t s5_thread_num; + std::map bom_cache_; + + BombWorkload() { + rnd_.init(); + + if (!FLAGS_bomb_mixed_mode) { + uint64_t total_threads = + FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num; + if (FLAGS_bomb_l1_thread_num && FLAGS_thread_num < total_threads) { + std::cerr << "Total number of threads must be " << FLAGS_thread_num + << std::endl; + ERR; + } + s5_thread_num = FLAGS_thread_num - + (FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num); } - static std::chrono::nanoseconds get_request_interval_nano() { - // use FLAGS_bomb_mixed_short_rate as request per seconds - return std::chrono::nanoseconds(1000*1000*1000/FLAGS_bomb_mixed_short_rate); - } + s3_counters_.resize(FLAGS_bomb_factory_size, 0); + } - static std::chrono::microseconds get_request_interval_micro() { - // use FLAGS_bomb_mixed_short_rate as request per minute - return std::chrono::microseconds(60*1000*1000/FLAGS_bomb_mixed_short_rate); + static std::chrono::nanoseconds get_request_interval_nano() { + // use FLAGS_bomb_mixed_short_rate as request per seconds + return std::chrono::nanoseconds(1000 * 1000 * 1000 / + FLAGS_bomb_mixed_short_rate); + } + + static std::chrono::microseconds get_request_interval_micro() { + // use FLAGS_bomb_mixed_short_rate as request per minute + return std::chrono::microseconds(60 * 1000 * 1000 / + FLAGS_bomb_mixed_short_rate); + } + + std::chrono::microseconds get_request_interval(TxType type) { + uint32_t rate; + switch (type) { + case TxType::UpdateProductCostMaster: + // L1 + rate = FLAGS_bomb_l1_rate / FLAGS_bomb_l1_thread_num; + break; + case TxType::UpdateMaterialCostMaster: + // S1 + rate = FLAGS_bomb_s1_rate / FLAGS_bomb_s1_thread_num; + break; + case TxType::IssueJournalVoucher: + // S2 + rate = FLAGS_bomb_s2_rate / FLAGS_bomb_s2_thread_num; + break; + case TxType::AddNewProduct: + // S3 + rate = FLAGS_bomb_s3_rate / FLAGS_bomb_s3_thread_num; + break; + case TxType::ChangeRawMaterial: + // S4 + rate = FLAGS_bomb_s4_rate / FLAGS_bomb_s4_thread_num; + break; + case TxType::ChangeProductQuantity: + // S5 + rate = FLAGS_bomb_s5_rate / s5_thread_num; + break; + default: + ERR; + break; } + return std::chrono::microseconds(60 * 1000 * 1000 / rate); + } - std::chrono::microseconds get_request_interval(TxType type) { - uint32_t rate; + class TxArgs { + public: + uint32_t f_id; + uint32_t p_id; + uint32_t i_id; + uint32_t m_id; + std::set i_id_set; + bool add; + + void generate(BombWorkload* w, TxExecutor& tx, TxType type) { switch (type) { + case TxType::IssueJournalVoucher: case TxType::UpdateProductCostMaster: - // L1 - rate = FLAGS_bomb_l1_rate / FLAGS_bomb_l1_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); break; case TxType::UpdateMaterialCostMaster: - // S1 - rate = FLAGS_bomb_s1_rate / FLAGS_bomb_s1_thread_num; - break; - case TxType::IssueJournalVoucher: - // S2 - rate = FLAGS_bomb_s2_rate / FLAGS_bomb_s2_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); + while (i_id_set.size() < FLAGS_bomb_mc_update_size) { + uint32_t m_id = w->rnd_.random_int( + get_i_id_material_start(), + get_i_id_material_start() + FLAGS_bomb_material_size - 1); + i_id_set.emplace(m_id); + } break; case TxType::AddNewProduct: - // S3 - rate = FLAGS_bomb_s3_rate / FLAGS_bomb_s3_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); + p_id = ItemIdCounter.fetch_add(1) + 1; + while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { + uint32_t i_id = w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + + FLAGS_bomb_work_size - 1); + i_id_set.emplace(i_id); + } +#ifdef ADD_OR_DELETE + // if switch add and delete in turn for each factory + add = w->s3_counters_.at(f_id - 1) % 2 == 0 ? true : false; + if (add) { + p_id = ItemIdCounter.fetch_add(1) + 1; + while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { + uint32_t i_id = w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + + FLAGS_bomb_work_size - 1); + i_id_set.emplace(i_id); + } + } + w->s3_counters_.at(f_id - 1)++; +#endif break; case TxType::ChangeRawMaterial: - // S4 - rate = FLAGS_bomb_s4_rate / FLAGS_bomb_s4_thread_num; + // get a root_wip item id randomly (deleted item is selected from the tree) + i_id = + w->rnd_.random_int(get_i_id_work_start(), + get_i_id_work_start() + FLAGS_bomb_work_size); + // get a material item id to insert + m_id = w->rnd_.random_int(get_i_id_material_start(), + get_i_id_material_start() + + FLAGS_bomb_material_size - 1); break; case TxType::ChangeProductQuantity: - // S5 - rate = FLAGS_bomb_s5_rate / s5_thread_num; + f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); break; default: + if (loadAcquire(tx.quit_)) break; ERR; - break; } - return std::chrono::microseconds(60*1000*1000/rate); } + }; - class TxArgs { - public: - uint32_t f_id; - uint32_t p_id; - uint32_t i_id; - uint32_t m_id; - std::set i_id_set; - bool add; - - void generate(BombWorkload* w, TxExecutor& tx, TxType type) { - switch (type) { - case TxType::IssueJournalVoucher: - case TxType::UpdateProductCostMaster: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - break; - case TxType::UpdateMaterialCostMaster: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - while (i_id_set.size() < FLAGS_bomb_mc_update_size) { - uint32_t m_id = w->rnd_.random_int( - get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1); - i_id_set.emplace(m_id); - } - break; - case TxType::AddNewProduct: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - p_id = ItemIdCounter.fetch_add(1) + 1; - while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { - uint32_t i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size - 1); - i_id_set.emplace(i_id); - } -#ifdef ADD_OR_DELETE - // if switch add and delete in turn for each factory - add = w->s3_counters_.at(f_id-1) % 2 == 0 ? true : false; - if (add) { - p_id = ItemIdCounter.fetch_add(1) + 1; - while (i_id_set.size() < FLAGS_bomb_tree_num_per_product) { - uint32_t i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size - 1); - i_id_set.emplace(i_id); - } - } - w->s3_counters_.at(f_id-1)++; -#endif - break; - case TxType::ChangeRawMaterial: - // get a root_wip item id randomly (deleted item is selected from the tree) - i_id = w->rnd_.random_int( - get_i_id_work_start(), - get_i_id_work_start() + FLAGS_bomb_work_size); - // get a material item id to insert - m_id = w->rnd_.random_int( - get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1); - break; - case TxType::ChangeProductQuantity: - f_id = w->rnd_.random_int(1, FLAGS_bomb_factory_size); - break; - default: - if (loadAcquire(tx.quit_)) break; - ERR; - } + class Query { + public: + TxType type; + TxArgs args; + + TxType decideType(TxExecutor& tx, [[maybe_unused]] Xoroshiro128Plus& r) { + // tx.thid_ is a non-negative thread index whose underlying type varies + // between protocols (int / size_t / uint8_t / unsigned int). Cast it + // to uint32_t once so each comparison against FLAGS_bomb_*_thread_num + // (declared as uint32) is sign-clean. + const uint32_t thid = static_cast(tx.thid_); + TxType txType; + if (thid < FLAGS_bomb_l1_thread_num) { + txType = TxType::UpdateProductCostMaster; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num) { + txType = TxType::UpdateMaterialCostMaster; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num) { + txType = TxType::IssueJournalVoucher; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + + FLAGS_bomb_s3_thread_num) { + txType = TxType::AddNewProduct; + } else if (thid < FLAGS_bomb_l1_thread_num + FLAGS_bomb_s1_thread_num + + FLAGS_bomb_s2_thread_num + + FLAGS_bomb_s3_thread_num + + FLAGS_bomb_s4_thread_num) { + txType = TxType::ChangeRawMaterial; + } else { + txType = TxType::ChangeProductQuantity; } - }; - class Query { - public: - TxType type; - TxArgs args; - - TxType decideType(TxExecutor& tx, [[maybe_unused]] Xoroshiro128Plus& r) { - // tx.thid_ is a non-negative thread index whose underlying type varies - // between protocols (int / size_t / uint8_t / unsigned int). Cast it - // to uint32_t once so each comparison against FLAGS_bomb_*_thread_num - // (declared as uint32) is sign-clean. - const uint32_t thid = static_cast(tx.thid_); - TxType txType; - if (thid < FLAGS_bomb_l1_thread_num) { - txType = TxType::UpdateProductCostMaster; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num) { - txType = TxType::UpdateMaterialCostMaster; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num) { - txType = TxType::IssueJournalVoucher; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num) { - txType = TxType::AddNewProduct; - } else if (thid < FLAGS_bomb_l1_thread_num - + FLAGS_bomb_s1_thread_num - + FLAGS_bomb_s2_thread_num - + FLAGS_bomb_s3_thread_num - + FLAGS_bomb_s4_thread_num) { - txType = TxType::ChangeRawMaterial; - } else { - txType = TxType::ChangeProductQuantity; - } - - return txType; - } + return txType; + } - std::pair getRequest(TxExecutor& tx) { - if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { - timepoint start = std::chrono::high_resolution_clock::now();; - return make_pair(TxType::UpdateProductCostMaster, start); - } else { - int queueIndex = tx.thid_ - FLAGS_bomb_l1_thread_num; - std::pair ret; - while (!loadAcquire(tx.quit_)) { - try { - ret = requestQueues[queueIndex].pop(); - break; - } catch (const std::out_of_range& e) { - std::this_thread::sleep_for(std::chrono::nanoseconds(100)); - } + std::pair getRequest(TxExecutor& tx) { + if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { + timepoint start = std::chrono::high_resolution_clock::now(); + ; + return make_pair(TxType::UpdateProductCostMaster, start); + } else { + int queueIndex = tx.thid_ - FLAGS_bomb_l1_thread_num; + std::pair ret; + while (!loadAcquire(tx.quit_)) { + try { + ret = requestQueues[queueIndex].pop(); + break; + } catch (const std::out_of_range& e) { + std::this_thread::sleep_for(std::chrono::nanoseconds(100)); } - return ret; } + return ret; } + } - timepoint generate(BombWorkload* workload, TxExecutor& tx) { - timepoint start; - if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { - type = TxType::UpdateProductCostMaster; - start = std::chrono::high_resolution_clock::now(); - } else if (!FLAGS_bomb_mixed_mode) { - type = decideType(tx, workload->rnd_); - start = std::chrono::high_resolution_clock::now(); - } else { - auto ret = getRequest(tx); - type = ret.first; - start = ret.second; - } - args.generate(workload, tx, type); - return start; + timepoint generate(BombWorkload* workload, TxExecutor& tx) { + timepoint start; + if (static_cast(tx.thid_) < FLAGS_bomb_l1_thread_num) { + type = TxType::UpdateProductCostMaster; + start = std::chrono::high_resolution_clock::now(); + } else if (!FLAGS_bomb_mixed_mode) { + type = decideType(tx, workload->rnd_); + start = std::chrono::high_resolution_clock::now(); + } else { + auto ret = getRequest(tx); + type = ret.first; + start = ret.second; } - }; - - static uint32_t get_i_id_product_start() { - return 1; + args.generate(workload, tx, type); + return start; } + }; - static uint32_t get_i_id_material_start() { - return get_i_id_product_start() + FLAGS_bomb_product_size; - } + static uint32_t get_i_id_product_start() { return 1; } - static uint32_t get_i_id_work_start() { - return get_i_id_material_start() + FLAGS_bomb_material_size; - } + static uint32_t get_i_id_material_start() { + return get_i_id_product_start() + FLAGS_bomb_product_size; + } - template - static inline auto select_random(Xoroshiro128Plus& r, const S &s) { - assert(!s.empty()); - auto itr = std::begin(s); - std::advance(itr, r.random_int(0, s.size()-1)); - return itr; - } + static uint32_t get_i_id_work_start() { + return get_i_id_material_start() + FLAGS_bomb_material_size; + } - template - inline T select_random(const std::set &s) { - assert(!s.empty()); - auto itr = std::begin(s); - std::advance(itr, rnd_.random_int(0, s.size()-1)); - return *itr; - } + template + static inline auto select_random(Xoroshiro128Plus& r, const S& s) { + assert(!s.empty()); + auto itr = std::begin(s); + std::advance(itr, r.random_int(0, s.size() - 1)); + return itr; + } - template - inline T select_random(const std::vector &v) { - assert(!v.empty()); - auto itr = std::begin(v); - std::advance(itr, rnd_.random_int(0, v.size()-1)); - return *itr; - } + template + inline T select_random(const std::set& s) { + assert(!s.empty()); + auto itr = std::begin(s); + std::advance(itr, rnd_.random_int(0, s.size() - 1)); + return *itr; + } - void prepare(TxExecutor& tx, Param *p) { - // for CC specific initialization parameter - this->param_ = p; - this->i_id_wip_end_ = ItemIdCounter.load(); - - if (FLAGS_bomb_use_cache) { - tx.reconnoiter_begin(); - std::vector product_ids; - // Return value intentionally discarded: the reconnaissance pass - // populates product_ids, which is all we need here. - (void)BombWorkload::select_im_by_factory(tx, 1, product_ids); - for (auto& p_id : product_ids) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - bom_cache_.emplace(p_id, root); - } - tx.reconnoiter_end(); - dump(tx.thid_, "[INFO] BoM cache creation done"); - } - } + template + inline T select_random(const std::vector& v) { + assert(!v.empty()); + auto itr = std::begin(v); + std::advance(itr, rnd_.random_int(0, v.size() - 1)); + return *itr; + } - Status update_product_cost_master(TxExecutor& tx, uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& pc = obj.ref(); - pc.pc_factory_id = f_id; - pc.pc_product_id = p_id; - pc.pc_cost = cost; - Status status = tx.update(Storage::ProductCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return status; - } + void prepare(TxExecutor& tx, Param* p) { + // for CC specific initialization parameter + this->param_ = p; + this->i_id_wip_end_ = ItemIdCounter.load(); - Node* build_bom_tree(TxExecutor& tx, uint32_t id) { - SimpleKey<8> item, low, up; - std::vector result; - Node* root = new Node(id); - std::vector next; - next.push_back(root); - while (next.size() != 0) { - auto node = next.back(); - next.pop_back(); - ItemMaster::CreateKey(node->i_id_, item.ptr()); - Status stat = tx.read_lock(Storage::ItemMaster, item.view()); - if (stat != Status::OK) { - std::stringstream ss; ss << "item id: " << node->i_id_; - dump(tx.thid_, ss.str()); - return nullptr; - } - ItemConstructionMaster::CreateKey(node->i_id_, 0, low.ptr()); - ItemConstructionMaster::CreateKey(node->i_id_ + 1, 0, up.ptr()); - tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms && !tx.reconnoitering_) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) { - dump(tx.thid_, "scan failed"); - return nullptr; // TODO: clean up tree - } - for (auto& tuple : result) { - const ItemConstructionMaster& ic = tuple->get_value().cast_to(); - // std::cout << " PID: " << ic.ic_parent_i_id - // << " ID: " << ic.ic_i_id - // << " Q: " << ic.ic_material_quantity << std::endl; - Node* n = new Node(ic.ic_i_id, ic.ic_material_quantity); - node->add_child(n); - next.push_back(n); - } + if (FLAGS_bomb_use_cache) { + tx.reconnoiter_begin(); + std::vector product_ids; + // Return value intentionally discarded: the reconnaissance pass + // populates product_ids, which is all we need here. + (void) BombWorkload::select_im_by_factory(tx, 1, + product_ids); + for (auto& p_id : product_ids) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + bom_cache_.emplace(p_id, root); } - return root; - } - - void insert_journal_voucher(TxExecutor& tx, uint32_t debit, uint32_t credit, double amount) { - JVID jv_id; - jv_id.thid = tx.thid_; - jv_id.vid = jv_counter_++; - SimpleKey<8> key; - JournalVoucher::CreateKey(jv_id.obj_, key.ptr()); - HeapObject obj; - obj.allocate(); - JournalVoucher& jv_tuple = obj.ref(); - jv_tuple.jv_voucher_id = jv_id.obj_; - jv_tuple.jv_date = 20220101235959; - jv_tuple.jv_debit = debit; - jv_tuple.jv_credit = credit; - jv_tuple.jv_amount = amount; - tx.insert(Storage::JournalVoucher, key.view(), TupleBody(key.view(), std::move(obj))); + tx.reconnoiter_end(); + dump(tx.thid_, "[INFO] BoM cache creation done"); } + } - void run_issue_journal_voucher(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - SimpleKey<8> factory, low, up; - std::vector result; - Factory::CreateKey(f_id, factory.ptr()); - ProductCostMaster::CreateKey(f_id, 0, low.ptr()); - ProductCostMaster::CreateKey(f_id+1, 0, up.ptr()); - Status stat = tx.read_lock(Storage::Factory, factory.view()); - if (stat != Status::OK) return; - tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) return; + Status update_product_cost_master(TxExecutor& tx, uint32_t f_id, + uint32_t p_id, double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& pc = obj.ref(); + pc.pc_factory_id = f_id; + pc.pc_product_id = p_id; + pc.pc_cost = cost; + Status status = tx.update(Storage::ProductCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return status; + } - uint32_t debit = 0; // product - uint32_t credit = 1; // work in progress + Node* build_bom_tree(TxExecutor& tx, uint32_t id) { + SimpleKey<8> item, low, up; + std::vector result; + Node* root = new Node(id); + std::vector next; + next.push_back(root); + while (next.size() != 0) { + auto node = next.back(); + next.pop_back(); + ItemMaster::CreateKey(node->i_id_, item.ptr()); + Status stat = tx.read_lock(Storage::ItemMaster, item.view()); + if (stat != Status::OK) { + std::stringstream ss; + ss << "item id: " << node->i_id_; + dump(tx.thid_, ss.str()); + return nullptr; + } + ItemConstructionMaster::CreateKey(node->i_id_, 0, low.ptr()); + ItemConstructionMaster::CreateKey(node->i_id_ + 1, 0, up.ptr()); + tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), + true, result); + if (FLAGS_bomb_interactive_ms && !tx.reconnoitering_) + sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) { + dump(tx.thid_, "scan failed"); + return nullptr; // TODO: clean up tree + } for (auto& tuple : result) { - const ProductCostMaster& pm = tuple->get_value().cast_to(); - double manufactured_quantity = 99.9; - insert_journal_voucher(tx, debit, credit, manufactured_quantity*pm.pc_cost); - if (tx.status_ == TransactionStatus::aborted) return; + const ItemConstructionMaster& ic = + tuple->get_value().cast_to(); + // std::cout << " PID: " << ic.ic_parent_i_id + // << " ID: " << ic.ic_i_id + // << " Q: " << ic.ic_material_quantity << std::endl; + Node* n = new Node(ic.ic_i_id, ic.ic_material_quantity); + node->add_child(n); + next.push_back(n); } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch } + return root; + } - void run_update_material_cost_master(TxExecutor& tx, Query& query) { - for (auto& m_id : query.args.i_id_set) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); - TupleBody* body; - tx.read(Storage::MaterialCostMaster, key.view(), &body); - MaterialCostMaster& old = body->get_value().cast_to(); - HeapObject obj; - obj.template allocate(); - MaterialCostMaster& mc = obj.ref(); - mc.mc_f_id = old.mc_f_id; - mc.mc_i_id = old.mc_i_id; - mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; - mc.mc_stock_price = old.mc_stock_price + 1.0; - tx.update(Storage::MaterialCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + void insert_journal_voucher(TxExecutor& tx, uint32_t debit, uint32_t credit, + double amount) { + JVID jv_id; + jv_id.thid = tx.thid_; + jv_id.vid = jv_counter_++; + SimpleKey<8> key; + JournalVoucher::CreateKey(jv_id.obj_, key.ptr()); + HeapObject obj; + obj.allocate(); + JournalVoucher& jv_tuple = obj.ref(); + jv_tuple.jv_voucher_id = jv_id.obj_; + jv_tuple.jv_date = 20220101235959; + jv_tuple.jv_debit = debit; + jv_tuple.jv_credit = credit; + jv_tuple.jv_amount = amount; + tx.insert(Storage::JournalVoucher, key.view(), + TupleBody(key.view(), std::move(obj))); + } + + void run_issue_journal_voucher(TxExecutor& tx, Query& query) { + uint32_t f_id = query.args.f_id; + SimpleKey<8> factory, low, up; + std::vector result; + Factory::CreateKey(f_id, factory.ptr()); + ProductCostMaster::CreateKey(f_id, 0, low.ptr()); + ProductCostMaster::CreateKey(f_id + 1, 0, up.ptr()); + Status stat = tx.read_lock(Storage::Factory, factory.view()); + if (stat != Status::OK) return; + tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, + result); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) return; + + uint32_t debit = 0; // product + uint32_t credit = 1; // work in progress + for (auto& tuple : result) { + const ProductCostMaster& pm = + tuple->get_value().cast_to(); + double manufactured_quantity = 99.9; + insert_journal_voucher(tx, debit, credit, + manufactured_quantity * pm.pc_cost); + if (tx.status_ == TransactionStatus::aborted) return; } + if (FLAGS_bomb_interactive_ms) + sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + } - void _run_update_product_cost_master_using_cache(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - std::map costs; - for (const auto& [p_id, root] : bom_cache_) { - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } + void run_update_material_cost_master(TxExecutor& tx, Query& query) { + for (auto& m_id : query.args.i_id_set) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); + TupleBody* body; + tx.read(Storage::MaterialCostMaster, key.view(), &body); + MaterialCostMaster& old = body->get_value().cast_to(); + HeapObject obj; + obj.template allocate(); + MaterialCostMaster& mc = obj.ref(); + mc.mc_f_id = old.mc_f_id; + mc.mc_i_id = old.mc_i_id; + mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; + mc.mc_stock_price = old.mc_stock_price + 1.0; + tx.update(Storage::MaterialCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) + sleepMicroSec(FLAGS_bomb_interactive_ms); // as batch + } + + void _run_update_product_cost_master_using_cache(TxExecutor& tx, + Query& query) { + uint32_t f_id = query.args.f_id; + std::map costs; + for (const auto& [p_id, root] : bom_cache_) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) + return; } - costs.emplace(p_id, root->calculate_cost()); } - for (const auto& [p_id, cost] : costs) { - update_product_cost_master(tx, f_id, p_id, cost); - if (tx.status_ == TransactionStatus::aborted) return; - if (tx.quit_) { // for long read phase - tx.abort(); - tx.status_ = TransactionStatus::invalid; - return; - } + costs.emplace(p_id, root->calculate_cost()); + } + for (const auto& [p_id, cost] : costs) { + update_product_cost_master(tx, f_id, p_id, cost); + if (tx.status_ == TransactionStatus::aborted) return; + if (tx.quit_) { // for long read phase + tx.abort(); + tx.status_ = TransactionStatus::invalid; + return; } } + } - void _run_update_product_cost_master(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - std::vector product_ids; - SimpleKey<8> factory; - Factory::CreateKey(f_id, factory.ptr()); - Status stat = tx.read_lock(Storage::Factory, factory.view()); - if (stat != Status::OK) return; - stat = select_im_by_factory(tx, f_id, product_ids); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) return; - if (product_ids.size() == 0) { - dump(tx.thid_, "ERROR: No target records."); - ERR; + void _run_update_product_cost_master(TxExecutor& tx, Query& query) { + uint32_t f_id = query.args.f_id; + std::vector product_ids; + SimpleKey<8> factory; + Factory::CreateKey(f_id, factory.ptr()); + Status stat = tx.read_lock(Storage::Factory, factory.view()); + if (stat != Status::OK) return; + stat = select_im_by_factory(tx, f_id, product_ids); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) return; + if (product_ids.size() == 0) { + dump(tx.thid_, "ERROR: No target records."); + ERR; + } + + std::map costs; + for (auto& p_id : product_ids) { + Node* root = build_bom_tree(tx, p_id); + if (root == nullptr) { + if (tx.status_ == TransactionStatus::aborted) { + return; + } else { + ERR; + } } - - std::map costs; - for (auto& p_id : product_ids) { - Node* root = build_bom_tree(tx, p_id); - if (root == nullptr) { - if (tx.status_ == TransactionStatus::aborted) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) return; - } else { - ERR; - } } - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } - } - costs.emplace(p_id, root->calculate_cost()); } - for (const auto& [p_id, cost] : costs) { - Status status = update_product_cost_master(tx, f_id, p_id, cost); - if (status == Status::WARN_NOT_FOUND) { - status = insert_product_cost_master(tx, f_id, p_id, 0.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - std::stringstream ss; - ss << "ERROR: insert product cost master fails " << f_id << " " << p_id; - dump(tx.thid_, ss.str()); - ERR; - } - } - if (tx.status_ == TransactionStatus::aborted) return; - if (tx.quit_) { // for long read phase - tx.abort(); - tx.status_ = TransactionStatus::invalid; - return; + costs.emplace(p_id, root->calculate_cost()); + } + for (const auto& [p_id, cost] : costs) { + Status status = update_product_cost_master(tx, f_id, p_id, cost); + if (status == Status::WARN_NOT_FOUND) { + status = insert_product_cost_master(tx, f_id, p_id, 0.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { + std::stringstream ss; + ss << "ERROR: insert product cost master fails " << f_id << " " + << p_id; + dump(tx.thid_, ss.str()); + ERR; } } - } - - void run_update_product_cost_master(TxExecutor& tx, Query& query) { - if (FLAGS_bomb_use_cache) { - _run_update_product_cost_master_using_cache(tx, query); - } else { - _run_update_product_cost_master(tx, query); + if (tx.status_ == TransactionStatus::aborted) return; + if (tx.quit_) { // for long read phase + tx.abort(); + tx.status_ = TransactionStatus::invalid; + return; } } + } - Status insert_item_master(TxExecutor& tx, uint32_t i_id) { - SimpleKey<8> key; - ItemMaster::CreateKey(i_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemMaster& i_tuple = obj.ref(); - i_tuple.i_id = i_id; - return tx.insert(Storage::ItemMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - - Status insert_item_construction_master(TxExecutor& tx, - uint32_t parent_id, uint32_t id, double material_quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = id; - ic_tuple.ic_material_quantity = material_quantity; - return tx.insert(Storage::ItemConstructionMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - - Status insert_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - return tx.insert(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); + void run_update_product_cost_master(TxExecutor& tx, Query& query) { + if (FLAGS_bomb_use_cache) { + _run_update_product_cost_master_using_cache(tx, query); + } else { + _run_update_product_cost_master(tx, query); } + } - Status insert_product_cost_master(TxExecutor& tx, uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& p_tuple = obj.ref(); - p_tuple.pc_factory_id = f_id; - p_tuple.pc_product_id = p_id; - p_tuple.pc_cost = cost; - return tx.insert(Storage::ProductCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status insert_item_master(TxExecutor& tx, uint32_t i_id) { + SimpleKey<8> key; + ItemMaster::CreateKey(i_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemMaster& i_tuple = obj.ref(); + i_tuple.i_id = i_id; + return tx.insert(Storage::ItemMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status delete_item_construction_master(TxExecutor& tx, uint32_t parent_id, uint32_t material_id) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); - return tx.delete_record(Storage::ItemConstructionMaster, key.view()); - } + Status insert_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t id, + double material_quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = id; + ic_tuple.ic_material_quantity = material_quantity; + return tx.insert(Storage::ItemConstructionMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status delete_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, uint32_t product_id) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - return tx.delete_record(Storage::ItemManufacturingMaster, key.view()); - } + Status insert_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + return tx.insert(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status update_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - return tx.update(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status insert_product_cost_master(TxExecutor& tx, uint32_t f_id, + uint32_t p_id, double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& p_tuple = obj.ref(); + p_tuple.pc_factory_id = f_id; + p_tuple.pc_product_id = p_id; + p_tuple.pc_cost = cost; + return tx.insert(Storage::ProductCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status upsert_item_manufacturing_master(TxExecutor& tx, - uint32_t factory_id, uint32_t product_id, double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - TupleBody* body; + Status delete_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t material_id) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); + return tx.delete_record(Storage::ItemConstructionMaster, key.view()); + } - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im = obj.ref(); - im.im_factory_id = factory_id; - im.im_product_id= product_id; - im.im_quantity = quantity; - - Status stat = tx.read(Storage::ItemManufacturingMaster, key.view(), &body); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) return stat; - if (stat == Status::WARN_NOT_FOUND) { - // insert - stat = tx.insert(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } else { - // update - stat = tx.update(Storage::ItemManufacturingMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; - } + Status delete_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + return tx.delete_record(Storage::ItemManufacturingMaster, key.view()); + } - Status update_item_construction_master(TxExecutor& tx, - uint32_t parent_id, uint32_t item_id, double quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, item_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = item_id; - ic_tuple.ic_material_quantity = quantity; - return tx.update(Storage::ItemConstructionMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } + Status update_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + return tx.update(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - Status run_add_new_prodcut(TxExecutor& tx, Query& query) { - Status stat; - uint32_t f_id = query.args.f_id; - uint32_t p_id = query.args.p_id; - for (auto& i_id : query.args.i_id_set) { - stat = insert_item_construction_master(tx, p_id, i_id, 1.0); - if (stat != Status::OK) { - std::stringstream ss; - ss << "WARN: insert bom table fails " << f_id << " " << i_id; - dump(tx.thid_, ss.str()); - return stat; - } - } + Status upsert_item_manufacturing_master(TxExecutor& tx, uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + TupleBody* body; + + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im = obj.ref(); + im.im_factory_id = factory_id; + im.im_product_id = product_id; + im.im_quantity = quantity; + + Status stat = tx.read(Storage::ItemManufacturingMaster, key.view(), &body); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (tx.status_ == TransactionStatus::aborted) return stat; + if (stat == Status::WARN_NOT_FOUND) { + // insert + stat = tx.insert(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } else { + // update + stat = tx.update(Storage::ItemManufacturingMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - stat = insert_item_manufacturing_master(tx, f_id, p_id, 10.0); - if (stat != Status::OK) { - std::stringstream ss; - ss << "WARN: insert product table fails " << f_id << " " << p_id; - dump(tx.thid_, ss.str()); - } + Status update_item_construction_master(TxExecutor& tx, uint32_t parent_id, + uint32_t item_id, double quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, item_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = item_id; + ic_tuple.ic_material_quantity = quantity; + return tx.update(Storage::ItemConstructionMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } - // insert item master - stat = insert_item_master(tx, p_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + Status run_add_new_prodcut(TxExecutor& tx, Query& query) { + Status stat; + uint32_t f_id = query.args.f_id; + uint32_t p_id = query.args.p_id; + for (auto& i_id : query.args.i_id_set) { + stat = insert_item_construction_master(tx, p_id, i_id, 1.0); if (stat != Status::OK) { std::stringstream ss; - ss << "WARN: insert item master fails " << f_id << " " << p_id; + ss << "WARN: insert bom table fails " << f_id << " " << i_id; dump(tx.thid_, ss.str()); - } - - return stat; - } - - Status run_delete_product(TxExecutor& tx, Query& query) { - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - if (stat != Status::OK) return stat; - - uint32_t product_id = select_random(product_ids); - stat = delete_item_manufacturing_master(tx, query.args.f_id, product_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - dump(tx.thid_, "delete product fail"); - } - return stat; - } - - void run_add_or_delete_product(TxExecutor& tx, Query& query) { - if (query.args.add) { - run_add_new_prodcut(tx, query); - } else { - run_delete_product(tx, query); + return stat; } } - void run_change_product(TxExecutor& tx, Query& query) { - SimpleKey<8> factory; - Factory::CreateKey(query.args.f_id, factory.ptr()); - Status stat = tx.write_lock(Storage::Factory, factory.view()); - if (stat != Status::OK) { - return; - } - stat = run_delete_product(tx, query); - if (stat != Status::OK) { - dump(tx.thid_, "delete product fail"); - return; - } else { - run_add_new_prodcut(tx, query); - } + stat = insert_item_manufacturing_master(tx, f_id, p_id, 10.0); + if (stat != Status::OK) { + std::stringstream ss; + ss << "WARN: insert product table fails " << f_id << " " << p_id; + dump(tx.thid_, ss.str()); } - Status run_add_raw_material(TxExecutor& tx, Query& query) { - Status stat = insert_item_construction_master(tx, query.args.i_id, query.args.m_id, 1.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; + // insert item master + stat = insert_item_master(tx, p_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { + std::stringstream ss; + ss << "WARN: insert item master fails " << f_id << " " << p_id; + dump(tx.thid_, ss.str()); } - Status run_delete_raw_material(TxExecutor& tx, Query& query) { - std::vector> material_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); - tx.reconnoiter_end(); - if (ret != Status::OK) return ret; + return stat; + } - if (material_ids.size() == 1) { - dump(tx.thid_, "WARN: No target records, but continue by adding a new material"); - return run_add_raw_material(tx, query); - } + Status run_delete_product(TxExecutor& tx, Query& query) { + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + if (stat != Status::OK) return stat; + + uint32_t product_id = select_random(product_ids); + stat = delete_item_manufacturing_master(tx, query.args.f_id, product_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { dump(tx.thid_, "delete product fail"); } + return stat; + } - auto pair = select_random(material_ids); - auto parent_id = pair.first; - auto material_id = pair.second; - Status stat = delete_item_construction_master(tx, parent_id, material_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - return stat; + void run_add_or_delete_product(TxExecutor& tx, Query& query) { + if (query.args.add) { + run_add_new_prodcut(tx, query); + } else { + run_delete_product(tx, query); } + } - Status run_add_or_delete_raw_material(TxExecutor& tx, Query& query) { - if (query.args.add) { - return run_add_raw_material(tx, query); - } else { - return run_delete_raw_material(tx, query); - } + void run_change_product(TxExecutor& tx, Query& query) { + SimpleKey<8> factory; + Factory::CreateKey(query.args.f_id, factory.ptr()); + Status stat = tx.write_lock(Storage::Factory, factory.view()); + if (stat != Status::OK) { return; } + stat = run_delete_product(tx, query); + if (stat != Status::OK) { + dump(tx.thid_, "delete product fail"); + return; + } else { + run_add_new_prodcut(tx, query); } + } - void run_change_raw_material(TxExecutor& tx, Query& query) { - std::vector> material_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); - tx.reconnoiter_end(); - if (ret != Status::OK) return; - - auto pair = select_random(material_ids); - auto parent_id = pair.first; - auto material_id = pair.second; - SimpleKey<8> item; - ItemMaster::CreateKey(parent_id, item.ptr()); - Status stat = tx.write_lock(Storage::ItemMaster, item.view()); - if (stat != Status::OK) return; - stat = delete_item_construction_master(tx, parent_id, material_id); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) return; - insert_item_construction_master(tx, parent_id, query.args.m_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); - } + Status run_add_raw_material(TxExecutor& tx, Query& query) { + Status stat = insert_item_construction_master(tx, query.args.i_id, + query.args.m_id, 1.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - void run_change_product_quantity(TxExecutor& tx, Query& query) { - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - // stringstream ss; ss << "[S5] f_id: " << query.args.f_id << " products: " << product_ids.size(); - // dump(tx.thid_, ss.str()); - if (stat != Status::OK) return; - if (product_ids.size() == 0) { - dump(tx.thid_, "ERROR: No target records."); - ERR; - } + Status run_delete_raw_material(TxExecutor& tx, Query& query) { + std::vector> material_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); + tx.reconnoiter_end(); + if (ret != Status::OK) return ret; + + if (material_ids.size() == 1) { + dump(tx.thid_, + "WARN: No target records, but continue by adding a new material"); + return run_add_raw_material(tx, query); + } + + auto pair = select_random(material_ids); + auto parent_id = pair.first; + auto material_id = pair.second; + Status stat = delete_item_construction_master(tx, parent_id, material_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + return stat; + } - uint32_t product_id = select_random(product_ids); - update_item_manufacturing_master(tx, query.args.f_id, product_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + Status run_add_or_delete_raw_material(TxExecutor& tx, Query& query) { + if (query.args.add) { + return run_add_raw_material(tx, query); + } else { + return run_delete_raw_material(tx, query); } + } - bool get_material_cost(TxExecutor& tx, uint32_t f_id, uint32_t m_id, double& cost) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); - TupleBody* body; - Status stat = tx.read(Storage::MaterialCostMaster, key.view(), &body); - if (tx.status_ == TransactionStatus::aborted) return false; - // Per CLAUDE.md: tx.read leaves *body unchanged on WARN_NOT_FOUND, - // so the cast_to below would dereference a stale pointer. - if (stat != Status::OK) return false; - MaterialCostMaster& mc = body->get_value().cast_to(); - cost = mc.mc_stock_price / mc.mc_stock_quantity; - return true; - } + void run_change_raw_material(TxExecutor& tx, Query& query) { + std::vector> material_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + auto ret = select_materials_by_item_id(tx, query.args.i_id, material_ids); + tx.reconnoiter_end(); + if (ret != Status::OK) return; + + auto pair = select_random(material_ids); + auto parent_id = pair.first; + auto material_id = pair.second; + SimpleKey<8> item; + ItemMaster::CreateKey(parent_id, item.ptr()); + Status stat = tx.write_lock(Storage::ItemMaster, item.view()); + if (stat != Status::OK) return; + stat = delete_item_construction_master(tx, parent_id, material_id); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) return; + insert_item_construction_master(tx, parent_id, query.args.m_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + } - Status select_materials_by_item_id(TxExecutor& tx, uint32_t i_id, - std::vector>& material_ids) { - // WIP with i_id may not have leaf nodes (materials), - // so recursively scan and get all materials - Node* parent = build_bom_tree(tx, i_id); - if (parent == nullptr) ERR; // TODO: retry? + void run_change_product_quantity(TxExecutor& tx, Query& query) { + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = select_im_by_factory(tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + // stringstream ss; ss << "[S5] f_id: " << query.args.f_id << " products: " << product_ids.size(); + // dump(tx.thid_, ss.str()); + if (stat != Status::OK) return; + if (product_ids.size() == 0) { + dump(tx.thid_, "ERROR: No target records."); + ERR; + } + + uint32_t product_id = select_random(product_ids); + update_item_manufacturing_master(tx, query.args.f_id, product_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMicroSec(FLAGS_bomb_interactive_ms); + } - std::vector nodes; - parent->get_all_leafs(nodes); + bool get_material_cost(TxExecutor& tx, uint32_t f_id, uint32_t m_id, + double& cost) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); + TupleBody* body; + Status stat = tx.read(Storage::MaterialCostMaster, key.view(), &body); + if (tx.status_ == TransactionStatus::aborted) return false; + // Per CLAUDE.md: tx.read leaves *body unchanged on WARN_NOT_FOUND, + // so the cast_to below would dereference a stale pointer. + if (stat != Status::OK) return false; + MaterialCostMaster& mc = body->get_value().cast_to(); + cost = mc.mc_stock_price / mc.mc_stock_quantity; + return true; + } - if (nodes.size() == 0) ERR; // TODO: retry? - for (auto& node : nodes) { - material_ids.emplace_back(node->parent_->i_id_, node->i_id_); - } - return Status::OK; + Status select_materials_by_item_id( + TxExecutor& tx, uint32_t i_id, + std::vector>& material_ids) { + // WIP with i_id may not have leaf nodes (materials), + // so recursively scan and get all materials + Node* parent = build_bom_tree(tx, i_id); + if (parent == nullptr) ERR; // TODO: retry? + + std::vector nodes; + parent->get_all_leafs(nodes); + + if (nodes.size() == 0) ERR; // TODO: retry? + for (auto& node : nodes) { + material_ids.emplace_back(node->parent_->i_id_, node->i_id_); } + return Status::OK; + } - void select_ic_by_product(TxExecutor& tx, uint32_t p_id) { - // for debug - SimpleKey<8> low, up; - std::vector result; - ItemConstructionMaster::CreateKey(p_id, 0, low.ptr()); - ItemConstructionMaster::CreateKey(p_id+1, 0, up.ptr()); - tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), false, result); - for (auto& tuple : result) { - const ItemConstructionMaster& ic = tuple->get_value().cast_to(); - std::cout << " PID: " << ic.ic_parent_i_id - << " ID: " << ic.ic_i_id - << " Q: " << ic.ic_material_quantity << std::endl; - } + void select_ic_by_product(TxExecutor& tx, uint32_t p_id) { + // for debug + SimpleKey<8> low, up; + std::vector result; + ItemConstructionMaster::CreateKey(p_id, 0, low.ptr()); + ItemConstructionMaster::CreateKey(p_id + 1, 0, up.ptr()); + tx.scan(Storage::ItemConstructionMaster, low.view(), false, up.view(), + false, result); + for (auto& tuple : result) { + const ItemConstructionMaster& ic = + tuple->get_value().cast_to(); + std::cout << " PID: " << ic.ic_parent_i_id << " ID: " << ic.ic_i_id + << " Q: " << ic.ic_material_quantity << std::endl; } + } - Status select_im_by_factory(TxExecutor& tx, uint32_t factory_id, std::vector& product_ids) { - SimpleKey<8> low, up; - std::vector result; - ItemManufacturingMaster::CreateKey(factory_id, 0, low.ptr()); - ItemManufacturingMaster::CreateKey(factory_id+1, 0, up.ptr()); - Status stat = tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), true, result); - if (tx.status_ == TransactionStatus::aborted) { - stringstream ss; ss << "[common] failed to scan manufactured products f_id: " << factory_id; - dump(tx.thid_, ss.str()); - return stat; - } - for (auto& tuple : result) { - const ItemManufacturingMaster& im = tuple->get_value().cast_to(); - product_ids.emplace_back(im.im_product_id); - } + Status select_im_by_factory(TxExecutor& tx, uint32_t factory_id, + std::vector& product_ids) { + SimpleKey<8> low, up; + std::vector result; + ItemManufacturingMaster::CreateKey(factory_id, 0, low.ptr()); + ItemManufacturingMaster::CreateKey(factory_id + 1, 0, up.ptr()); + Status stat = tx.scan(Storage::ItemManufacturingMaster, low.view(), false, + up.view(), true, result); + if (tx.status_ == TransactionStatus::aborted) { + stringstream ss; + ss << "[common] failed to scan manufactured products f_id: " + << factory_id; + dump(tx.thid_, ss.str()); return stat; } - - void select_all_im_master(TxExecutor& tx) { - // for debug - SimpleKey<8> low, up; - std::vector result; - ItemManufacturingMaster::CreateKey(1, 0, low.ptr()); - ItemManufacturingMaster::CreateKey(FLAGS_bomb_factory_size, FLAGS_bomb_product_size, up.ptr()); - tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), false, result); - for (auto& tuple : result) { - const ItemManufacturingMaster& im = tuple->get_value().cast_to(); - std::cout << " FID: " << im.im_factory_id - << " PID: " << im.im_product_id - << " Q: " << im.im_quantity << std::endl; - } + for (auto& tuple : result) { + const ItemManufacturingMaster& im = + tuple->get_value().cast_to(); + product_ids.emplace_back(im.im_product_id); } + return stat; + } - // void dump_all_ic_master() { - // // for debug (single-version CC only) - // SimpleKey<8> low, up; - // std::vector result; - // ItemConstructionMaster::CreateKey(1, 0, low.ptr()); - // ItemConstructionMaster::CreateKey(10000000, 0, up.ptr()); - // std::vector scan_res; - // Masstrees[get_storage(Storage::ItemConstructionMaster)].scan( - // low.view().data(), low.view().size(), false, - // up.view().data(), up.view().size(), true, - // &scan_res, false); - // for (auto& tuple : scan_res) { - // const ItemConstructionMaster& ic = tuple->body_.get_value().cast_to(); - // std::cout << " PID: " << ic.ic_parent_i_id - // << " ID: " << ic.ic_i_id - // << " Q: " << ic.ic_material_quantity - // << " TUPLE: " << tuple << std::endl; - // } - // } - - template - void run(TxExecutor& tx) { - Query query; - auto start = query.generate(this, tx); - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); - } - - if (loadAcquire(tx.quit_)) return; - - tx.begin(); + void select_all_im_master(TxExecutor& tx) { + // for debug + SimpleKey<8> low, up; + std::vector result; + ItemManufacturingMaster::CreateKey(1, 0, low.ptr()); + ItemManufacturingMaster::CreateKey(FLAGS_bomb_factory_size, + FLAGS_bomb_product_size, up.ptr()); + tx.scan(Storage::ItemManufacturingMaster, low.view(), false, up.view(), + false, result); + for (auto& tuple : result) { + const ItemManufacturingMaster& im = + tuple->get_value().cast_to(); + std::cout << " FID: " << im.im_factory_id << " PID: " << im.im_product_id + << " Q: " << im.im_quantity << std::endl; + } + } - switch (query.type) { - case TxType::IssueJournalVoucher: - run_issue_journal_voucher(tx, query); - break; - case TxType::UpdateMaterialCostMaster: - run_update_material_cost_master(tx, query); - break; - case TxType::UpdateProductCostMaster: - run_update_product_cost_master(tx, query); - break; - case TxType::AddNewProduct: - run_change_product(tx, query); - break; - case TxType::ChangeRawMaterial: - run_change_raw_material(tx, query); - break; - case TxType::ChangeProductQuantity: - run_change_product_quantity(tx, query); - break; - default: - ERR; - break; - } + // void dump_all_ic_master() { + // // for debug (single-version CC only) + // SimpleKey<8> low, up; + // std::vector result; + // ItemConstructionMaster::CreateKey(1, 0, low.ptr()); + // ItemConstructionMaster::CreateKey(10000000, 0, up.ptr()); + // std::vector scan_res; + // Masstrees[get_storage(Storage::ItemConstructionMaster)].scan( + // low.view().data(), low.view().size(), false, + // up.view().data(), up.view().size(), true, + // &scan_res, false); + // for (auto& tuple : scan_res) { + // const ItemConstructionMaster& ic = tuple->body_.get_value().cast_to(); + // std::cout << " PID: " << ic.ic_parent_i_id + // << " ID: " << ic.ic_i_id + // << " Q: " << ic.ic_material_quantity + // << " TUPLE: " << tuple << std::endl; + // } + // } + + template + void run(TxExecutor& tx) { + Query query; + auto start = query.generate(this, tx); + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + + switch (query.type) { + case TxType::IssueJournalVoucher: + run_issue_journal_voucher(tx, query); + break; + case TxType::UpdateMaterialCostMaster: + run_update_material_cost_master(tx, query); + break; + case TxType::UpdateProductCostMaster: + run_update_product_cost_master(tx, query); + break; + case TxType::AddNewProduct: + run_change_product(tx, query); + break; + case TxType::ChangeRawMaterial: + run_change_raw_material(tx, query); + break; + case TxType::ChangeProductQuantity: + run_change_product_quantity(tx, query); + break; + default: + ERR; + break; + } - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start); - if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { - auto interval = get_request_interval(query.type); - if (elapsed < interval) { - std::this_thread::sleep_for((interval - elapsed) * 0.95); - } - } - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + elapsed.count(); - return; + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); + if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { + auto interval = get_request_interval(query.type); + if (elapsed < interval) { + std::this_thread::sleep_for((interval - elapsed) * 0.95); + } } + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + + elapsed.count(); + return; + } - static void insert_factory(Param *param, uint32_t f_id) { - SimpleKey<8> key; - Factory::CreateKey(f_id, key.ptr()); - HeapObject obj; - obj.allocate(); - Factory& f_tuple = obj.ref(); - f_tuple.f_id = f_id; - Tuple* tmp = new Tuple(); - tmp->init(0, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::Factory)].insert_value(key.view(), tmp); - } + static void insert_factory(Param* param, uint32_t f_id) { + SimpleKey<8> key; + Factory::CreateKey(f_id, key.ptr()); + HeapObject obj; + obj.allocate(); + Factory& f_tuple = obj.ref(); + f_tuple.f_id = f_id; + Tuple* tmp = new Tuple(); + tmp->init(0, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::Factory)].insert_value(key.view(), tmp); + } - static void insert_item_master(Param *param, uint32_t i_id) { - SimpleKey<8> key; - ItemMaster::CreateKey(i_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemMaster& i_tuple = obj.ref(); - i_tuple.i_id = i_id; - Tuple* tmp = new Tuple(); - tmp->init(0, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::ItemMaster)].insert_value(key.view(), tmp); - } + static void insert_item_master(Param* param, uint32_t i_id) { + SimpleKey<8> key; + ItemMaster::CreateKey(i_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemMaster& i_tuple = obj.ref(); + i_tuple.i_id = i_id; + Tuple* tmp = new Tuple(); + tmp->init(0, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::ItemMaster)].insert_value(key.view(), tmp); + } - static void insert_item_construction_master([[maybe_unused]] size_t thid, Param *param, - uint32_t parent_id, uint32_t id, - double material_quantity) { - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemConstructionMaster& ic_tuple = obj.ref(); - ic_tuple.ic_parent_i_id = parent_id; - ic_tuple.ic_i_id = id; - ic_tuple.ic_material_quantity = material_quantity; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::ItemConstructionMaster)].insert_value(key.view(), tmp); - } + static void insert_item_construction_master([[maybe_unused]] size_t thid, + Param* param, uint32_t parent_id, + uint32_t id, + double material_quantity) { + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemConstructionMaster& ic_tuple = obj.ref(); + ic_tuple.ic_parent_i_id = parent_id; + ic_tuple.ic_i_id = id; + ic_tuple.ic_material_quantity = material_quantity; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::ItemConstructionMaster)].insert_value( + key.view(), tmp); + } - static void insert_item_manufacturing_master([[maybe_unused]] size_t thid, Param *param, - uint32_t factory_id, uint32_t product_id, - double quantity) { - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ItemManufacturingMaster& im_tuple = obj.ref(); - im_tuple.im_factory_id = factory_id; - im_tuple.im_product_id = product_id; - im_tuple.im_quantity = quantity; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); - Masstrees[get_storage(Storage::ItemManufacturingMaster)].insert_value(key.view(), tmp); - } + static void insert_item_manufacturing_master([[maybe_unused]] size_t thid, + Param* param, + uint32_t factory_id, + uint32_t product_id, + double quantity) { + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(factory_id, product_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ItemManufacturingMaster& im_tuple = obj.ref(); + im_tuple.im_factory_id = factory_id; + im_tuple.im_product_id = product_id; + im_tuple.im_quantity = quantity; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), param); + Masstrees[get_storage(Storage::ItemManufacturingMaster)].insert_value( + key.view(), tmp); + } - static void insert_material_cost_master([[maybe_unused]] size_t thid, Param *p, - uint32_t f_id, uint32_t m_id, double quantity, double price) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); - HeapObject obj; - obj.allocate(); - MaterialCostMaster& m_tuple = obj.ref(); - m_tuple.mc_f_id = f_id; - m_tuple.mc_i_id = m_id; - m_tuple.mc_stock_quantity = quantity; - m_tuple.mc_stock_price = price; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); - Masstrees[get_storage(Storage::MaterialCostMaster)].insert_value(key.view(), tmp); - } + static void insert_material_cost_master([[maybe_unused]] size_t thid, + Param* p, uint32_t f_id, + uint32_t m_id, double quantity, + double price) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(f_id, m_id, key.ptr()); + HeapObject obj; + obj.allocate(); + MaterialCostMaster& m_tuple = obj.ref(); + m_tuple.mc_f_id = f_id; + m_tuple.mc_i_id = m_id; + m_tuple.mc_stock_quantity = quantity; + m_tuple.mc_stock_price = price; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); + Masstrees[get_storage(Storage::MaterialCostMaster)].insert_value(key.view(), + tmp); + } - static void insert_product_cost_master([[maybe_unused]] size_t thid, Param *p, - uint32_t f_id, uint32_t p_id, double cost) { - SimpleKey<8> key; - ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); - HeapObject obj; - obj.allocate(); - ProductCostMaster& p_tuple = obj.ref(); - p_tuple.pc_factory_id = f_id; - p_tuple.pc_product_id = p_id; - p_tuple.pc_cost = cost; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); - Masstrees[get_storage(Storage::ProductCostMaster)].insert_value(key.view(), tmp); - } + static void insert_product_cost_master([[maybe_unused]] size_t thid, Param* p, + uint32_t f_id, uint32_t p_id, + double cost) { + SimpleKey<8> key; + ProductCostMaster::CreateKey(f_id, p_id, key.ptr()); + HeapObject obj; + obj.allocate(); + ProductCostMaster& p_tuple = obj.ref(); + p_tuple.pc_factory_id = f_id; + p_tuple.pc_product_id = p_id; + p_tuple.pc_cost = cost; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); + Masstrees[get_storage(Storage::ProductCostMaster)].insert_value(key.view(), + tmp); + } - static void load_work_in_progress([[maybe_unused]] size_t thid, Param* param, - std::atomic& i_id, uint64_t start, uint64_t end) { + static void load_work_in_progress([[maybe_unused]] size_t thid, Param* param, + std::atomic& i_id, uint64_t start, + uint64_t end) { #if MASSTREE_USE - MasstreeWrapper::thread_init(thid); + MasstreeWrapper::thread_init(thid); #endif - Xoroshiro128Plus rand; - rand.init(); - for (auto i = start; i <= end; ++i) { - // TODO: randomized tree size (number of WIP nodes in the tree) - auto tree_size = FLAGS_bomb_base_tree_size; - - // create root - Node* root = new Node(); - std::vector nodes; - nodes.push_back(root); - - // add work in progress - while (nodes.size() < tree_size) { - assert(!nodes.empty()); - Node* node = new Node(); - Node* parent = nodes.at(rand.random_int(0, nodes.size()-1)); - parent->add_child(node); - nodes.push_back(node); - } + Xoroshiro128Plus rand; + rand.init(); + for (auto i = start; i <= end; ++i) { + // TODO: randomized tree size (number of WIP nodes in the tree) + auto tree_size = FLAGS_bomb_base_tree_size; + + // create root + Node* root = new Node(); + std::vector nodes; + nodes.push_back(root); + + // add work in progress + while (nodes.size() < tree_size) { + assert(!nodes.empty()); + Node* node = new Node(); + Node* parent = nodes.at(rand.random_int(0, nodes.size() - 1)); + parent->add_child(node); + nodes.push_back(node); + } - // assign i_id for work in progress recursively - root->i_id_ = get_i_id_work_start() + i; - root->assign_id(i_id); - - // assign raw materials - for (auto& node : nodes) { - if (!node->is_leaf()) continue; - auto material_size = FLAGS_bomb_material_per_wip; - std::set s; - while (s.size() < material_size) - s.emplace(rand.random_int(get_i_id_material_start(), - get_i_id_material_start() + FLAGS_bomb_material_size - 1)); - for (auto& i_id_material : s) - node->add_child(new Node(i_id_material)); - } + // assign i_id for work in progress recursively + root->i_id_ = get_i_id_work_start() + i; + root->assign_id(i_id); - // insert item construction master - nodes.clear(); - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->parent_ == nullptr) continue; - insert_item_construction_master(thid, param, node->parent_->i_id_, node->i_id_, 1.0); - } + // assign raw materials + for (auto& node : nodes) { + if (!node->is_leaf()) continue; + auto material_size = FLAGS_bomb_material_per_wip; + std::set s; + while (s.size() < material_size) + s.emplace(rand.random_int(get_i_id_material_start(), + get_i_id_material_start() + + FLAGS_bomb_material_size - 1)); + for (auto& i_id_material : s) node->add_child(new Node(i_id_material)); } - } - static void load_item_construction_master_product([[maybe_unused]] size_t thid, Param *param, - uint32_t p_id, std::set& wip_ids) { - for (auto& id : wip_ids) { - insert_item_construction_master(thid, param, p_id, id, 1.0); + // insert item construction master + nodes.clear(); + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->parent_ == nullptr) continue; + insert_item_construction_master(thid, param, node->parent_->i_id_, + node->i_id_, 1.0); } } + } - static void load_item_manufacturing_master([[maybe_unused]] size_t thid, Param *param, - Xoroshiro128Plus& rand, - std::set& product_ids, - std::vector>& pm_keys) { - for (uint32_t i = 0; i < FLAGS_bomb_base_product_size_per_factory; i++) { // all - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } - product_ids.erase(itr); - } + static void + load_item_construction_master_product([[maybe_unused]] size_t thid, + Param* param, uint32_t p_id, + std::set& wip_ids) { + for (auto& id : wip_ids) { + insert_item_construction_master(thid, param, p_id, id, 1.0); + } + } - // Disable different product size per factory to improve fairness - // when choosing a factory in long batch transaction -#ifdef USE_DIFFERENT_PRODUCT_SIZE_PER_FACTORY - for (uint32_t i = 0; i < 20; i++) { // 50% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 2 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } - } - product_ids.erase(itr); + static void load_item_manufacturing_master( + [[maybe_unused]] size_t thid, Param* param, Xoroshiro128Plus& rand, + std::set& product_ids, + std::vector>& pm_keys) { + for (uint32_t i = 0; i < FLAGS_bomb_base_product_size_per_factory; + i++) { // all + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } + product_ids.erase(itr); + } - for (uint32_t i = 0; i < 30; i++) { // 25% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 4 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } + // Disable different product size per factory to improve fairness + // when choosing a factory in long batch transaction +#ifdef USE_DIFFERENT_PRODUCT_SIZE_PER_FACTORY + for (uint32_t i = 0; i < 20; i++) { // 50% + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + if (f_id % 2 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } - product_ids.erase(itr); } + product_ids.erase(itr); + } - for (uint32_t i = 0; i < 40; i++) { // 10% - auto itr = select_random(rand, product_ids); - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - if (f_id % 10 == 1) { - insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); - pm_keys.emplace_back(f_id, *itr); - } + for (uint32_t i = 0; i < 30; i++) { // 25% + auto itr = select_random(rand, product_ids); + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + if (f_id % 4 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } - product_ids.erase(itr); } -#endif + product_ids.erase(itr); } - static void load_material_cost_master([[maybe_unused]] size_t thid, Param *param) { + for (uint32_t i = 0; i < 40; i++) { // 10% + auto itr = select_random(rand, product_ids); for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - for (uint32_t m_id = get_i_id_material_start(); - m_id < get_i_id_material_start() + FLAGS_bomb_material_size; m_id++) { - insert_material_cost_master(0, param, f_id, m_id, 1.0, 1.0); + if (f_id % 10 == 1) { + insert_item_manufacturing_master(0, param, f_id, *itr, 1.0); + pm_keys.emplace_back(f_id, *itr); } } + product_ids.erase(itr); } +#endif + } - static void load_product_cost_master([[maybe_unused]] size_t thid, Param *param, - std::vector>& pm_keys) { - for (auto& [f_id, p_id] : pm_keys) { - insert_product_cost_master(0, param, f_id, p_id, 0.0); + static void load_material_cost_master([[maybe_unused]] size_t thid, + Param* param) { + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + for (uint32_t m_id = get_i_id_material_start(); + m_id < get_i_id_material_start() + FLAGS_bomb_material_size; + m_id++) { + insert_material_cost_master(0, param, f_id, m_id, 1.0, 1.0); } } + } - static uint32_t getTableNum() { - return (uint32_t)Storage::Size; - } - - static void makeDB(Param* param) { - Xoroshiro128Plus rand; - rand.init(); - size_t maxthread = 64; - std::vector thv; - auto product_start = get_i_id_product_start(); - auto root_wip_start = get_i_id_work_start(); - auto non_root_wip_start = get_i_id_work_start() + FLAGS_bomb_work_size; - ItemIdCounter.store(non_root_wip_start); - - // TODO: move this codes to appropriate place - set_tx_name(TxType::UpdateMaterialCostMaster, "UpdateMaterialCostMaster"); - set_tx_name(TxType::UpdateProductCostMaster, "UpdateProductCostMaster"); - set_tx_name(TxType::IssueJournalVoucher, "IssueJournalVoucher"); - set_tx_name(TxType::AddNewProduct, "AddNewProduct"); - set_tx_name(TxType::ChangeRawMaterial, "ChangeRawMaterial"); - set_tx_name(TxType::ChangeProductQuantity, "ChangeProductQuantity"); - - std::cout << "load factory" << std::endl; - for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { - insert_factory(param, f_id); - } - - // TODO: can we remove thid from loader function? - // load item construction master for work in progress - std::cout << "load item construction master for work in progress" << std::endl; - for (size_t i = 0; i < maxthread; i++) { - thv.emplace_back(load_work_in_progress, i, param, std::ref(ItemIdCounter), - i * (FLAGS_bomb_work_size / maxthread), - (i + 1) * ((FLAGS_bomb_work_size + maxthread - 1) / maxthread) - 1); - } - for (auto &th : thv) th.join(); - - std::cout << "load item master" << std::endl; - for (uint32_t i_id = 1; i_id <= ItemIdCounter; i_id++) { - insert_item_master(param, i_id); - } - - // load item construction master for finished products - std::cout << "load item construction master for finished products" << std::endl; - std::set product_id_set; // for loading item manufacturing master - for (uint32_t p_id = product_start; - p_id < product_start + FLAGS_bomb_product_size; p_id++) { - auto tree_size = FLAGS_bomb_tree_num_per_product; - std::set s; - while (s.size() < tree_size) - s.emplace(rand.random_int(root_wip_start, - root_wip_start + FLAGS_bomb_work_size - 1)); - load_item_construction_master_product(0, param, p_id, s); - product_id_set.emplace(p_id); - } - - // load item manufacturing master - std::cout << "load item manufacturing master " << std::endl; - std::vector> pm_keys; // for load product cost master - load_item_manufacturing_master(0, param, rand, product_id_set, pm_keys); - - // load material cost master - std::cout << "load material cost master " << std::endl; - load_material_cost_master(0, param); - - // load product cost master - std::cout << "load product cost master " << std::endl; - load_product_cost_master(0, param, pm_keys); - - std::cout << "loading done" << std::endl; + static void load_product_cost_master( + [[maybe_unused]] size_t thid, Param* param, + std::vector>& pm_keys) { + for (auto& [f_id, p_id] : pm_keys) { + insert_product_cost_master(0, param, f_id, p_id, 0.0); } + } - static TxType decideType(Xoroshiro128Plus& r, uint64_t* thresholds) { - uint64_t x = r.random_int(1, 100); - if (x > thresholds[0]) return TxType::UpdateMaterialCostMaster; - if (x > thresholds[1]) return TxType::IssueJournalVoucher; - if (x > thresholds[2]) return TxType::AddNewProduct; - if (x > thresholds[3]) return TxType::ChangeRawMaterial; - return TxType::ChangeProductQuantity; - } + static uint32_t getTableNum() { return (uint32_t) Storage::Size; } + + static void makeDB(Param* param) { + Xoroshiro128Plus rand; + rand.init(); + size_t maxthread = 64; + std::vector thv; + auto product_start = get_i_id_product_start(); + auto root_wip_start = get_i_id_work_start(); + auto non_root_wip_start = get_i_id_work_start() + FLAGS_bomb_work_size; + ItemIdCounter.store(non_root_wip_start); + + // TODO: move this codes to appropriate place + set_tx_name(TxType::UpdateMaterialCostMaster, "UpdateMaterialCostMaster"); + set_tx_name(TxType::UpdateProductCostMaster, "UpdateProductCostMaster"); + set_tx_name(TxType::IssueJournalVoucher, "IssueJournalVoucher"); + set_tx_name(TxType::AddNewProduct, "AddNewProduct"); + set_tx_name(TxType::ChangeRawMaterial, "ChangeRawMaterial"); + set_tx_name(TxType::ChangeProductQuantity, "ChangeProductQuantity"); + + std::cout << "load factory" << std::endl; + for (uint32_t f_id = 1; f_id <= FLAGS_bomb_factory_size; f_id++) { + insert_factory(param, f_id); + } + + // TODO: can we remove thid from loader function? + // load item construction master for work in progress + std::cout << "load item construction master for work in progress" + << std::endl; + for (size_t i = 0; i < maxthread; i++) { + thv.emplace_back( + load_work_in_progress, i, param, std::ref(ItemIdCounter), + i * (FLAGS_bomb_work_size / maxthread), + (i + 1) * ((FLAGS_bomb_work_size + maxthread - 1) / maxthread) - 1); + } + for (auto& th : thv) th.join(); + + std::cout << "load item master" << std::endl; + for (uint32_t i_id = 1; i_id <= ItemIdCounter; i_id++) { + insert_item_master(param, i_id); + } + + // load item construction master for finished products + std::cout << "load item construction master for finished products" + << std::endl; + std::set product_id_set; // for loading item manufacturing master + for (uint32_t p_id = product_start; + p_id < product_start + FLAGS_bomb_product_size; p_id++) { + auto tree_size = FLAGS_bomb_tree_num_per_product; + std::set s; + while (s.size() < tree_size) + s.emplace(rand.random_int(root_wip_start, + root_wip_start + FLAGS_bomb_work_size - 1)); + load_item_construction_master_product(0, param, p_id, s); + product_id_set.emplace(p_id); + } + + // load item manufacturing master + std::cout << "load item manufacturing master " << std::endl; + std::vector> + pm_keys; // for load product cost master + load_item_manufacturing_master(0, param, rand, product_id_set, pm_keys); + + // load material cost master + std::cout << "load material cost master " << std::endl; + load_material_cost_master(0, param); + + // load product cost master + std::cout << "load product cost master " << std::endl; + load_product_cost_master(0, param, pm_keys); + + std::cout << "loading done" << std::endl; + } - static void request_dispatcher([[maybe_unused]] size_t thid, char &ready, const bool &start, const bool &quit) { - // prepare queues for short transactions - int numQueues = TotalThreadNum - FLAGS_bomb_l1_thread_num; - requestQueues = new ConcurrentQueue>[numQueues]; + static TxType decideType(Xoroshiro128Plus& r, uint64_t* thresholds) { + uint64_t x = r.random_int(1, 100); + if (x > thresholds[0]) return TxType::UpdateMaterialCostMaster; + if (x > thresholds[1]) return TxType::IssueJournalVoucher; + if (x > thresholds[2]) return TxType::AddNewProduct; + if (x > thresholds[3]) return TxType::ChangeRawMaterial; + return TxType::ChangeProductQuantity; + } - uint64_t thresholds[4]; - int32_t perc_s5 = 100 - (FLAGS_bomb_perc_s1 + FLAGS_bomb_perc_s2 + FLAGS_bomb_perc_s3 + FLAGS_bomb_perc_s4); - if (perc_s5 < 0) { - std::cout << "Specify short transaction percentage to make the total 100" << std::endl; - ERR; - } - thresholds[3] = perc_s5; - thresholds[2] = thresholds[3] + FLAGS_bomb_perc_s4; - thresholds[1] = thresholds[2] + FLAGS_bomb_perc_s3; - thresholds[0] = thresholds[1] + FLAGS_bomb_perc_s2; - - Xoroshiro128Plus r; - storeRelease(ready, 1); - while (!loadAcquire(start)) _mm_pause(); - while (!loadAcquire(quit)) { - for (int i = 0; i < numQueues; i++) { - auto start = std::chrono::high_resolution_clock::now(); - for (uint32_t j = 0; j < FLAGS_bomb_req_batch_size; j++) { - requestQueues[i].push(make_pair(decideType(r, thresholds), start)); - } - if (FLAGS_bomb_mixed_short_rate_tps) { - std::this_thread::sleep_for(get_request_interval_nano()); - } else { - std::this_thread::sleep_for(get_request_interval_micro()); - } + static void request_dispatcher([[maybe_unused]] size_t thid, char& ready, + const bool& start, const bool& quit) { + // prepare queues for short transactions + int numQueues = TotalThreadNum - FLAGS_bomb_l1_thread_num; + requestQueues = + new ConcurrentQueue>[numQueues]; + + uint64_t thresholds[4]; + int32_t perc_s5 = 100 - (FLAGS_bomb_perc_s1 + FLAGS_bomb_perc_s2 + + FLAGS_bomb_perc_s3 + FLAGS_bomb_perc_s4); + if (perc_s5 < 0) { + std::cout << "Specify short transaction percentage to make the total 100" + << std::endl; + ERR; + } + thresholds[3] = perc_s5; + thresholds[2] = thresholds[3] + FLAGS_bomb_perc_s4; + thresholds[1] = thresholds[2] + FLAGS_bomb_perc_s3; + thresholds[0] = thresholds[1] + FLAGS_bomb_perc_s2; + + Xoroshiro128Plus r; + storeRelease(ready, 1); + while (!loadAcquire(start)) _mm_pause(); + while (!loadAcquire(quit)) { + for (int i = 0; i < numQueues; i++) { + auto start = std::chrono::high_resolution_clock::now(); + for (uint32_t j = 0; j < FLAGS_bomb_req_batch_size; j++) { + requestQueues[i].push(make_pair(decideType(r, thresholds), start)); + } + if (FLAGS_bomb_mixed_short_rate_tps) { + std::this_thread::sleep_for(get_request_interval_nano()); + } else { + std::this_thread::sleep_for(get_request_interval_micro()); } } - sleepMs(1000); - delete[] requestQueues; } + sleepMs(1000); + delete[] requestQueues; + } - static void displayWorkloadParameter() { - } + static void displayWorkloadParameter() {} - static void displayWorkloadResult() { - } + static void displayWorkloadResult() {} }; diff --git a/include/bomb_static.hh b/include/bomb_static.hh index 23922539..b92ca196 100644 --- a/include/bomb_static.hh +++ b/include/bomb_static.hh @@ -20,101 +20,101 @@ #include "gflags/gflags.h" template -class StaticBombWorkload : public BombWorkload { +class StaticBombWorkload : public BombWorkload { public: - std::map bom_cache_; - - StaticBombWorkload() {} - using Query = typename BombWorkload::Query; - - void prepare(TxExecutor& tx, Param *p) { - BombWorkload::prepare(tx, p); - - // for static BoM - tx.begin(); - std::vector product_ids; - // Return value intentionally discarded: the call populates product_ids. - (void)BombWorkload::select_im_by_factory(tx, 1, product_ids); - for (auto& p_id : product_ids) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - bom_cache_.emplace(p_id, root); - } - tx.commit(); + std::map bom_cache_; + + StaticBombWorkload() {} + using Query = typename BombWorkload::Query; + + void prepare(TxExecutor& tx, Param* p) { + BombWorkload::prepare(tx, p); + + // for static BoM + tx.begin(); + std::vector product_ids; + // Return value intentionally discarded: the call populates product_ids. + (void) BombWorkload::select_im_by_factory(tx, 1, product_ids); + for (auto& p_id : product_ids) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + bom_cache_.emplace(p_id, root); } - - void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { - uint32_t f_id = query.args.f_id; - for (const auto& [p_id, root] : bom_cache_) { - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - // std::cout << p_id << " : " << node->i_id_ << std::endl; - if (!BombWorkload::get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } - } - BombWorkload::update_product_cost_master(tx, f_id, p_id, root->calculate_cost()); - if (tx.status_ == TransactionStatus::aborted) return; - if (tx.quit_) { // for long read phase - tx.status_ = TransactionStatus::invalid; - return; + tx.commit(); + } + + void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { + uint32_t f_id = query.args.f_id; + for (const auto& [p_id, root] : bom_cache_) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + // std::cout << p_id << " : " << node->i_id_ << std::endl; + if (!BombWorkload::get_material_cost( + tx, f_id, node->i_id_, node->unit_cost_)) + return; } } + BombWorkload::update_product_cost_master( + tx, f_id, p_id, root->calculate_cost()); + if (tx.status_ == TransactionStatus::aborted) return; + if (tx.quit_) { // for long read phase + tx.status_ = TransactionStatus::invalid; + return; + } + } + } + + template + void run(TxExecutor& tx) { + Query query; + query.generate(this, tx); + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + + switch (query.type) { + case TxType::IssueJournalVoucher: + BombWorkload::run_issue_journal_voucher(tx, query); + break; + case TxType::UpdateMaterialCostMaster: + BombWorkload::run_update_material_cost_master(tx, query); + break; + case TxType::UpdateProductCostMaster: + run_update_prodcut_cost_master(tx, query); + break; + default: + ERR; + break; } - template - void run(TxExecutor& tx) { - Query query; - query.generate(this, tx); - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); - } - - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - - switch (query.type) { - case TxType::IssueJournalVoucher: - BombWorkload::run_issue_journal_voucher(tx, query); - break; - case TxType::UpdateMaterialCostMaster: - BombWorkload::run_update_material_cost_master(tx, query); - break; - case TxType::UpdateProductCostMaster: - run_update_prodcut_cost_master(tx, query); - break; - default: - ERR; - break; - } - - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - return; - } + return; + } }; diff --git a/include/check.hh b/include/check.hh index e69d5824..5a465d24 100644 --- a/include/check.hh +++ b/include/check.hh @@ -4,7 +4,7 @@ #include -static bool chkInt(const char *arg) { +static bool chkInt(const char* arg) { for (uint i = 0; i < strlen(arg); ++i) { if (!isdigit(arg[i])) { std::cout << std::string(arg) << " is not a number." << std::endl; diff --git a/include/cpu.hh b/include/cpu.hh index 3844e660..a3aa53d4 100644 --- a/include/cpu.hh +++ b/include/cpu.hh @@ -7,23 +7,23 @@ #include "debug.hh" -#define CPUID(INFO, LEAF, SUBLEAF) \ +#define CPUID(INFO, LEAF, SUBLEAF) \ __cpuid_count(LEAF, SUBLEAF, INFO[0], INFO[1], INFO[2], INFO[3]) -#define GETCPU(CPU) \ - { \ - uint32_t CPUInfo[4]; \ - CPUID(CPUInfo, 1, 0); \ - /* CPUInfo[1] is EBX, bits 24-31 are APIC ID */ \ - if ((CPUInfo[3] & (1 << 9)) == 0) { \ - CPU = -1; /* no APIC on chip */ \ - } else { \ - CPU = (unsigned)CPUInfo[1] >> 24; \ - /*unsigned int cores = ((unsigned)CPUInfo[1] >> 16) & 0xff;*/ \ - /*if ((CPUInfo[3] & (1 << 28)) == 1) printf("HTT\n");*/ \ - /*printf("total core number : %d\n", cores);*/ \ - } \ - if (CPU < 0) CPU = 0; \ +#define GETCPU(CPU) \ + { \ + uint32_t CPUInfo[4]; \ + CPUID(CPUInfo, 1, 0); \ + /* CPUInfo[1] is EBX, bits 24-31 are APIC ID */ \ + if ((CPUInfo[3] & (1 << 9)) == 0) { \ + CPU = -1; /* no APIC on chip */ \ + } else { \ + CPU = (unsigned) CPUInfo[1] >> 24; \ + /*unsigned int cores = ((unsigned)CPUInfo[1] >> 16) & 0xff;*/ \ + /*if ((CPUInfo[3] & (1 << 28)) == 1) printf("HTT\n");*/ \ + /*printf("total core number : %d\n", cores);*/ \ + } \ + if (CPU < 0) CPU = 0; \ } #ifdef Linux @@ -39,9 +39,9 @@ static void setThreadAffinity(const int myid) { // printf("thread affinity (id==%d) [ok]\n", myid); return; } -#endif // Linux +#endif // Linux inline int cached_sched_getcpu() { - thread_local int value = ::sched_getcpu(); - return value; + thread_local int value = ::sched_getcpu(); + return value; } diff --git a/include/dbomb_deterministic.hh b/include/dbomb_deterministic.hh index 1ed5f38b..0b57ca8c 100644 --- a/include/dbomb_deterministic.hh +++ b/include/dbomb_deterministic.hh @@ -20,413 +20,443 @@ #include "gflags/gflags.h" template -class DeterministicBombWorkload : public BombWorkload { +class DeterministicBombWorkload : public BombWorkload { public: - DeterministicBombWorkload() {} - using Query = typename BombWorkload::Query; - - void prepare(TxExecutor& tx, Param *p) { - BombWorkload::prepare(tx, p); + DeterministicBombWorkload() {} + using Query = typename BombWorkload::Query; + + void prepare(TxExecutor& tx, Param* p) { + BombWorkload::prepare(tx, p); + } + + Status select_pc_by_factory(TxExecutor& tx, uint32_t factory_id, + std::vector& product_ids) { + SimpleKey<8> low, up; + std::vector result; + ProductCostMaster::CreateKey(factory_id, 0, low.ptr()); + ProductCostMaster::CreateKey(factory_id + 1, 0, up.ptr()); + Status stat = tx.scan(Storage::ProductCostMaster, low.view(), false, + up.view(), true, result); + if (tx.status_ == TransactionStatus::aborted) return stat; + for (auto& tuple : result) { + const ProductCostMaster& pc = + tuple->get_value().cast_to(); + product_ids.emplace_back(pc.pc_product_id); } - - Status select_pc_by_factory(TxExecutor& tx, uint32_t factory_id, std::vector& product_ids) { - SimpleKey<8> low, up; - std::vector result; - ProductCostMaster::CreateKey(factory_id, 0, low.ptr()); - ProductCostMaster::CreateKey(factory_id+1, 0, up.ptr()); - Status stat = tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, result); - if (tx.status_ == TransactionStatus::aborted) return stat; - for (auto& tuple : result) { - const ProductCostMaster& pc = tuple->get_value().cast_to(); - product_ids.emplace_back(pc.pc_product_id); - } - return stat; + return stat; + } + + void run_issue_journal_voucher(TxExecutor& tx, Query& query) { + RETRY: + if (tx.quit_) return; + uint32_t f_id = query.args.f_id; + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + // Return value intentionally discarded: the call populates product_ids. + (void) select_pc_by_factory(tx, f_id, product_ids); + tx.reconnoiter_end(); + + // prepare keys + uint32_t i = 0; + SimpleKey<8> keys[product_ids.size()]; + for (const auto& p_id : product_ids) { + ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), + false); + i++; } - void run_issue_journal_voucher(TxExecutor& tx, Query& query) { -RETRY: - if (tx.quit_) return; - uint32_t f_id = query.args.f_id; - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - // Return value intentionally discarded: the call populates product_ids. - (void)select_pc_by_factory(tx, f_id, product_ids); - tx.reconnoiter_end(); - - // prepare keys - uint32_t i = 0; - SimpleKey<8> keys[product_ids.size()]; - for (const auto& p_id : product_ids) { - ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), false); - i++; - } - - // sort keys and lock - if (!tx.lockList()) { - tx.unlockList(); - goto RETRY; // already reconnaissance fails due to deletion, so retry - } - - // access record - SimpleKey<8> low, up; - std::vector result; - ProductCostMaster::CreateKey(f_id, 0, low.ptr()); - ProductCostMaster::CreateKey(f_id+1, 0, up.ptr()); - tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - - uint32_t debit = 0; // product - uint32_t credit = 1; // work in progress - for (auto& tuple : result) { - const ProductCostMaster& pm = tuple->get_value().cast_to(); - double manufactured_quantity = 99.9; - BombWorkload::insert_journal_voucher(tx, debit, credit, manufactured_quantity*pm.pc_cost); - } - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); // as batch + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + goto RETRY; // already reconnaissance fails due to deletion, so retry } - - void run_update_material_cost_master(TxExecutor& tx, Query& query) { -RETRY: - if (tx.quit_) return; - // prepare keys - uint32_t i = 0; - SimpleKey<8> keys[query.args.i_id_set.size()]; - for (auto& m_id : query.args.i_id_set) { - MaterialCostMaster::CreateKey(query.args.f_id, m_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), true); - i++; - } - // sort keys and lock - if (!tx.lockList()) { - tx.unlockList(); - goto RETRY; // already reconnaissance fails due to deletion, so retry - } + // access record + SimpleKey<8> low, up; + std::vector result; + ProductCostMaster::CreateKey(f_id, 0, low.ptr()); + ProductCostMaster::CreateKey(f_id + 1, 0, up.ptr()); + tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, + result); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + + uint32_t debit = 0; // product + uint32_t credit = 1; // work in progress + for (auto& tuple : result) { + const ProductCostMaster& pm = + tuple->get_value().cast_to(); + double manufactured_quantity = 99.9; + BombWorkload::insert_journal_voucher( + tx, debit, credit, manufactured_quantity * pm.pc_cost); + } + if (FLAGS_bomb_interactive_ms) + sleepMs(FLAGS_bomb_interactive_ms); // as batch + } + + void run_update_material_cost_master(TxExecutor& tx, Query& query) { + RETRY: + if (tx.quit_) return; + // prepare keys + uint32_t i = 0; + SimpleKey<8> keys[query.args.i_id_set.size()]; + for (auto& m_id : query.args.i_id_set) { + MaterialCostMaster::CreateKey(query.args.f_id, m_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), + true); + i++; + } - // access record - for (auto& m_id : query.args.i_id_set) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); - TupleBody* body; - tx.read(Storage::MaterialCostMaster, key.view(), &body); - MaterialCostMaster& old = body->get_value().cast_to(); - HeapObject obj; - obj.template allocate(); - MaterialCostMaster& mc = obj.ref(); - mc.mc_f_id = old.mc_f_id; - mc.mc_i_id = old.mc_i_id; - mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; - mc.mc_stock_price = old.mc_stock_price + 1.0; - tx.update(Storage::MaterialCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); // as batch + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + goto RETRY; // already reconnaissance fails due to deletion, so retry } - void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { - uint32_t i = 0; - uint32_t f_id = query.args.f_id; - std::vector product_ids; - std::vector verify_products; - std::map bom; - std::map verify_bom; - - tx.reconnoiter_begin(); // Do target selection as if read from cache - // Reconnoiter pass: this call's job is to fill product_ids. The - // Status is intentionally discarded — if it aborted, product_ids - // is just empty or partial and the build_bom_tree loop below - // propagates the abort. - (void) BombWorkload::select_im_by_factory(tx, f_id, product_ids); - for (auto& p_id : product_ids) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - bom.emplace(p_id, root); - } - tx.reconnoiter_end(); - - // prepare keys - SimpleKey<8>* keys; - if (posix_memalign((void **) &keys, CACHE_LINE_SIZE, - FLAGS_bomb_base_product_size_per_factory - + FLAGS_bomb_base_product_size_per_factory - * FLAGS_bomb_tree_num_per_product - * FLAGS_bomb_base_tree_size - * FLAGS_bomb_material_per_wip * sizeof(SimpleKey<8>)) != 0) ERR; - - for (const auto& [p_id, root] : bom) { - //std::cout << p_id << " : " << root << std::endl; - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - MaterialCostMaster::CreateKey(f_id, node->i_id_, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), false); - } - i++; + // access record + for (auto& m_id : query.args.i_id_set) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); + TupleBody* body; + tx.read(Storage::MaterialCostMaster, key.view(), &body); + MaterialCostMaster& old = body->get_value().cast_to(); + HeapObject obj; + obj.template allocate(); + MaterialCostMaster& mc = obj.ref(); + mc.mc_f_id = old.mc_f_id; + mc.mc_i_id = old.mc_i_id; + mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; + mc.mc_stock_price = old.mc_stock_price + 1.0; + tx.update(Storage::MaterialCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) + sleepMs(FLAGS_bomb_interactive_ms); // as batch + } + + void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { + uint32_t i = 0; + uint32_t f_id = query.args.f_id; + std::vector product_ids; + std::vector verify_products; + std::map bom; + std::map verify_bom; + + tx.reconnoiter_begin(); // Do target selection as if read from cache + // Reconnoiter pass: this call's job is to fill product_ids. The + // Status is intentionally discarded — if it aborted, product_ids + // is just empty or partial and the build_bom_tree loop below + // propagates the abort. + (void) BombWorkload::select_im_by_factory(tx, f_id, + product_ids); + for (auto& p_id : product_ids) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + bom.emplace(p_id, root); + } + tx.reconnoiter_end(); + + // prepare keys + SimpleKey<8>* keys; + if (posix_memalign((void**) &keys, CACHE_LINE_SIZE, + FLAGS_bomb_base_product_size_per_factory + + FLAGS_bomb_base_product_size_per_factory * + FLAGS_bomb_tree_num_per_product * + FLAGS_bomb_base_tree_size * + FLAGS_bomb_material_per_wip * + sizeof(SimpleKey<8>)) != 0) + ERR; + + for (const auto& [p_id, root] : bom) { + //std::cout << p_id << " : " << root << std::endl; + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + MaterialCostMaster::CreateKey(f_id, node->i_id_, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, + keys[i].view(), false); } - ItemManufacturingMaster::CreateKey(f_id, p_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, keys[i].view(), true); - i++; - ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), true); i++; } - - // sort keys and lock - if (!tx.lockList()) { - tx.unlockList(); - // already reconnaissance fails due to deletion, so retry - // dump(tx.thid_, "lock fails"); - goto FAIL; - } - - // access record - for (const auto& [p_id, root] : bom) { - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!BombWorkload::get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } - } - BombWorkload::update_product_cost_master(tx, f_id, p_id, root->calculate_cost()); - if (tx.quit_) { // for long read phase - tx.unlockList(); - tx.status_ = TransactionStatus::invalid; - return; - } - } - - // Verify pass: see comment on the first select_im_by_factory call - // above — Status is discarded by design, downstream code propagates - // any abort. - (void) BombWorkload::select_im_by_factory(tx, f_id, verify_products); - for (auto& p_id : verify_products) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - verify_bom.emplace(p_id, root); - } - if (product_ids.size() != verify_products.size() - || !std::equal(product_ids.cbegin(), product_ids.cend(), verify_products.cbegin())) { - // dump(tx.thid_, "product verify fails"); - goto FAIL; - } - for (const auto& [p_id, root] : bom) { - std::vector nodes; - std::vector verify_nodes; - Node* verify_root; - if (auto it = verify_bom.find(p_id); it == verify_bom.end()) { - // dump(tx.thid_, "bom verify fails (1)"); - goto FAIL; - } else { - verify_root = verify_bom.at(p_id); - } - root->get_all_nodes(nodes); - verify_root->get_all_nodes(verify_nodes); - if (nodes.size() != verify_nodes.size() - || !std::equal(nodes.cbegin(), nodes.cend(), verify_nodes.cbegin(), - [](const Node* lhs, const Node* rhs) { return lhs->i_id_ == rhs->i_id_; })) { - // dump(tx.thid_, "bom verify fails (2)"); - goto FAIL; - } - } - // dump(tx.thid_, "verify done"); - return; - -FAIL: - tx.status_ = TransactionStatus::aborted; - return; + ItemManufacturingMaster::CreateKey(f_id, p_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, + keys[i].view(), true); + i++; + ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), + true); + i++; } - Status run_delete_product(TxExecutor& tx, Query& query, uint32_t product_id) { - Status stat = BombWorkload::delete_item_manufacturing_master(tx, query.args.f_id, product_id); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - dump(tx.thid_, "delete product fail"); - } - return stat; + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + // already reconnaissance fails due to deletion, so retry + // dump(tx.thid_, "lock fails"); + goto FAIL; } - Status run_change_product(TxExecutor& tx, Query& query) { -RETRY: - if (tx.quit_) return Status::OK; - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = BombWorkload::select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - if (stat != Status::OK) { - return stat; + // access record + for (const auto& [p_id, root] : bom) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!BombWorkload::get_material_cost( + tx, f_id, node->i_id_, node->unit_cost_)) + return; + } } - uint32_t product_id = BombWorkload::select_random(product_ids); - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(query.args.f_id, product_id, key.ptr()); - tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, key.view(), true); - - // sort keys and lock - if (!tx.lockList()) { + BombWorkload::update_product_cost_master( + tx, f_id, p_id, root->calculate_cost()); + if (tx.quit_) { // for long read phase tx.unlockList(); - // dump(tx.thid_, "WARN: lock fails"); - goto RETRY; // already reconnaissance fails due to deletion, so retry + tx.status_ = TransactionStatus::invalid; + return; } + } - // actual transaction logic - stat = run_delete_product(tx, query, product_id); - if (stat == Status::OK) { - // dump(tx.thid_, "INFO: delete OK"); - stat = BombWorkload::run_add_new_prodcut(tx, query); + // Verify pass: see comment on the first select_im_by_factory call + // above — Status is discarded by design, downstream code propagates + // any abort. + (void) BombWorkload::select_im_by_factory(tx, f_id, + verify_products); + for (auto& p_id : verify_products) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + verify_bom.emplace(p_id, root); + } + if (product_ids.size() != verify_products.size() || + !std::equal(product_ids.cbegin(), product_ids.cend(), + verify_products.cbegin())) { + // dump(tx.thid_, "product verify fails"); + goto FAIL; + } + for (const auto& [p_id, root] : bom) { + std::vector nodes; + std::vector verify_nodes; + Node* verify_root; + if (auto it = verify_bom.find(p_id); it == verify_bom.end()) { + // dump(tx.thid_, "bom verify fails (1)"); + goto FAIL; } else { - dump(tx.thid_, "WARN: product deletion fails"); + verify_root = verify_bom.at(p_id); } - if (stat != Status::OK) { - dump(tx.thid_, "WARN: product insertion fails"); + root->get_all_nodes(nodes); + verify_root->get_all_nodes(verify_nodes); + if (nodes.size() != verify_nodes.size() || + !std::equal(nodes.cbegin(), nodes.cend(), verify_nodes.cbegin(), + [](const Node* lhs, const Node* rhs) { + return lhs->i_id_ == rhs->i_id_; + })) { + // dump(tx.thid_, "bom verify fails (2)"); + goto FAIL; } - return stat; + } + // dump(tx.thid_, "verify done"); + return; + + FAIL: + tx.status_ = TransactionStatus::aborted; + return; + } + + Status run_delete_product(TxExecutor& tx, Query& query, uint32_t product_id) { + Status stat = BombWorkload::delete_item_manufacturing_master( + tx, query.args.f_id, product_id); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { dump(tx.thid_, "delete product fail"); } + return stat; + } + + Status run_change_product(TxExecutor& tx, Query& query) { + RETRY: + if (tx.quit_) return Status::OK; + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = BombWorkload::select_im_by_factory( + tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + if (stat != Status::OK) { return stat; } + uint32_t product_id = + BombWorkload::select_random(product_ids); + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(query.args.f_id, product_id, key.ptr()); + tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, key.view(), + true); + + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + // dump(tx.thid_, "WARN: lock fails"); + goto RETRY; // already reconnaissance fails due to deletion, so retry } - void run_change_raw_material(TxExecutor& tx, Query& query) { -RETRY: - if (tx.quit_) return; - std::vector> material_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - auto ret = BombWorkload::select_materials_by_item_id(tx, query.args.i_id, material_ids); - tx.reconnoiter_end(); - if (ret != Status::OK) return; - - auto pair = BombWorkload::select_random(material_ids); - auto parent_id = pair.first; - auto material_id = pair.second; - - SimpleKey<8> key; - ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); - tx.lock_entries_.emplace_back(Storage::ItemConstructionMaster, key.view(), true); - - // sort keys and lock - if (!tx.lockList()) { - tx.unlockList(); - goto RETRY; // already reconnaissance fails due to deletion, so retry - } + // actual transaction logic + stat = run_delete_product(tx, query, product_id); + if (stat == Status::OK) { + // dump(tx.thid_, "INFO: delete OK"); + stat = BombWorkload::run_add_new_prodcut(tx, query); + } else { + dump(tx.thid_, "WARN: product deletion fails"); + } + if (stat != Status::OK) { dump(tx.thid_, "WARN: product insertion fails"); } + return stat; + } + + void run_change_raw_material(TxExecutor& tx, Query& query) { + RETRY: + if (tx.quit_) return; + std::vector> material_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + auto ret = BombWorkload::select_materials_by_item_id( + tx, query.args.i_id, material_ids); + tx.reconnoiter_end(); + if (ret != Status::OK) return; + + auto pair = BombWorkload::select_random(material_ids); + auto parent_id = pair.first; + auto material_id = pair.second; + + SimpleKey<8> key; + ItemConstructionMaster::CreateKey(parent_id, material_id, key.ptr()); + tx.lock_entries_.emplace_back(Storage::ItemConstructionMaster, key.view(), + true); + + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + goto RETRY; // already reconnaissance fails due to deletion, so retry + } - // actual transaction logic - Status stat = BombWorkload::delete_item_construction_master(tx, parent_id, material_id); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - if (stat != Status::OK) { - dump(tx.thid_, "WARN: bom record deletion fails"); - return; - } - stat = BombWorkload::insert_item_construction_master(tx, parent_id, query.args.m_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - if (stat != Status::OK && stat != Status::WARN_ALREADY_EXISTS) { - // record may exist if a material to be inserted has already used for the parent item - dump(tx.thid_, "WARN: bom record insertion fails"); - return; - } + // actual transaction logic + Status stat = BombWorkload::delete_item_construction_master( + tx, parent_id, material_id); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + if (stat != Status::OK) { + dump(tx.thid_, "WARN: bom record deletion fails"); + return; + } + stat = BombWorkload::insert_item_construction_master( + tx, parent_id, query.args.m_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + if (stat != Status::OK && stat != Status::WARN_ALREADY_EXISTS) { + // record may exist if a material to be inserted has already used for the parent item + dump(tx.thid_, "WARN: bom record insertion fails"); + return; + } + } + + void run_change_product_quantity(TxExecutor& tx, Query& query) { + RETRY: + if (tx.quit_) return; + std::vector product_ids; + tx.reconnoiter_begin(); // Do target selection as if read from cache + Status stat = BombWorkload::select_im_by_factory( + tx, query.args.f_id, product_ids); + tx.reconnoiter_end(); + if (stat != Status::OK) return; + if (product_ids.size() == 0) { + dump(tx.thid_, "ERROR: No target records."); + ERR; + } + uint32_t product_id = + BombWorkload::select_random(product_ids); + SimpleKey<8> key; + ItemManufacturingMaster::CreateKey(query.args.f_id, product_id, key.ptr()); + tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, key.view(), + true); + + // sort keys and lock + if (!tx.lockList()) { + tx.unlockList(); + goto RETRY; // already reconnaissance fails due to deletion, so retry } - void run_change_product_quantity(TxExecutor& tx, Query& query) { -RETRY: - if (tx.quit_) return; - std::vector product_ids; - tx.reconnoiter_begin(); // Do target selection as if read from cache - Status stat = BombWorkload::select_im_by_factory(tx, query.args.f_id, product_ids); - tx.reconnoiter_end(); - if (stat != Status::OK) return; - if (product_ids.size() == 0) { - dump(tx.thid_, "ERROR: No target records."); + // actual transaction logic + stat = BombWorkload::update_item_manufacturing_master( + tx, query.args.f_id, product_id, 10.0); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { + // may not be found if already deleted by S3 + dump(tx.thid_, "WARN: item_manufacturing_master update fails"); + return; + } + } + + template + void run(TxExecutor& tx) { + Query query; + query.generate(this, tx); + auto start = std::chrono::high_resolution_clock::now(); + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + + switch (query.type) { + case TxType::IssueJournalVoucher: + run_issue_journal_voucher(tx, query); + break; + case TxType::UpdateMaterialCostMaster: + run_update_material_cost_master(tx, query); + break; + case TxType::UpdateProductCostMaster: + run_update_prodcut_cost_master(tx, query); + break; + case TxType::AddNewProduct: + run_change_product(tx, query); + break; + case TxType::ChangeRawMaterial: + run_change_raw_material(tx, query); + break; + case TxType::ChangeProductQuantity: + run_change_product_quantity(tx, query); + break; + default: ERR; - } - uint32_t product_id = BombWorkload::select_random(product_ids); - SimpleKey<8> key; - ItemManufacturingMaster::CreateKey(query.args.f_id, product_id, key.ptr()); - tx.lock_entries_.emplace_back(Storage::ItemManufacturingMaster, key.view(), true); - - // sort keys and lock - if (!tx.lockList()) { - tx.unlockList(); - goto RETRY; // already reconnaissance fails due to deletion, so retry - } - - // actual transaction logic - stat = BombWorkload::update_item_manufacturing_master(tx, query.args.f_id, product_id, 10.0); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - if (stat != Status::OK && stat != Status::WARN_NOT_FOUND) { - // may not be found if already deleted by S3 - dump(tx.thid_, "WARN: item_manufacturing_master update fails"); - return; - } + break; } - template - void run(TxExecutor& tx) { - Query query; - query.generate(this, tx); - auto start = std::chrono::high_resolution_clock::now(); - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); - } - - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - - switch (query.type) { - case TxType::IssueJournalVoucher: - run_issue_journal_voucher(tx, query); - break; - case TxType::UpdateMaterialCostMaster: - run_update_material_cost_master(tx, query); - break; - case TxType::UpdateProductCostMaster: - run_update_prodcut_cost_master(tx, query); - break; - case TxType::AddNewProduct: - run_change_product(tx, query); - break; - case TxType::ChangeRawMaterial: - run_change_raw_material(tx, query); - break; - case TxType::ChangeProductQuantity: - run_change_product_quantity(tx, query); - break; - default: - ERR; - break; - } - - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - - auto end = std::chrono::high_resolution_clock::now(); - auto elapsed = std::chrono::duration_cast(end - start); - if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { - auto interval = BombWorkload::get_request_interval(query.type); - if (elapsed < interval) { - std::this_thread::sleep_for((interval - elapsed) * 0.95); - } - } - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = - tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + elapsed.count(); - return; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + + auto end = std::chrono::high_resolution_clock::now(); + auto elapsed = + std::chrono::duration_cast(end - start); + if (!FLAGS_bomb_mixed_mode && FLAGS_bomb_rate_control) { + auto interval = + BombWorkload::get_request_interval(query.type); + if (elapsed < interval) { + std::this_thread::sleep_for((interval - elapsed) * 0.95); + } } + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] = + tx.result_->local_latency_per_tx_[get_tx_type(query.type)] + + elapsed.count(); + return; + } }; diff --git a/include/debug.hh b/include/debug.hh index c1a2ae8c..4dca69f5 100644 --- a/include/debug.hh +++ b/include/debug.hh @@ -14,66 +14,67 @@ extern std::mutex cout_mutex; extern void dump(int thid, std::string s); #endif -#define CCC(val) \ - do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %c\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ - fflush(stderr); \ +#define CCC(val) \ + do { \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %c\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__, #val, val); \ + fflush(stderr); \ } while (0) -#define DDD(val) \ - do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %d\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ - fflush(stderr); \ +#define DDD(val) \ + do { \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %d\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__, #val, val); \ + fflush(stderr); \ } while (0) -#define PPP(val) \ - do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %p\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ - fflush(stderr); \ +#define PPP(val) \ + do { \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %p\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__, #val, val); \ + fflush(stderr); \ } while (0) #define LLL(val) \ do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %ld\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %ld\n", \ + (long int) pthread_self(), __FILE__, __LINE__, __func__, #val, \ + val); \ fflush(stderr); \ } while (0) -#define SSS(val) \ - do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %s\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ - fflush(stderr); \ +#define SSS(val) \ + do { \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %s\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__, #val, val); \ + fflush(stderr); \ } while (0) -#define FFF(val) \ - do { \ - fprintf(stderr, "%ld %16s %4d %16s %16s: %f\n", (long int)pthread_self(), \ - __FILE__, __LINE__, __func__, #val, val); \ - fflush(stderr); \ +#define FFF(val) \ + do { \ + fprintf(stderr, "%ld %16s %4d %16s %16s: %f\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__, #val, val); \ + fflush(stderr); \ } while (0) #define NNN \ do { \ - fprintf(stderr, "%ld %16s %4d %16s\n", (long int)pthread_self(), __FILE__, \ - __LINE__, __func__); \ + fprintf(stderr, "%ld %16s %4d %16s\n", (long int) pthread_self(), \ + __FILE__, __LINE__, __func__); \ fflush(stderr); \ } while (0) -#define ERR \ - do { \ - perror("ERROR"); \ - NNN; \ - exit(1); \ +#define ERR \ + do { \ + perror("ERROR"); \ + NNN; \ + exit(1); \ } while (0) -#define RERR(fd) \ - do { \ - perror("Recv Error"); \ - NNN; \ - close(fd); \ - pthread_exit(NULL); \ +#define RERR(fd) \ + do { \ + perror("Recv Error"); \ + NNN; \ + close(fd); \ + pthread_exit(NULL); \ } while (0) -#define ERR2 \ - do { \ - perror("ERROR"); \ - NNN; \ - pthread_exit(NULL); \ +#define ERR2 \ + do { \ + perror("ERROR"); \ + NNN; \ + pthread_exit(NULL); \ } while (0) #define FCN cout << "file can't open.\n" diff --git a/include/delay.hh b/include/delay.hh index 3ddd81f7..2dd6306d 100644 --- a/include/delay.hh +++ b/include/delay.hh @@ -8,8 +8,7 @@ using namespace std; -[[maybe_unused]] static void -clock_delay(size_t clocks) { +[[maybe_unused]] static void clock_delay(size_t clocks) { std::size_t start(rdtscp()), stop; for (;;) { diff --git a/include/fence.hh b/include/fence.hh index 8286a5f5..20639db0 100644 --- a/include/fence.hh +++ b/include/fence.hh @@ -2,4 +2,4 @@ #include "inline.hh" -INLINE void compilerFence() { asm volatile("":: : "memory"); } +INLINE void compilerFence() { asm volatile("" ::: "memory"); } diff --git a/include/fileio.hh b/include/fileio.hh index 14ad75b5..00daa552 100644 --- a/include/fileio.hh +++ b/include/fileio.hh @@ -16,14 +16,14 @@ #ifdef Linux #include -#endif // Linux +#endif // Linux class File { private: int fd_; bool autoClose_; - void throwOpenError(const std::string &filePath) const { + void throwOpenError(const std::string& filePath) const { const int err = errno; std::string s("open failed: "); s += filePath; @@ -33,28 +33,28 @@ private: public: File() : fd_(-1), autoClose_(false) {} - bool open(const std::string &filePath, int flags) { + bool open(const std::string& filePath, int flags) { fd_ = ::open(filePath.c_str(), flags); autoClose_ = true; return fd_ >= 0; } - bool open(const std::string &filePath, int flags, mode_t mode) { + bool open(const std::string& filePath, int flags, mode_t mode) { fd_ = ::open(filePath.c_str(), flags, mode); autoClose_ = true; return fd_ >= 0; } - File(const std::string &filePath, int flags) : File() { + File(const std::string& filePath, int flags) : File() { if (!this->open(filePath, flags)) throwOpenError(filePath); } - File(const std::string &filePath, int flags, mode_t mode) : File() { + File(const std::string& filePath, int flags, mode_t mode) : File() { if (!this->open(filePath, flags, mode)) throwOpenError(filePath); } explicit File(int fd, bool autoClose = false) - : fd_(fd), autoClose_(autoClose) {} + : fd_(fd), autoClose_(autoClose) {} ~File() noexcept try { close(); } catch (...) { } @@ -66,20 +66,18 @@ public: void close() { if (!autoClose_ || fd_ < 0) return; - if (::close(fd_) < 0) { - throw LibcError(errno, "close failed: "); - } + if (::close(fd_) < 0) { throw LibcError(errno, "close failed: "); } fd_ = -1; } - size_t readsome(void *data, size_t size) { + size_t readsome(void* data, size_t size) { ssize_t r = ::read(fd(), data, size); if (r < 0) throw LibcError(errno, "read failed: "); return r; } - void read(void *data, size_t size) { - char *buf = reinterpret_cast(data); + void read(void* data, size_t size) { + char* buf = reinterpret_cast(data); size_t s = 0; while (s < size) { size_t r = readsome(&buf[s], size - s); @@ -88,8 +86,8 @@ public: } } - void write(const void *data, size_t size) { - const char *buf = reinterpret_cast(data); + void write(const void* data, size_t size) { + const char* buf = reinterpret_cast(data); size_t s = 0; while (s < size) { ssize_t r = ::write(fd(), &buf[s], size - s); @@ -101,16 +99,12 @@ public: #ifdef Linux void fdatasync() { - if (::fdatasync(fd()) < 0) { - throw LibcError(errno, "fdsync failed: "); - } + if (::fdatasync(fd()) < 0) { throw LibcError(errno, "fdsync failed: "); } } -#endif // Linux +#endif // Linux void fsync() { - if (::fsync(fd()) < 0) { - throw LibcError(errno, "fsync failed: "); - } + if (::fsync(fd()) < 0) { throw LibcError(errno, "fsync failed: "); } } void ftruncate(off_t length) { @@ -121,7 +115,7 @@ public: }; // create a file if it does not exist. -inline void createEmptyFile(const std::string &path, mode_t mode = 0644) { +inline void createEmptyFile(const std::string& path, mode_t mode = 0644) { struct stat st; if (::stat(path.c_str(), &st) == 0) return; File writer(path, O_CREAT | O_TRUNC | O_RDWR, mode); @@ -136,10 +130,10 @@ inline void createEmptyFile(const std::string &path, mode_t mode = 0644) { * String : it must have size(), resize(), and operator[]. * such as std::string and std::vector. */ -template -inline void readAllFromFile(File &file, String &buf) { - constexpr const size_t usize = 4096; // unit size. - size_t rsize = buf.size(); // read data will be appended to buf. +template +inline void readAllFromFile(File& file, String& buf) { + constexpr const size_t usize = 4096; // unit size. + size_t rsize = buf.size(); // read data will be appended to buf. for (;;) { if (buf.size() < rsize + usize) buf.resize(rsize + usize); @@ -150,14 +144,14 @@ inline void readAllFromFile(File &file, String &buf) { buf.resize(rsize); } -template -inline void readAllFromFile(const std::string &path, String &buf) { +template +inline void readAllFromFile(const std::string& path, String& buf) { File file(path, O_RDONLY); readAllFromFile(file, buf); file.close(); } -inline void genLogFileName(std::string &logpath, const int thid) { +inline void genLogFileName(std::string& logpath, const int thid) { const int PATHNAME_SIZE = 512; char pathname[PATHNAME_SIZE]; diff --git a/include/heap_object.hh b/include/heap_object.hh index 0bebea4c..5fe6b222 100644 --- a/include/heap_object.hh +++ b/include/heap_object.hh @@ -9,8 +9,7 @@ * Heap object manager. * The instance can work as a stub object if owner is false. */ -struct HeapObject -{ +struct HeapObject { private: void* data_; size_t size_; @@ -18,51 +17,68 @@ private: bool owner_; public: - HeapObject() : data_(nullptr), size_(0), align_(std::align_val_t(0)), owner_(false) { - } + HeapObject() + : data_(nullptr), size_(0), align_(std::align_val_t(0)), owner_(false) {} // call shallow_copy() or deep_copy() explicitly. HeapObject(const HeapObject& rhs) = delete; HeapObject(HeapObject&& rhs) noexcept : HeapObject() { swap(rhs); } - HeapObject(const void* data, size_t size, std::align_val_t align) : HeapObject() { + HeapObject(const void* data, size_t size, std::align_val_t align) + : HeapObject() { deep_copy_from(data, size, align); } ~HeapObject() { reset(); } HeapObject& operator=(const HeapObject&) = delete; - HeapObject& operator=(HeapObject&& rhs) noexcept { swap(rhs); return *this; } + HeapObject& operator=(HeapObject&& rhs) noexcept { + swap(rhs); + return *this; + } class TmpRefObj { HeapObject* ptr; + public: explicit TmpRefObj(HeapObject* ptr0) : ptr(ptr0) {} - template operator T&() { + template + operator T&() { assert(ptr->is_compatible()); return *reinterpret_cast(ptr->data()); } - template operator const T&() { + template + operator const T&() { assert(ptr->is_compatible()); return *reinterpret_cast(ptr->data()); } }; class ConstTmpRefObj { const HeapObject* ptr; + public: explicit ConstTmpRefObj(const HeapObject* ptr0) : ptr(ptr0) {} - template operator const T&() { + template + operator const T&() { assert(ptr->is_compatible()); return *reinterpret_cast(ptr->data()); } }; - TmpRefObj ref() { TmpRefObj obj(this); return obj; } - ConstTmpRefObj ref() const { ConstTmpRefObj obj(this); return obj; } + TmpRefObj ref() { + TmpRefObj obj(this); + return obj; + } + ConstTmpRefObj ref() const { + ConstTmpRefObj obj(this); + return obj; + } - template T& cast_to() { + template + T& cast_to() { assert(is_compatible()); return *reinterpret_cast(data()); } - template const T& cast_to() const { + template + const T& cast_to() const { assert(is_compatible()); return *reinterpret_cast(data()); } @@ -76,7 +92,8 @@ public: size_t size() const { return size_; } std::align_val_t align() const { return align_; } - void allocate(size_t size, std::align_val_t align = std::align_val_t(sizeof(uint8_t))) { + void allocate(size_t size, + std::align_val_t align = std::align_val_t(sizeof(uint8_t))) { reset(); data_ = ::operator new(size, align); size_ = size; @@ -114,12 +131,15 @@ public: template bool is_compatible() const { static_assert(std::is_trivially_copyable_v); - return data_ != nullptr && size_ == sizeof(T) && align_ == std::align_val_t(alignof(T)); + return data_ != nullptr && size_ == sizeof(T) && + align_ == std::align_val_t(alignof(T)); } void reset() noexcept { if (owner_) { - assert(data_!= nullptr); assert(size_ > 0); assert(static_cast(align_) > 0); + assert(data_ != nullptr); + assert(size_ > 0); + assert(static_cast(align_) > 0); ::operator delete(data_, size_, align_); } data_ = nullptr; @@ -132,13 +152,11 @@ public: }; -inline void shallow_copy(HeapObject& lhs, const HeapObject& rhs) -{ +inline void shallow_copy(HeapObject& lhs, const HeapObject& rhs) { lhs.shallow_copy_from(rhs); } -inline void deep_copy(HeapObject& lhs, const HeapObject& rhs) -{ +inline void deep_copy(HeapObject& lhs, const HeapObject& rhs) { lhs.deep_copy_from(rhs); } diff --git a/include/lock.hh b/include/lock.hh index 05d347d8..978418b4 100644 --- a/include/lock.hh +++ b/include/lock.hh @@ -19,12 +19,10 @@ public: int expected, desired; for (;;) { expected = counter.load(std::memory_order_acquire); -RETRY_R_LOCK: + RETRY_R_LOCK: if (expected != -1) desired = expected + 1; - else { - continue; - } + else { continue; } if (counter.compare_exchange_strong( expected, desired, memory_order_acq_rel, memory_order_acquire)) break; @@ -43,7 +41,7 @@ RETRY_R_LOCK: return false; if (counter.compare_exchange_strong( - expected, desired, memory_order_acq_rel, memory_order_acquire)) + expected, desired, memory_order_acq_rel, memory_order_acquire)) return true; } } @@ -55,7 +53,7 @@ RETRY_R_LOCK: int expected; for (;;) { expected = counter.load(memory_order_acquire); -RETRY_W_LOCK: + RETRY_W_LOCK: if (expected != 0) continue; if (counter.compare_exchange_strong(expected, -1, memory_order_acq_rel, memory_order_acquire)) @@ -72,7 +70,7 @@ RETRY_W_LOCK: if (expected != 0) return false; if (counter.compare_exchange_strong( - expected, desired, memory_order_acq_rel, memory_order_acquire)) + expected, desired, memory_order_acq_rel, memory_order_acquire)) return true; } } @@ -83,7 +81,6 @@ RETRY_W_LOCK: void upgrade() { int one = 1; while (!counter.compare_exchange_strong(one, -1, memory_order_acq_rel, - memory_order_acquire)) { - } + memory_order_acquire)) {} } }; diff --git a/include/masstree_wrapper.hh b/include/masstree_wrapper.hh index 3384d00c..50b9ab8c 100644 --- a/include/masstree_wrapper.hh +++ b/include/masstree_wrapper.hh @@ -36,7 +36,8 @@ class key_unparse_unsigned { public: - static int unparse_key(Masstree::key key, char *buf, int buflen) { + static int unparse_key(Masstree::key key, char* buf, + int buflen) { return snprintf(buf, buflen, "%" PRIu64, key.ikey()); } }; @@ -45,13 +46,13 @@ public: * type of object is T. * inserting a pointer of T as value. */ -template +template class MasstreeWrapper { public: - static constexpr std::uint64_t insert_bound = UINT64_MAX; // 0xffffff; + static constexpr std::uint64_t insert_bound = UINT64_MAX; // 0xffffff; // static constexpr std::uint64_t insert_bound = 0xffffff; //0xffffff; struct table_params : public Masstree::nodeparams<15, 15> { - typedef T *value_type; + typedef T* value_type; typedef Masstree::value_print value_print_type; typedef threadinfo threadinfo_type; typedef key_unparse_unsigned key_unparse_type; @@ -67,7 +68,7 @@ public: typedef typename table_type::leaf_type node_type; typedef typename unlocked_cursor_type::nodeversion_value_type - nodeversion_value_type; + nodeversion_value_type; struct insert_info_t { const node_type* node; @@ -75,7 +76,7 @@ public: uint64_t new_version; }; - static __thread typename table_params::threadinfo_type *ti; + static __thread typename table_params::threadinfo_type* ti; MasstreeWrapper() { this->table_init(); } @@ -91,18 +92,19 @@ public: * The order of calling on_resp_node() and invoke() is up to the implementation. */ class ScanCallback { - public: + public: virtual ~ScanCallback() {} /** * This node lies within the search range (at version v) */ - virtual void on_resp_node(const node_type *n, uint64_t version) = 0; + virtual void on_resp_node(const node_type* n, uint64_t version) = 0; /** * This key/value pair was read from node n @ version */ - virtual bool invoke(const std::string_view &k, T v, const node_type *n, uint64_t version) = 0; + virtual bool invoke(const std::string_view& k, T v, const node_type* n, + uint64_t version) = 0; }; void table_init() { @@ -122,11 +124,12 @@ public: table_.print(stdout); fprintf(stdout, "Stats: %s\n", Masstree::json_stats(table_, ti) - .unparse(lcdf::Json::indent_depth(1000)) - .c_str()); + .unparse(lcdf::Json::indent_depth(1000)) + .c_str()); } - Status insert_value(std::string_view key, T *value, insert_info_t *insert_info = NULL) { + Status insert_value(std::string_view key, T* value, + insert_info_t* insert_info = NULL) { cursor_type lp(table_, key.data(), key.size()); bool found = lp.find_insert(*ti); // always_assert(!found, "keys should all be unique"); @@ -147,9 +150,10 @@ public: return Status::OK; } - void insert_value(std::uint64_t key, T *value) { + void insert_value(std::uint64_t key, T* value) { std::uint64_t key_buf{__builtin_bswap64(key)}; - insert_value({reinterpret_cast(&key_buf), sizeof(key_buf)}, value); // NOLINT + insert_value({reinterpret_cast(&key_buf), sizeof(key_buf)}, + value); // NOLINT } Status remove_value(std::string_view key) { @@ -171,24 +175,22 @@ public: (void) remove_value(key); } - T *get_value(std::string_view key) { + T* get_value(std::string_view key) { unlocked_cursor_type lp(table_, key.data(), key.size()); bool found = lp.find_unlocked(*ti); - if (found) { - return lp.value(); - } + if (found) { return lp.value(); } return nullptr; } - T *get_value(std::uint64_t key) { + T* get_value(std::uint64_t key) { std::uint64_t key_buf{__builtin_bswap64(key)}; - return get_value({reinterpret_cast(&key_buf), sizeof(key_buf)}); + return get_value({reinterpret_cast(&key_buf), sizeof(key_buf)}); } - void scan(const char *const lkey, const std::size_t len_lkey, - const bool l_exclusive, const char *const rkey, + void scan(const char* const lkey, const std::size_t len_lkey, + const bool l_exclusive, const char* const rkey, const std::size_t len_rkey, const bool r_exclusive, - std::vector *res, int64_t max_scan_num, + std::vector* res, int64_t max_scan_num, ScanCallback& callback) { Str mtkey; if (lkey == nullptr) { @@ -197,31 +199,34 @@ public: mtkey = Str(lkey, len_lkey); } - SearchRangeScanner scanner(rkey, len_rkey, r_exclusive, res, max_scan_num, callback); + SearchRangeScanner scanner(rkey, len_rkey, r_exclusive, res, max_scan_num, + callback); table_.scan(mtkey, !l_exclusive, scanner, *ti); } - void scan(const char *const lkey, const std::size_t len_lkey, - const bool l_exclusive, const char *const rkey, + void scan(const char* const lkey, const std::size_t len_lkey, + const bool l_exclusive, const char* const rkey, const std::size_t len_rkey, const bool r_exclusive, - std::vector *res, bool limited_scan, ScanCallback& callback) { + std::vector* res, bool limited_scan, ScanCallback& callback) { scan(lkey, len_lkey, l_exclusive, rkey, len_rkey, r_exclusive, res, limited_scan ? (int64_t) 1000 : (int64_t) -1, callback); } - void scan(const char *const lkey, const std::size_t len_lkey, - const bool l_exclusive, const char *const rkey, + void scan(const char* const lkey, const std::size_t len_lkey, + const bool l_exclusive, const char* const rkey, const std::size_t len_rkey, const bool r_exclusive, - std::vector *res, int64_t max_scan_num) { - scan(lkey, len_lkey, l_exclusive, rkey, len_rkey, r_exclusive, res, max_scan_num, default_callback); + std::vector* res, int64_t max_scan_num) { + scan(lkey, len_lkey, l_exclusive, rkey, len_rkey, r_exclusive, res, + max_scan_num, default_callback); } // for compatibility - void scan(const char *const lkey, const std::size_t len_lkey, - const bool l_exclusive, const char *const rkey, + void scan(const char* const lkey, const std::size_t len_lkey, + const bool l_exclusive, const char* const rkey, const std::size_t len_rkey, const bool r_exclusive, - std::vector *res, bool limited_scan) { - scan(lkey, len_lkey, l_exclusive, rkey, len_rkey, r_exclusive, res, limited_scan, default_callback); + std::vector* res, bool limited_scan) { + scan(lkey, len_lkey, l_exclusive, rkey, len_rkey, r_exclusive, res, + limited_scan, default_callback); } static inline uint64_t ExtractVersionNumber(const node_type* n) { @@ -239,49 +244,43 @@ private: table_type table_; std::uint64_t key_gen_; - static inline Str make_key(std::uint64_t int_key, std::uint64_t &key_buf) { + static inline Str make_key(std::uint64_t int_key, std::uint64_t& key_buf) { key_buf = __builtin_bswap64(int_key); - return Str((const char *) &key_buf, sizeof(key_buf)); + return Str((const char*) &key_buf, sizeof(key_buf)); } }; -template +template class MasstreeWrapper::DefaultScanCallback : public ScanCallback { - void on_resp_node(const node_type * /*n*/, uint64_t /*version*/) {} - bool invoke(const std::string_view & /*k*/, T /*v*/, const node_type * /*n*/, + void on_resp_node(const node_type* /*n*/, uint64_t /*version*/) {} + bool invoke(const std::string_view& /*k*/, T /*v*/, const node_type* /*n*/, uint64_t /*version*/) { return true; } }; -template +template class MasstreeWrapper::SearchRangeScanner { - public: +public: using Str = Masstree::Str; - SearchRangeScanner(const char *const rkey, const std::size_t len_rkey, - const bool r_exclusive, std::vector *scan_buffer, + SearchRangeScanner(const char* const rkey, const std::size_t len_rkey, + const bool r_exclusive, std::vector* scan_buffer, int64_t max_scan_num, ScanCallback& callback) - : rkey_(rkey), - len_rkey_(len_rkey), - r_exclusive_(r_exclusive), - scan_buffer_(scan_buffer), - max_scan_num_(max_scan_num), + : rkey_(rkey), len_rkey_(len_rkey), r_exclusive_(r_exclusive), + scan_buffer_(scan_buffer), max_scan_num_(max_scan_num), callback_(callback) { - if (max_scan_num_ > 0) { - scan_buffer->reserve(max_scan_num_); - } + if (max_scan_num_ > 0) { scan_buffer->reserve(max_scan_num_); } } void visit_leaf(const Masstree::scanstackelt& iter, - const Masstree::key& /*key*/, - threadinfo& /*ti*/) { + const Masstree::key& /*key*/, threadinfo& /*ti*/) { const Masstree::leaf* node = iter.node(); uint64_t version = iter.full_version_value(); callback_.on_resp_node(node, version); } - bool visit_value(const Str key, T *val, threadinfo &) { + bool visit_value(const Str key, T* val, threadinfo&) { if (max_scan_num_ >= 0 && scan_buffer_->size() >= static_cast(max_scan_num_)) { return false; @@ -304,18 +303,18 @@ class MasstreeWrapper::SearchRangeScanner { return false; } - private: - const char *const rkey_{}; +private: + const char* const rkey_{}; const std::size_t len_rkey_{}; const bool r_exclusive_{}; - std::vector *scan_buffer_{}; + std::vector* scan_buffer_{}; int64_t max_scan_num_ = -1; ScanCallback& callback_; }; -template -__thread typename MasstreeWrapper::table_params::threadinfo_type * - MasstreeWrapper::ti = nullptr; +template +__thread typename MasstreeWrapper::table_params::threadinfo_type* + MasstreeWrapper::ti = nullptr; #ifdef GLOBAL_VALUE_DEFINE volatile mrcu_epoch_type active_epoch = 1; volatile std::uint64_t globalepoch = 1; diff --git a/include/op_element.hh b/include/op_element.hh index c21f9f7d..70fd0590 100644 --- a/include/op_element.hh +++ b/include/op_element.hh @@ -13,23 +13,23 @@ enum class OpType : std::uint8_t { RMW, }; -template +template class OpElement { public: Storage storage_; std::string key_; - T *rcdptr_; + T* rcdptr_; OpType op_; OpElement() : key_(0), rcdptr_(nullptr) {} OpElement(std::string_view key) : key_(key) {} - OpElement(std::string_view key, T *rcdptr) : key_(key), rcdptr_(rcdptr) {} + OpElement(std::string_view key, T* rcdptr) : key_(key), rcdptr_(rcdptr) {} - OpElement(Storage s, std::string_view key, T *rcdptr) - : storage_(s), key_(key), rcdptr_(rcdptr) {} + OpElement(Storage s, std::string_view key, T* rcdptr) + : storage_(s), key_(key), rcdptr_(rcdptr) {} - OpElement(Storage s, std::string_view key, T *rcdptr, OpType op) - : storage_(s), key_(key), rcdptr_(rcdptr), op_(op) {} + OpElement(Storage s, std::string_view key, T* rcdptr, OpType op) + : storage_(s), key_(key), rcdptr_(rcdptr), op_(op) {} }; diff --git a/include/procedure.hh b/include/procedure.hh index 204efff1..81d90739 100644 --- a/include/procedure.hh +++ b/include/procedure.hh @@ -22,7 +22,7 @@ public: Procedure(Ope ope, uint64_t key) : ope_(ope), key_(key) {} - bool operator<(const Procedure &right) const { + bool operator<(const Procedure& right) const { if (this->key_ == right.key_ && this->ope_ == Ope::WRITE && right.ope_ == Ope::READ) { return true; diff --git a/include/queue.hh b/include/queue.hh index 4f61d40f..7645d145 100644 --- a/include/queue.hh +++ b/include/queue.hh @@ -7,7 +7,7 @@ #include "lock.hh" #include "util.hh" -template +template class ConcurrentQueue : std::queue { typedef std::queue super; alignas(CACHE_LINE_SIZE) RWLock lock_; @@ -33,7 +33,5 @@ public: return element; } - size_t size() { - return super::size(); - } + size_t size() { return super::size(); } }; diff --git a/include/random.hh b/include/random.hh index a7e82e8c..4030f4e2 100644 --- a/include/random.hh +++ b/include/random.hh @@ -13,9 +13,7 @@ class Xoroshiro128Plus { public: - Xoroshiro128Plus() { - init(); - } + Xoroshiro128Plus() { init(); } uint64_t s[2]; @@ -42,8 +40,8 @@ public: const uint64_t result = s0 + s1; s1 ^= s0; - s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b - s[1] = rotl(s1, 37); // c + s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b + s[1] = rotl(s1, 37); // c return result; } diff --git a/include/result.hh b/include/result.hh index 474c7f75..a141fed1 100644 --- a/include/result.hh +++ b/include/result.hh @@ -126,17 +126,18 @@ public: void displayAllResult(size_t clocks_per_us, size_t extime, size_t thread_num, size_t op_num, size_t batch_op_num); - void displayPerTxResult(std::map tx_types); + void displayPerTxResult(std::map tx_types); - void displayOzeAnalysisResult(size_t clocks_per_us, size_t extime, size_t thread_num); + void displayOzeAnalysisResult(size_t clocks_per_us, size_t extime, + size_t thread_num); #if ADD_ANALYSIS - void displayAbortByOperationRate(); // abort by operation rate; - void displayAbortByValidationRate(); // abort by validation rate; + void displayAbortByOperationRate(); // abort by operation rate; + void displayAbortByValidationRate(); // abort by validation rate; void displayAbortLatencyRate(size_t clocks_per_us, size_t extime, size_t thread_num); void displayCommitLatencyRate(size_t clocks_per_us, size_t extime, - size_t thread_num); + size_t thread_num); void displayBackoffLatencyRate(size_t clocks_per_us, size_t extime, size_t thread_num); void displayEarlyAbortRate(); @@ -147,10 +148,10 @@ public: void displayGCTMTElementsCounts(); void displayGCVersionCounts(); void displayMakeProcedureLatencyRate(size_t clocks_per_us, size_t extime, - size_t thread_num); + size_t thread_num); void displayMemcpys(); void displayOtherWorkLatencyRate(size_t clocks_per_us, size_t extime, - size_t thread_num); + size_t thread_num); void displayPreemptiveAbortsCounts(); void displayRatioOfPreemptiveAbortToTotalAbort(); void displayReadLatencyRate(size_t clocks_per_us, size_t extime, @@ -166,8 +167,10 @@ public: size_t thread_num); void displayValiLatencyRate(size_t clocks_per_us, size_t extime, size_t thread_num); - void displayReadValidationRate(size_t clocks_per_us, size_t extime, size_t thread_num); - void displayWriteValidationRate(size_t clocks_per_us, size_t extime, size_t thread_num); + void displayReadValidationRate(size_t clocks_per_us, size_t extime, + size_t thread_num); + void displayWriteValidationRate(size_t clocks_per_us, size_t extime, + size_t thread_num); void displayValidationFailureByTidRate(); void displayValidationFailureByWritelockRate(); void displayVersionMalloc(); @@ -179,8 +182,9 @@ public: void displayForwardingCount(); #endif - void addLocalAllResult(const Result &other); - void addLocalPerTxResult(const Result &other, std::map tx_types); + void addLocalAllResult(const Result& other); + void addLocalPerTxResult(const Result& other, + std::map tx_types); void addLocalAbortCounts(const uint64_t count); void addLocalBatchAbortCounts(const uint64_t count); diff --git a/include/sbomb_deterministic.hh b/include/sbomb_deterministic.hh index 897addbf..1dbe3c6a 100644 --- a/include/sbomb_deterministic.hh +++ b/include/sbomb_deterministic.hh @@ -20,207 +20,219 @@ #include "gflags/gflags.h" template -class DeterministicSbombWorkload : public BombWorkload { +class DeterministicSbombWorkload : public BombWorkload { public: - std::map bom_cache_; - - DeterministicSbombWorkload() {} - using Query = typename BombWorkload::Query; - - void prepare(TxExecutor& tx, Param *p) { - BombWorkload::prepare(tx, p); - - // for static BoM - tx.begin(); - std::vector product_ids; - // Return value intentionally discarded: the call populates product_ids. - (void)BombWorkload::select_im_by_factory(tx, 1, product_ids); - for (auto& p_id : product_ids) { - Node* root = BombWorkload::build_bom_tree(tx, p_id); - if (root == nullptr) ERR; - bom_cache_.emplace(p_id, root); - } - tx.commit(); - - // std::cout << "prepare " << tx.thid_ << std::endl; - // for (const auto& [p_id, root] : bom_cache_) { - // std::vector nodes; - // root->get_all_nodes(nodes); - // for (auto& node : nodes) { - // if (node->is_leaf()) { - // if (tx.thid_ == 0) std::cout << p_id << " : " << node->i_id_ << std::endl; - // } - // } - // } + std::map bom_cache_; + + DeterministicSbombWorkload() {} + using Query = typename BombWorkload::Query; + + void prepare(TxExecutor& tx, Param* p) { + BombWorkload::prepare(tx, p); + + // for static BoM + tx.begin(); + std::vector product_ids; + // Return value intentionally discarded: the call populates product_ids. + (void) BombWorkload::select_im_by_factory(tx, 1, product_ids); + for (auto& p_id : product_ids) { + Node* root = BombWorkload::build_bom_tree(tx, p_id); + if (root == nullptr) ERR; + bom_cache_.emplace(p_id, root); } - - void run_issue_journal_voucher(TxExecutor& tx, Query& query) { - uint32_t i = 0; - uint32_t f_id = query.args.f_id; - SimpleKey<8> keys[bom_cache_.size()]; - - // prepare keys - for (const auto& [p_id, root] : bom_cache_) { - ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), false); - i++; - } - - // sort keys and lock - tx.lockList(); - - // access record - SimpleKey<8> low, up; - std::vector result; - ProductCostMaster::CreateKey(f_id, 0, low.ptr()); - ProductCostMaster::CreateKey(f_id+1, 0, up.ptr()); - tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, result); - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); - - uint32_t debit = 0; // product - uint32_t credit = 1; // work in progress - for (auto& tuple : result) { - const ProductCostMaster& pm = tuple->get_value().cast_to(); - double manufactured_quantity = 99.9; - BombWorkload::insert_journal_voucher(tx, debit, credit, manufactured_quantity*pm.pc_cost); - } - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); // as batch + tx.commit(); + + // std::cout << "prepare " << tx.thid_ << std::endl; + // for (const auto& [p_id, root] : bom_cache_) { + // std::vector nodes; + // root->get_all_nodes(nodes); + // for (auto& node : nodes) { + // if (node->is_leaf()) { + // if (tx.thid_ == 0) std::cout << p_id << " : " << node->i_id_ << std::endl; + // } + // } + // } + } + + void run_issue_journal_voucher(TxExecutor& tx, Query& query) { + uint32_t i = 0; + uint32_t f_id = query.args.f_id; + SimpleKey<8> keys[bom_cache_.size()]; + + // prepare keys + for (const auto& [p_id, root] : bom_cache_) { + ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), + false); + i++; } - - void run_update_material_cost_master(TxExecutor& tx, Query& query) { - uint32_t i = 0; - SimpleKey<8> keys[query.args.i_id_set.size()]; - - // prepare keys - for (auto& m_id : query.args.i_id_set) { - MaterialCostMaster::CreateKey(query.args.f_id, m_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), true); - i++; - } - // sort keys and lock - tx.lockList(); - - // access record - for (auto& m_id : query.args.i_id_set) { - SimpleKey<8> key; - MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); - TupleBody* body; - tx.read(Storage::MaterialCostMaster, key.view(), &body); - MaterialCostMaster& old = body->get_value().cast_to(); - HeapObject obj; - obj.template allocate(); - MaterialCostMaster& mc = obj.ref(); - mc.mc_f_id = old.mc_f_id; - mc.mc_i_id = old.mc_i_id; - mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; - mc.mc_stock_price = old.mc_stock_price + 1.0; - tx.update(Storage::MaterialCostMaster, key.view(), TupleBody(key.view(), std::move(obj))); - } - if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); // as batch + // sort keys and lock + tx.lockList(); + + // access record + SimpleKey<8> low, up; + std::vector result; + ProductCostMaster::CreateKey(f_id, 0, low.ptr()); + ProductCostMaster::CreateKey(f_id + 1, 0, up.ptr()); + tx.scan(Storage::ProductCostMaster, low.view(), false, up.view(), true, + result); + if (FLAGS_bomb_interactive_ms) sleepMs(FLAGS_bomb_interactive_ms); + + uint32_t debit = 0; // product + uint32_t credit = 1; // work in progress + for (auto& tuple : result) { + const ProductCostMaster& pm = + tuple->get_value().cast_to(); + double manufactured_quantity = 99.9; + BombWorkload::insert_journal_voucher( + tx, debit, credit, manufactured_quantity * pm.pc_cost); + } + if (FLAGS_bomb_interactive_ms) + sleepMs(FLAGS_bomb_interactive_ms); // as batch + } + + void run_update_material_cost_master(TxExecutor& tx, Query& query) { + uint32_t i = 0; + SimpleKey<8> keys[query.args.i_id_set.size()]; + + // prepare keys + for (auto& m_id : query.args.i_id_set) { + MaterialCostMaster::CreateKey(query.args.f_id, m_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), + true); + i++; } - void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { - uint32_t i = 0; - uint32_t f_id = query.args.f_id; - SimpleKey<8>* keys; - if (posix_memalign((void **) &keys, CACHE_LINE_SIZE, - FLAGS_bomb_base_product_size_per_factory - + FLAGS_bomb_base_product_size_per_factory - * FLAGS_bomb_tree_num_per_product - * FLAGS_bomb_base_tree_size - * FLAGS_bomb_material_per_wip * sizeof(SimpleKey<8>)) != 0) ERR; - - // prepare keys - for (const auto& [p_id, root] : bom_cache_) { - //std::cout << p_id << " : " << root << std::endl; - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - MaterialCostMaster::CreateKey(f_id, node->i_id_, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, keys[i].view(), false); - } - i++; + // sort keys and lock + tx.lockList(); + + // access record + for (auto& m_id : query.args.i_id_set) { + SimpleKey<8> key; + MaterialCostMaster::CreateKey(query.args.f_id, m_id, key.ptr()); + TupleBody* body; + tx.read(Storage::MaterialCostMaster, key.view(), &body); + MaterialCostMaster& old = body->get_value().cast_to(); + HeapObject obj; + obj.template allocate(); + MaterialCostMaster& mc = obj.ref(); + mc.mc_f_id = old.mc_f_id; + mc.mc_i_id = old.mc_i_id; + mc.mc_stock_quantity = old.mc_stock_quantity + 1.0; + mc.mc_stock_price = old.mc_stock_price + 1.0; + tx.update(Storage::MaterialCostMaster, key.view(), + TupleBody(key.view(), std::move(obj))); + } + if (FLAGS_bomb_interactive_ms) + sleepMs(FLAGS_bomb_interactive_ms); // as batch + } + + void run_update_prodcut_cost_master(TxExecutor& tx, Query& query) { + uint32_t i = 0; + uint32_t f_id = query.args.f_id; + SimpleKey<8>* keys; + if (posix_memalign((void**) &keys, CACHE_LINE_SIZE, + FLAGS_bomb_base_product_size_per_factory + + FLAGS_bomb_base_product_size_per_factory * + FLAGS_bomb_tree_num_per_product * + FLAGS_bomb_base_tree_size * + FLAGS_bomb_material_per_wip * + sizeof(SimpleKey<8>)) != 0) + ERR; + + // prepare keys + for (const auto& [p_id, root] : bom_cache_) { + //std::cout << p_id << " : " << root << std::endl; + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + MaterialCostMaster::CreateKey(f_id, node->i_id_, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::MaterialCostMaster, + keys[i].view(), false); } - ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); - tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), true); i++; } + ProductCostMaster::CreateKey(f_id, p_id, keys[i].ptr()); + tx.lock_entries_.emplace_back(Storage::ProductCostMaster, keys[i].view(), + true); + i++; + } - // sort keys and lock - tx.lockList(); - - // access record - for (const auto& [p_id, root] : bom_cache_) { - std::vector nodes; - root->get_all_nodes(nodes); - for (auto& node : nodes) { - if (node->is_leaf()) { - if (!BombWorkload::get_material_cost(tx, f_id, node->i_id_, node->unit_cost_)) - return; - } - } - BombWorkload::update_product_cost_master(tx, f_id, p_id, root->calculate_cost()); - if (tx.quit_) { // for long read phase - tx.status_ = TransactionStatus::invalid; - return; + // sort keys and lock + tx.lockList(); + + // access record + for (const auto& [p_id, root] : bom_cache_) { + std::vector nodes; + root->get_all_nodes(nodes); + for (auto& node : nodes) { + if (node->is_leaf()) { + if (!BombWorkload::get_material_cost( + tx, f_id, node->i_id_, node->unit_cost_)) + return; } } - free(keys); + BombWorkload::update_product_cost_master( + tx, f_id, p_id, root->calculate_cost()); + if (tx.quit_) { // for long read phase + tx.status_ = TransactionStatus::invalid; + return; + } + } + free(keys); + } + + template + void run(TxExecutor& tx) { + Query query; + query.generate(this, tx); + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + + switch (query.type) { + case TxType::IssueJournalVoucher: + run_issue_journal_voucher(tx, query); + break; + case TxType::UpdateMaterialCostMaster: + run_update_material_cost_master(tx, query); + break; + case TxType::UpdateProductCostMaster: + run_update_prodcut_cost_master(tx, query); + break; + default: + ERR; + break; } - template - void run(TxExecutor& tx) { - Query query; - query.generate(this, tx); - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); - } - - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - - switch (query.type) { - case TxType::IssueJournalVoucher: - run_issue_journal_voucher(tx, query); - break; - case TxType::UpdateMaterialCostMaster: - run_update_material_cost_master(tx, query); - break; - case TxType::UpdateProductCostMaster: - run_update_prodcut_cost_master(tx, query); - break; - default: - ERR; - break; - } - - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - return; - } + return; + } }; diff --git a/include/string.hh b/include/string.hh index 2ba40b21..ab25ee7a 100644 --- a/include/string.hh +++ b/include/string.hh @@ -6,8 +6,8 @@ using std::cout; using std::endl; -[[maybe_unused]] static void genStringRepeatedNumber(char *string, size_t val_size, - size_t thid) { +[[maybe_unused]] static void +genStringRepeatedNumber(char* string, size_t val_size, size_t thid) { size_t digit(1), thidnum(thid); for (;;) { thidnum /= 10; @@ -19,8 +19,6 @@ using std::endl; // generate write value for this thread. sprintf(string, "%ld", thid); - for (uint i = digit; i < val_size - 2; ++i) { - string[i] = '0'; - } + for (uint i = digit; i < val_size - 2; ++i) { string[i] = '0'; } // printf("%s\n", string); } diff --git a/include/tpcc.hh b/include/tpcc.hh index 19c223ed..5cd9c7f7 100644 --- a/include/tpcc.hh +++ b/include/tpcc.hh @@ -28,109 +28,105 @@ template class TPCCWorkload { public: - Param* param_; - Xoroshiro128Plus rnd_; - HistoryKeyGenerator hkg_; - uint16_t w_id; // home warehouse + Param* param_; + Xoroshiro128Plus rnd_; + HistoryKeyGenerator hkg_; + uint16_t w_id; // home warehouse - TPCCWorkload() { - rnd_.init(); - } + TPCCWorkload() { rnd_.init(); } - void prepare(TxExecutor& tx, [[maybe_unused]] Param *p) { - hkg_.init(tx.thid_, true); - w_id = (tx.thid_ % FLAGS_tpcc_num_wh) + 1; // home warehouse. - } + void prepare(TxExecutor& tx, [[maybe_unused]] Param* p) { + hkg_.init(tx.thid_, true); + w_id = (tx.thid_ % FLAGS_tpcc_num_wh) + 1; // home warehouse. + } - template - void run(TxExecutor& tx) { - Query query; - TPCCQuery::Option option; + template + void run(TxExecutor& tx) { + Query query; + TPCCQuery::Option option; -RETRY: - query.generate(w_id, option); + RETRY: + query.generate(w_id, option); - if (tx.isLeader()) { - tx.leaderWork(); - } + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - - switch (query.type) { - case TxType::NewOrder: - if (!run_new_order(tx, &query.new_order)) { - tx.status_ = TransactionStatus::aborted; - } - break; - case TxType::Payment: - if (!run_payment(tx, &query.payment, &hkg_)) { - tx.status_ = TransactionStatus::aborted; - } - break; - case TxType::OrderStatus: - if (!run_order_status(tx, &query.order_status)) { - tx.status_ = TransactionStatus::aborted; - } - break; - case TxType::Delivery: - if (!run_delivery(tx, &query.delivery)) { - tx.status_ = TransactionStatus::aborted; - } - break; - case TxType::StockLevel: - if (!run_stock_level(tx, &query.stock_level)) { - tx.status_ = TransactionStatus::aborted; - } - break; - default: - ERR; - break; + switch (query.type) { + case TxType::NewOrder: + if (!run_new_order(tx, + &query.new_order)) { + tx.status_ = TransactionStatus::aborted; } + break; + case TxType::Payment: + if (!run_payment( + tx, &query.payment, &hkg_)) { + tx.status_ = TransactionStatus::aborted; + } + break; + case TxType::OrderStatus: + if (!run_order_status( + tx, &query.order_status)) { + tx.status_ = TransactionStatus::aborted; + } + break; + case TxType::Delivery: + if (!run_delivery(tx, &query.delivery)) { + tx.status_ = TransactionStatus::aborted; + } + break; + case TxType::StockLevel: + if (!run_stock_level( + tx, &query.stock_level)) { + tx.status_ = TransactionStatus::aborted; + } + break; + default: + ERR; + break; + } - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - if (tx.status_ == TransactionStatus::invalid) return; - tx.result_->local_abort_counts_++; - tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; - goto RETRY; - } + if (!tx.commit()) { + tx.abort(); + if (tx.status_ == TransactionStatus::invalid) return; + tx.result_->local_abort_counts_++; + tx.result_->local_abort_counts_per_tx_[get_tx_type(query.type)]++; + goto RETRY; + } - if (loadAcquire(tx.quit_)) return; - tx.result_->local_commit_counts_++; - tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; + if (loadAcquire(tx.quit_)) return; + tx.result_->local_commit_counts_++; + tx.result_->local_commit_counts_per_tx_[get_tx_type(query.type)]++; - return; - } + return; + } - static uint32_t getTableNum() { - return (uint32_t)Storage::Size; - } + static uint32_t getTableNum() { return (uint32_t) Storage::Size; } - static void makeDB([[maybe_unused]] Param* param) { - Xoroshiro128Plus rand; - rand.init(); + static void makeDB([[maybe_unused]] Param* param) { + Xoroshiro128Plus rand; + rand.init(); - // TODO: move this codes to appropriate place - // set_tx_name(TxType::xxx, "xxx"); + // TODO: move this codes to appropriate place + // set_tx_name(TxType::xxx, "xxx"); - TPCCInitializaer::load(param); - } + TPCCInitializaer::load(param); + } - static void displayWorkloadParameter() { - } + static void displayWorkloadParameter() {} - static void displayWorkloadResult() { - } + static void displayWorkloadResult() {} }; diff --git a/include/tpcc/tpcc_common.hh b/include/tpcc/tpcc_common.hh index a587c710..d1bcd0e6 100644 --- a/include/tpcc/tpcc_common.hh +++ b/include/tpcc/tpcc_common.hh @@ -5,10 +5,13 @@ #ifdef GLOBAL_VALUE_DEFINE DEFINE_uint32(tpcc_num_wh, 1, "The number of warehouses"); DEFINE_uint64(tpcc_perc_payment, 43, "The percentage of Payment transactions"); -DEFINE_uint64(tpcc_perc_order_status, 4, "The percentage of Order-Status transactions"); +DEFINE_uint64(tpcc_perc_order_status, 4, + "The percentage of Order-Status transactions"); DEFINE_uint64(tpcc_perc_delivery, 4, "The percentage of Delivery transactions"); -DEFINE_uint64(tpcc_perc_stock_level, 4, "The percentage of Stock-Level transactions"); -DEFINE_uint32(tpcc_interactive_ms, 0, "Sleep milliseconds per SQL(-equivalent) unit"); +DEFINE_uint64(tpcc_perc_stock_level, 4, + "The percentage of Stock-Level transactions"); +DEFINE_uint32(tpcc_interactive_ms, 0, + "Sleep milliseconds per SQL(-equivalent) unit"); #else DECLARE_uint32(tpcc_num_wh); DECLARE_uint64(tpcc_perc_payment); diff --git a/include/tpcc/tpcc_initializer.hh b/include/tpcc/tpcc_initializer.hh index 13df8808..64d94b7b 100644 --- a/include/tpcc/tpcc_initializer.hh +++ b/include/tpcc/tpcc_initializer.hh @@ -29,26 +29,27 @@ template class TPCCInitializaer { public: - static void db_insert_raw([[maybe_unused]] size_t thid, [[maybe_unused]] Param *param, - Storage st, std::string_view key, HeapObject&& val) { - Tuple* tuple = new Tuple(); - tuple->init(thid, TupleBody(key, std::move(val)), param); - - // TODO: - // rec->set_for_load(); - - MasstreeWrapper::thread_init(cached_sched_getcpu()); - Masstrees[get_storage(st)].insert_value(key, tuple); - // TODO: status handling - // Status sta = kohler_masstree::insert_record(st, key, rec); - // if (sta != Status::OK) { - // std::cout << __FILE__ << " : " << __LINE__ << " : " - // << "fatal error. unique key restriction." << std::endl; - // std::cout << "st : " << static_cast(st) - // << ", key : " << str_view_hex(key) - // << ", val : " << str_view_hex(rec->get_tuple().get_val()) << std::endl; - // std::abort(); - // } + static void db_insert_raw([[maybe_unused]] size_t thid, + [[maybe_unused]] Param* param, Storage st, + std::string_view key, HeapObject&& val) { + Tuple* tuple = new Tuple(); + tuple->init(thid, TupleBody(key, std::move(val)), param); + + // TODO: + // rec->set_for_load(); + + MasstreeWrapper::thread_init(cached_sched_getcpu()); + Masstrees[get_storage(st)].insert_value(key, tuple); + // TODO: status handling + // Status sta = kohler_masstree::insert_record(st, key, rec); + // if (sta != Status::OK) { + // std::cout << __FILE__ << " : " << __LINE__ << " : " + // << "fatal error. unique key restriction." << std::endl; + // std::cout << "st : " << static_cast(st) + // << ", key : " << str_view_hex(key) + // << ", val : " << str_view_hex(rec->get_tuple().get_val()) << std::endl; + // std::abort(); + // } } @@ -56,8 +57,8 @@ public: static void load_item([[maybe_unused]] Param* param) { struct S { - static void work([[maybe_unused]] Param* param, - std::uint32_t i_id_start, std::uint32_t i_id_end, const IsOriginal& is_original) { + static void work([[maybe_unused]] Param* param, std::uint32_t i_id_start, + std::uint32_t i_id_end, const IsOriginal& is_original) { for (std::uint32_t i_id = i_id_start; i_id <= i_id_end; ++i_id) { assert(i_id != 0); // 1-origin HeapObject obj; @@ -70,7 +71,9 @@ public: std::size_t dataLen = random_alpha_string(26, 50, ite.I_DATA); if (is_original[i_id - 1]) make_original(ite.I_DATA, dataLen); #ifdef DEBUG - std::cout<<"I_ID:"< key{}; ite.createKey(key.ptr()); @@ -104,35 +107,39 @@ public: } //CREATE Warehouses - static void load_warehouse([[maybe_unused]] Param *param, std::uint16_t w_id) { + static void load_warehouse([[maybe_unused]] Param* param, + std::uint16_t w_id) { assert(w_id != 0); // 1-origin HeapObject obj; obj.allocate(); Warehouse& ware = obj.ref(); ware.W_ID = w_id; random_alpha_string(6, 10, ware.W_NAME); - make_address(ware.W_STREET_1, - ware.W_STREET_2, - ware.W_CITY, - ware.W_STATE, - ware.W_ZIP); + make_address(ware.W_STREET_1, ware.W_STREET_2, ware.W_CITY, ware.W_STATE, + ware.W_ZIP); ware.W_TAX = random_double(0, 2000, 10000); ware.W_YTD = 300000; #ifdef DEBUG - std::cout<<"W_ID:"< wh_key{}; ware.createKey(wh_key.ptr()); - db_insert_raw(w_id, param, Storage::Warehouse, wh_key.view(), std::move(obj)); + db_insert_raw(w_id, param, Storage::Warehouse, wh_key.view(), + std::move(obj)); } //CREATE Stock - static void load_stock([[maybe_unused]] Param *param, std::uint16_t w_id) { + static void load_stock([[maybe_unused]] Param* param, std::uint16_t w_id) { struct S { - static void work([[maybe_unused]] Param *param, - std::uint32_t i_id_start, std::uint32_t i_id_end, std::uint16_t w_id, const IsOriginal& is_original) { + static void work([[maybe_unused]] Param* param, std::uint32_t i_id_start, + std::uint32_t i_id_end, std::uint16_t w_id, + const IsOriginal& is_original) { for (std::uint32_t i_id = i_id_start; i_id <= i_id_end; ++i_id) { assert(i_id != 0); // 1-origin HeapObject obj; @@ -141,9 +148,10 @@ public: st.S_I_ID = i_id; st.S_W_ID = w_id; st.S_QUANTITY = random_int(10, 100); - for (char* out : { - st.S_DIST_01, st.S_DIST_02, st.S_DIST_03, st.S_DIST_04, st.S_DIST_05, - st.S_DIST_06, st.S_DIST_07, st.S_DIST_08, st.S_DIST_09, st.S_DIST_10}) { + for (char* out : + {st.S_DIST_01, st.S_DIST_02, st.S_DIST_03, st.S_DIST_04, + st.S_DIST_05, st.S_DIST_06, st.S_DIST_07, st.S_DIST_08, + st.S_DIST_09, st.S_DIST_10}) { random_alpha_string(24, 24, out); } st.S_YTD = 0; @@ -154,7 +162,8 @@ public: SimpleKey<8> st_key{}; st.createKey(st_key.ptr()); - db_insert_raw(w_id, param, Storage::Stock, st_key.view(), std::move(obj)); + db_insert_raw(w_id, param, Storage::Stock, st_key.view(), + std::move(obj)); } } }; @@ -181,8 +190,9 @@ public: } //CREATE History - static void load_history([[maybe_unused]] Param *param, - std::uint16_t w_id, uint8_t d_id, std::uint32_t c_id, std::string_view key) { + static void load_history([[maybe_unused]] Param* param, std::uint16_t w_id, + uint8_t d_id, std::uint32_t c_id, + std::string_view key) { std::time_t now = get_lightweight_timestamp(); HeapObject obj; obj.allocate(); @@ -198,8 +208,9 @@ public: } //CREATE Orderline - static void load_orderline([[maybe_unused]] Param *param, - std::uint16_t w_id, std::uint16_t d_id, std::uint32_t o_id, uint8_t ol_num) { + static void load_orderline([[maybe_unused]] Param* param, std::uint16_t w_id, + std::uint16_t d_id, std::uint32_t o_id, + uint8_t ol_num) { std::time_t now = get_lightweight_timestamp(); HeapObject obj; obj.allocate(); @@ -229,8 +240,8 @@ public: } //CREATE Order - static void load_order([[maybe_unused]] Param *param, - std::uint16_t w_id, uint8_t d_id, std::uint32_t o_id, std::uint32_t c_id) { + static void load_order([[maybe_unused]] Param* param, std::uint16_t w_id, + uint8_t d_id, std::uint32_t o_id, std::uint32_t c_id) { std::time_t now = get_lightweight_timestamp(); HeapObject obj; obj.allocate(); @@ -256,11 +267,13 @@ public: db_insert_raw(w_id, param, Storage::Order, key.view(), std::move(obj)); char o_secondary_key_buf[16]; - std::string_view o_secondary_key = order.createSecondaryKey(&o_secondary_key_buf[0]); + std::string_view o_secondary_key = + order.createSecondaryKey(&o_secondary_key_buf[0]); // ::printf("o_cust_key %s\n", str_view_hex(o_cust_key).c_str()); // TODO: consider to store o_id directly as value of masstree - db_insert_raw(w_id, param, Storage::OrderSecondary, o_secondary_key, std::move(key_obj)); + db_insert_raw(w_id, param, Storage::OrderSecondary, o_secondary_key, + std::move(key_obj)); } //O_OL_CNT orderlines per order. for (uint8_t ol_num = 1; ol_num <= order.O_OL_CNT + 1; ol_num++) { @@ -278,20 +291,21 @@ public: { SimpleKey<8> key{}; new_order.createKey(key.ptr()); - db_insert_raw(w_id, param, Storage::NewOrder, key.view(), std::move(obj)); + db_insert_raw(w_id, param, Storage::NewOrder, key.view(), + std::move(obj)); } } } //CREATE Customer - static void load_customer([[maybe_unused]] Param *param, - uint8_t d_id, std::uint16_t w_id, HistoryKeyGenerator &hkg) { + static void load_customer([[maybe_unused]] Param* param, uint8_t d_id, + std::uint16_t w_id, HistoryKeyGenerator& hkg) { struct S { - static void - work([[maybe_unused]] Param *param, - std::uint32_t c_id_start, std::uint32_t c_id_end, HistoryKeyGenerator &hkg, - uint8_t d_id, std::uint16_t w_id, const Permutation& perm) { + static void work([[maybe_unused]] Param* param, std::uint32_t c_id_start, + std::uint32_t c_id_end, HistoryKeyGenerator& hkg, + uint8_t d_id, std::uint16_t w_id, + const Permutation& perm) { for (std::uint32_t c_id = c_id_start; c_id <= c_id_end; ++c_id) { assert(c_id != 0); // 1-origin. std::time_t now = get_lightweight_timestamp(); @@ -304,24 +318,22 @@ public: if (c_id <= 1000) { // for all c_last patterns [0, 999] to be exist. make_c_last(c_id - 1, customer.C_LAST); - #ifdef DEBUG - std::cout<<"C_LAST:"<(0, 999), customer.C_LAST); } copy_cstr(customer.C_MIDDLE, "OE", sizeof(customer.C_MIDDLE)); random_alpha_string(8, 16, customer.C_FIRST); - make_address(customer.C_STREET_1, - customer.C_STREET_2, - customer.C_CITY, - customer.C_STATE, - customer.C_ZIP); + make_address(customer.C_STREET_1, customer.C_STREET_2, + customer.C_CITY, customer.C_STATE, customer.C_ZIP); random_number_string(16, 16, customer.C_PHONE); - #ifdef DEBUG - if(c==start&& w==1&& d==2)std::cout<<"C_PHONE:"< pkey{}; customer.createKey(pkey.ptr()); char c_last_key_buf[Customer::CLastKey::required_size()]; - std::string_view c_last_key = customer.createSecondaryKey(&c_last_key_buf[0]); + std::string_view c_last_key = + customer.createSecondaryKey(&c_last_key_buf[0]); // ::printf("c_last_key %s\n", str_view_hex(c_last_key).c_str()); - db_insert_raw(w_id, param, Storage::Customer, pkey.view(), std::move(obj)); + db_insert_raw(w_id, param, Storage::Customer, pkey.view(), + std::move(obj)); - std::vector> *ctn_ptr; + std::vector>* ctn_ptr; MasstreeWrapper::thread_init(cached_sched_getcpu()); - Tuple* tuple = Masstrees[get_storage(Storage::CustomerSecondary)].get_value(c_last_key); + Tuple* tuple = + Masstrees[get_storage(Storage::CustomerSecondary)].get_value( + c_last_key); if (tuple != nullptr) { memcpy(&ctn_ptr, tuple->body_.get_val().data(), sizeof(uintptr_t)); //::printf("found %p\n", ctn_ptr); @@ -361,20 +377,25 @@ public: obj.allocate(); uintptr_t& p = obj.ref(); p = uintptr_t(ctn_ptr); - db_insert_raw(w_id, param, Storage::CustomerSecondary, c_last_key, std::move(obj)); + db_insert_raw(w_id, param, Storage::CustomerSecondary, c_last_key, + std::move(obj)); } struct S { - static Customer *search(const SimpleKey<8> &pkey) { + static Customer* search(const SimpleKey<8>& pkey) { MasstreeWrapper::thread_init(cached_sched_getcpu()); - auto *tuple = reinterpret_cast(Masstrees[get_storage(Storage::Customer)].get_value(pkey.view())); - return reinterpret_cast(const_cast(tuple->body_.get_val().data())); + auto* tuple = reinterpret_cast( + Masstrees[get_storage(Storage::Customer)].get_value( + pkey.view())); + return reinterpret_cast( + const_cast(tuple->body_.get_val().data())); } - static bool less(const SimpleKey<8> &lh, const SimpleKey<8> &rh) { - const Customer *lh_cust = search(lh); - const Customer *rh_cust = search(rh); - return ::strncmp(lh_cust->C_FIRST, rh_cust->C_FIRST, sizeof(Customer::C_FIRST)) < 0; + static bool less(const SimpleKey<8>& lh, const SimpleKey<8>& rh) { + const Customer* lh_cust = search(lh); + const Customer* rh_cust = search(rh); + return ::strncmp(lh_cust->C_FIRST, rh_cust->C_FIRST, + sizeof(Customer::C_FIRST)) < 0; } }; @@ -392,7 +413,7 @@ public: Permutation perm(1, CUST_PER_DIST); S::work(param, 1, CUST_PER_DIST, hkg, d_id, w_id, perm); - #if 0 +#if 0 constexpr std::std::size_t cust_num_per_th{500}; constexpr std::std::size_t para_num{CUST_PER_DIST / cust_num_per_th}; std::vector thv; @@ -405,13 +426,13 @@ public: for (auto &&th : thv) { th.join(); } - #endif +#endif } - static void load_district([[maybe_unused]] Param *param, std::uint16_t w_id) { + static void load_district([[maybe_unused]] Param* param, std::uint16_t w_id) { struct S { - static void work([[maybe_unused]] Param *param, - uint8_t d_id, std::uint16_t w_id, HistoryKeyGenerator &hkg) { + static void work([[maybe_unused]] Param* param, uint8_t d_id, + std::uint16_t w_id, HistoryKeyGenerator& hkg) { assert(d_id != 0); // 1-origin. HeapObject obj; obj.allocate(); @@ -419,21 +440,19 @@ public: district.D_ID = d_id; district.D_W_ID = w_id; random_alpha_string(6, 10, district.D_NAME); - make_address(district.D_STREET_1, - district.D_STREET_2, - district.D_CITY, - district.D_STATE, - district.D_ZIP); + make_address(district.D_STREET_1, district.D_STREET_2, district.D_CITY, + district.D_STATE, district.D_ZIP); district.D_TAX = random_double(0, 2000, 10000); district.D_YTD = 30000.00; district.D_NEXT_O_ID = 3001; - #ifdef DEBUG - std::cout<<"D_ID:"< key{}; district.createKey(key.ptr()); - db_insert_raw(w_id, param, Storage::District, key.view(), std::move(obj)); + db_insert_raw(w_id, param, Storage::District, key.view(), + std::move(obj)); // CREATE Customer History Order Orderline. 3000 customers per a district. load_customer(param, d_id, w_id, hkg); @@ -443,7 +462,7 @@ public: assert(w_id != 0); // 1-origin. hkg.init(w_id - 1, false); - #if 0 +#if 0 std::vector thv; for (std::size_t d = 1; d <= DIST_PER_WARE; ++d) { thv.emplace_back(S::work, d, w, std::ref(hkg)); @@ -451,13 +470,12 @@ public: for (auto &&th : thv) { th.join(); } - #else +#else // single-threaded. for (uint8_t d_id = 1; d_id <= DIST_PER_WARE; ++d_id) { S::work(param, d_id, w_id, hkg); } - #endif - +#endif } static void load(Param* param) { @@ -475,9 +493,7 @@ public: thv.emplace_back(load_district, param, w); } - for (auto &&th : thv) { - th.join(); - } + for (auto&& th : thv) { th.join(); } std::cout << "[end] load." << std::endl; } }; diff --git a/include/tpcc/tpcc_query.hh b/include/tpcc/tpcc_query.hh index 03386f09..9844574c 100644 --- a/include/tpcc/tpcc_query.hh +++ b/include/tpcc/tpcc_query.hh @@ -56,9 +56,12 @@ public: Option() { threshold_delivery = perc_stock_level * (UINT64_MAX / 100); - threshold_order_status = threshold_delivery + (perc_delivery * (UINT64_MAX / 100)); - threshold_payment = threshold_order_status + (perc_order_status * (UINT64_MAX / 100)); - threshold_new_order = threshold_payment + (perc_payment * (UINT64_MAX / 100)); + threshold_order_status = + threshold_delivery + (perc_delivery * (UINT64_MAX / 100)); + threshold_payment = + threshold_order_status + (perc_order_status * (UINT64_MAX / 100)); + threshold_new_order = + threshold_payment + (perc_payment * (UINT64_MAX / 100)); #if 0 ::printf("query_type_threshold: %.3f %.3f %.3f %.3f\n" , threshold_new_order / (double)UINT64_MAX @@ -83,7 +86,7 @@ public: bool remote; std::uint8_t ol_cnt; - void generate([[maybe_unused]]uint16_t w_id0, Option &opt) { + void generate([[maybe_unused]] uint16_t w_id0, Option& opt) { #ifdef FIXED_WAREHOUSE_PER_THREAD w_id = w_id0; #else @@ -116,17 +119,21 @@ public: } items[i].ol_quantity = random_int(1, 10); } - if (rbk == 1) { // set an unused item number to produce "not-found" for roll back + if (rbk == + 1) { // set an unused item number to produce "not-found" for roll back items[ol_cnt - 1].ol_i_id += opt.max_items; } } void print() { - printf("nod: w_id=%" PRIu16 " d_id=%" PRIu8 " c_id=%" PRIu32 " rbk=%" PRIu8 " remote=%s ol_cnt=%" PRIu8 "\n", - w_id, d_id, c_id, rbk, remote ? "t" : "f", ol_cnt); + printf("nod: w_id=%" PRIu16 " d_id=%" PRIu8 " c_id=%" PRIu32 " rbk=%" PRIu8 + " remote=%s ol_cnt=%" PRIu8 "\n", + w_id, d_id, c_id, rbk, remote ? "t" : "f", ol_cnt); for (unsigned int i = 0; i < ol_cnt; ++i) { - printf(" [%d]: ol_i_id=%" PRIu32 " ol_supply_w_id=%" PRIu16 " c_quantity=%" PRIu8 "\n", i, - items[i].ol_i_id, items[i].ol_supply_w_id, items[i].ol_quantity); + printf(" [%d]: ol_i_id=%" PRIu32 " ol_supply_w_id=%" PRIu16 + " c_quantity=%" PRIu8 "\n", + i, items[i].ol_i_id, items[i].ol_supply_w_id, + items[i].ol_quantity); } } }; @@ -143,7 +150,7 @@ public: double h_amount; bool by_last_name; - void generate([[maybe_unused]]std::uint16_t w_id0, Option &opt) { + void generate([[maybe_unused]] std::uint16_t w_id0, Option& opt) { #ifdef FIXED_WAREHOUSE_PER_THREAD w_id = w_id0; #else @@ -183,8 +190,9 @@ public: } void print() { - printf("pay: w_id=%" PRIu16 " d_id=%" PRIu8 " d_w_id=%" PRIu16 " c_w_id=%" PRIu16 " c_d_id=%" PRIu8 " h_amount=%.2f\n", - w_id, d_id, d_w_id, c_w_id, c_d_id, h_amount); + printf("pay: w_id=%" PRIu16 " d_id=%" PRIu8 " d_w_id=%" PRIu16 + " c_w_id=%" PRIu16 " c_d_id=%" PRIu8 " h_amount=%.2f\n", + w_id, d_id, d_w_id, c_w_id, c_d_id, h_amount); if (by_last_name) { printf(" by_last_name=t c_last=%s\n", c_last); } else { @@ -201,7 +209,7 @@ public: char c_last[LASTNAME_LEN + 1]; bool by_last_name; - void generate(uint16_t w_id0, Option &opt) { + void generate(uint16_t w_id0, Option& opt) { #ifdef FIXED_WAREHOUSE_PER_THREAD w_id = w_id0; #else @@ -237,7 +245,7 @@ public: std::uint8_t o_carrier_id; std::uint64_t ol_delivery_d; - void generate(uint16_t w_id0, [[maybe_unused]] Option &opt) { + void generate(uint16_t w_id0, [[maybe_unused]] Option& opt) { #ifdef FIXED_WAREHOUSE_PER_THREAD w_id = w_id0; #else @@ -248,8 +256,9 @@ public: } void print() { - printf("del: w_id=%" PRIu16 " o_carrier_id=%" PRIu8 "ol_delivery_d=%" PRIu64 "\n", - w_id, o_carrier_id, ol_delivery_d); + printf("del: w_id=%" PRIu16 " o_carrier_id=%" PRIu8 "ol_delivery_d=%" PRIu64 + "\n", + w_id, o_carrier_id, ol_delivery_d); } }; @@ -259,7 +268,7 @@ public: std::uint8_t d_id; std::uint8_t threshold; - void generate(uint16_t w_id0, Option &opt) { + void generate(uint16_t w_id0, Option& opt) { #ifdef FIXED_WAREHOUSE_PER_THREAD w_id = w_id0; #else @@ -270,13 +279,14 @@ public: } void print() { - printf("stklvl: w_id=%" PRIu16 " d_id=%" PRIu8 " threshold=%" PRIu8, w_id, d_id, threshold); + printf("stklvl: w_id=%" PRIu16 " d_id=%" PRIu8 " threshold=%" PRIu8, w_id, + d_id, threshold); } }; } // namespace TPCCQuery -static TxType decideQueryType(TPCCQuery::Option &opt) { +static TxType decideQueryType(TPCCQuery::Option& opt) { uint64_t x = random_64bits(); if (x >= opt.threshold_new_order) return TxType::NewOrder; if (x >= opt.threshold_payment) return TxType::Payment; @@ -296,7 +306,7 @@ public: TPCCQuery::StockLevel stock_level; }; - void generate(std::uint16_t w_id, TPCCQuery::Option &opt) { + void generate(std::uint16_t w_id, TPCCQuery::Option& opt) { type = decideQueryType(opt); switch (type) { case TxType::NewOrder: @@ -321,10 +331,10 @@ public: void print() { switch (type) { - case TxType::NewOrder : + case TxType::NewOrder: new_order.print(); break; - case TxType::Payment : + case TxType::Payment: payment.print(); break; case TxType::OrderStatus: diff --git a/include/tpcc/tpcc_tables.hh b/include/tpcc/tpcc_tables.hh index 0f711801..8c43d2b0 100644 --- a/include/tpcc/tpcc_tables.hh +++ b/include/tpcc/tpcc_tables.hh @@ -29,8 +29,7 @@ enum class Storage : std::uint32_t { }; struct Warehouse { - alignas(CACHE_LINE_SIZE) - std::uint16_t W_ID; //2*W unique IDs + alignas(CACHE_LINE_SIZE) std::uint16_t W_ID; //2*W unique IDs char W_NAME[11]; char W_STREET_1[21]; char W_STREET_2[21]; @@ -42,19 +41,18 @@ struct Warehouse { //Primary Key: W_ID //key size is 8 bytes. - static void CreateKey(uint16_t w_id, char *out) { + static void CreateKey(uint16_t w_id, char* out) { ::memset(out, 0, 6); assign_as_bigendian(w_id, &out[6]); } - void createKey(char *out) const { return CreateKey(W_ID, out); } + void createKey(char* out) const { return CreateKey(W_ID, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct District { - alignas(CACHE_LINE_SIZE) - std::uint8_t D_ID; //20 unique IDs + alignas(CACHE_LINE_SIZE) std::uint8_t D_ID; //20 unique IDs std::uint16_t D_W_ID; //2*W unique IDs D_W_ID Foreign Key, references W_ID char D_NAME[11]; char D_STREET_1[21]; @@ -62,29 +60,28 @@ struct District { char D_CITY[21]; char D_STATE[3]; char D_ZIP[10]; - double D_TAX; //signed numeric(4,4) - double D_YTD; //signed numeric(12,2) + double D_TAX; //signed numeric(4,4) + double D_YTD; //signed numeric(12,2) std::uint32_t D_NEXT_O_ID; //10,000,000 unique IDs //Primary Key: (D_W_ID, D_ID) //key size is 8. - static void CreateKey(uint16_t w_id, uint8_t d_id, char *out) { + static void CreateKey(uint16_t w_id, uint8_t d_id, char* out) { ::memset(out, 0, 5); assign_as_bigendian(w_id, &out[5]); assign_as_bigendian(d_id, &out[7]); } - void createKey(char *out) const { return CreateKey(D_W_ID, D_ID, out); } + void createKey(char* out) const { return CreateKey(D_W_ID, D_ID, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct Customer { //(C_W_ID, C_D_ID) Foreign Key, references (D_W_ID, D_ID) - alignas(CACHE_LINE_SIZE) - std::uint32_t C_ID; //96,000 unique IDs - std::uint8_t C_D_ID; //20 unique IDs - std::uint16_t C_W_ID; //2*W unique IDs + alignas(CACHE_LINE_SIZE) std::uint32_t C_ID; //96,000 unique IDs + std::uint8_t C_D_ID; //20 unique IDs + std::uint16_t C_W_ID; //2*W unique IDs char C_FIRST[17]; char C_MIDDLE[3]; char C_LAST[17]; //the customer's last name @@ -94,8 +91,8 @@ struct Customer { char C_STATE[3]; char C_ZIP[10]; char C_PHONE[17]; - std::uint64_t C_SINCE;//date and time - char C_CREDIT[3]; //"GC"=good, "BC"=bad + std::uint64_t C_SINCE; //date and time + char C_CREDIT[3]; //"GC"=good, "BC"=bad double C_CREDIT_LIM; double C_DISCOUNT; double C_BALANCE; @@ -132,7 +129,8 @@ struct Customer { } std::string pretty_str() const { char buf[128]; - ::snprintf(buf, sizeof(buf), "Customer_Key: w_id %u d_id %u c_id %u", w_id, d_id, c_id); + ::snprintf(buf, sizeof(buf), "Customer_Key: w_id %u d_id %u c_id %u", + w_id, d_id, c_id); return std::string(buf); } }; @@ -143,7 +141,9 @@ struct Customer { const char* c_last; char* c_last_out; - constexpr static size_t required_size() { return sizeof(C_W_ID) + sizeof(C_D_ID) + sizeof(C_LAST); } + constexpr static size_t required_size() { + return sizeof(C_W_ID) + sizeof(C_D_ID) + sizeof(C_LAST); + } /** * CAUSION: c_last is just a pointer. Set it approprieately before calling parse(). @@ -163,7 +163,9 @@ struct Customer { } std::string pretty_str() const { char buf[128]; - ::snprintf(buf, sizeof(buf), "Customer_CLastKey: c_w_id %u c_d_id %u c_last %s\n", c_w_id, c_d_id, c_last); + ::snprintf(buf, sizeof(buf), + "Customer_CLastKey: c_w_id %u c_d_id %u c_last %s\n", c_w_id, + c_d_id, c_last); return std::string(buf); } }; @@ -171,24 +173,29 @@ struct Customer { //Primary Key: (C_W_ID, C_D_ID, C_ID) //key size is 8 bytes. - static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t c_id, char *out) { + static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t c_id, char* out) { Key key{w_id, d_id, c_id}; key.create(out); } - void createKey(char *out) const { return CreateKey(C_W_ID, C_D_ID, C_ID, out); } + void createKey(char* out) const { + return CreateKey(C_W_ID, C_D_ID, C_ID, out); + } //Secondary Key: (C_W_ID, C_D_ID, C_LAST) //key length is variable. (maximum length is maxLenOfSecondaryKey()). //out buffer will not be null-terminated. - static std::string_view CreateSecondaryKey(uint16_t w_id, uint8_t d_id, const char* c_last, char* out) { + static std::string_view CreateSecondaryKey(uint16_t w_id, uint8_t d_id, + const char* c_last, char* out) { CLastKey key{w_id, d_id, c_last, nullptr}; size_t len = key.create(out); return std::string_view(out, len); } - std::string_view createSecondaryKey(char* out){ return CreateSecondaryKey(C_W_ID, C_D_ID, &C_LAST[0], out); } + std::string_view createSecondaryKey(char* out) { + return CreateSecondaryKey(C_W_ID, C_D_ID, &C_LAST[0], out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; @@ -198,14 +205,13 @@ struct History { // (H_C_W_ID, H_C_D_ID, H_C_ID) Foreign Key, references (C_W_ID, C_D_ID, C_ID) // (H_W_ID, H_D_ID) Foreign Key, references (D_W_ID, D_ID) - alignas(CACHE_LINE_SIZE) - std::uint32_t H_C_ID; //96,000 unique IDs - std::uint8_t H_C_D_ID;// 20 unique IDs - std::uint16_t H_C_W_ID; // 2*W unique IDs - std::uint8_t H_D_ID; //20 unique IDs - std::uint16_t H_W_ID; // 2*W unique IDs - std::uint64_t H_DATE; //date and time - double H_AMOUNT; //signed numeric(6, 2) + alignas(CACHE_LINE_SIZE) std::uint32_t H_C_ID; //96,000 unique IDs + std::uint8_t H_C_D_ID; // 20 unique IDs + std::uint16_t H_C_W_ID; // 2*W unique IDs + std::uint8_t H_D_ID; //20 unique IDs + std::uint16_t H_W_ID; // 2*W unique IDs + std::uint64_t H_DATE; //date and time + double H_AMOUNT; //signed numeric(6, 2) char H_DATA[25]; // variable text, size 24 Miscellaneous information [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } @@ -215,19 +221,16 @@ struct History { class HistoryKeyGenerator { public: union { - alignas(CACHE_LINE_SIZE) - std::uint64_t key_; + alignas(CACHE_LINE_SIZE) std::uint64_t key_; struct { - std::uint64_t counter_: 47; - std::uint64_t at_work_: 1; // 0 at initial load, 1 at work. - std::uint64_t id_: 16; + std::uint64_t counter_ : 47; + std::uint64_t at_work_ : 1; // 0 at initial load, 1 at work. + std::uint64_t id_ : 16; }; // upper bits are thread_id in little endian architecture. }; - std::uint64_t get_raw() { - return fetchAdd(key_, 1); - } + std::uint64_t get_raw() { return fetchAdd(key_, 1); } SimpleKey<8> get_as_simple_key() { SimpleKey<8> ret{}; @@ -245,52 +248,55 @@ public: struct NewOrder { //(NO_W_ID, NO_D_ID, NO_O_ID) Foreign Key, references (O_W_ID, O_D_ID, O_ID) - alignas(CACHE_LINE_SIZE) - std::uint32_t NO_O_ID; //10,000,000 unique IDs - std::uint8_t NO_D_ID; //20 unique IDs - std::uint16_t NO_W_ID; //2*W unique IDs + alignas(CACHE_LINE_SIZE) std::uint32_t NO_O_ID; //10,000,000 unique IDs + std::uint8_t NO_D_ID; //20 unique IDs + std::uint16_t NO_W_ID; //2*W unique IDs //Primary Key: (NO_W_ID, NO_D_ID, NO_O_ID) //key size is 8 bytes. - static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, char *out) { + static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, char* out) { assign_as_bigendian(w_id, &out[0]); out[2] = 0; assign_as_bigendian(d_id, &out[3]); assign_as_bigendian(o_id, &out[4]); } - void createKey(char *out) const { return CreateKey(NO_W_ID, NO_D_ID, NO_O_ID, out); } + void createKey(char* out) const { + return CreateKey(NO_W_ID, NO_D_ID, NO_O_ID, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct Order { //(O_W_ID, O_D_ID, O_C_ID) Foreign Key, references (C_W_ID, C_D_ID, C_ID) - alignas(CACHE_LINE_SIZE) - std::uint32_t O_ID; //10,000,000 unique IDs - std::uint8_t O_D_ID; // 20 unique IDs - std::uint16_t O_W_ID; // 2*W unique IDs - std::uint32_t O_C_ID; //96,000 unique IDs - std::uint64_t O_ENTRY_D; //date and time - std::uint32_t O_CARRIER_ID; // unique IDs, or null - std::uint8_t O_OL_CNT; //numeric(2) Count of Order-Lines - std::uint8_t O_ALL_LOCAL; //numeric(1) + alignas(CACHE_LINE_SIZE) std::uint32_t O_ID; //10,000,000 unique IDs + std::uint8_t O_D_ID; // 20 unique IDs + std::uint16_t O_W_ID; // 2*W unique IDs + std::uint32_t O_C_ID; //96,000 unique IDs + std::uint64_t O_ENTRY_D; //date and time + std::uint32_t O_CARRIER_ID; // unique IDs, or null + std::uint8_t O_OL_CNT; //numeric(2) Count of Order-Lines + std::uint8_t O_ALL_LOCAL; //numeric(1) //Primary Key: (O_W_ID, O_D_ID, O_ID) //key size is 8 bytes. - static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, char *out) { + static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, char* out) { assign_as_bigendian(w_id, &out[0]); out[2] = 0; assign_as_bigendian(d_id, &out[3]); assign_as_bigendian(o_id, &out[4]); } - void createKey(char *out) const { return CreateKey(O_W_ID, O_D_ID, O_ID, out); } + void createKey(char* out) const { + return CreateKey(O_W_ID, O_D_ID, O_ID, out); + } //Secondary Key: (O_ID, O_W_ID, O_D_ID, O_C_ID) //key size is 16 bytes. static std::string_view CreateSecondaryKey(uint16_t w_id, uint8_t d_id, - uint32_t c_id, uint32_t o_id, char *out) { + uint32_t c_id, uint32_t o_id, + char* out) { ::memset(&out[0], 0, 5); assign_as_bigendian(w_id, &out[5]); assign_as_bigendian(d_id, &out[7]); @@ -299,7 +305,7 @@ struct Order { return std::string_view(out, 16); } - std::string_view createSecondaryKey(char* out){ + std::string_view createSecondaryKey(char* out) { return CreateSecondaryKey(O_W_ID, O_D_ID, O_C_ID, O_ID, out); } @@ -309,48 +315,50 @@ struct Order { struct OrderLine { //(OL_W_ID, OL_D_ID, OL_O_ID) Foreign Key, references (O_W_ID, O_D_ID, O_ID) //(OL_SUPPLY_W_ID, OL_I_ID) Foreign Key, references (S_W_ID, S_I_ID) - alignas(CACHE_LINE_SIZE) - std::uint32_t OL_O_ID;// 10,000,000 unique IDs - std::uint8_t OL_D_ID;// 20 unique IDs - std::uint16_t OL_W_ID;// 2*W unique IDs - std::uint8_t OL_NUMBER;// 15 unique IDs - std::uint32_t OL_I_ID;// 200,000 unique IDs - std::uint16_t OL_SUPPLY_W_ID;// 2*W unique IDs - std::uint64_t OL_DELIVERY_D;// date and time, or null - std::uint8_t OL_QUANTITY;// numeric(2) - double OL_AMOUNT;// signed numeric(6, 2) - char OL_DIST_INFO[25];// fixed text, size 24 + alignas(CACHE_LINE_SIZE) std::uint32_t OL_O_ID; // 10,000,000 unique IDs + std::uint8_t OL_D_ID; // 20 unique IDs + std::uint16_t OL_W_ID; // 2*W unique IDs + std::uint8_t OL_NUMBER; // 15 unique IDs + std::uint32_t OL_I_ID; // 200,000 unique IDs + std::uint16_t OL_SUPPLY_W_ID; // 2*W unique IDs + std::uint64_t OL_DELIVERY_D; // date and time, or null + std::uint8_t OL_QUANTITY; // numeric(2) + double OL_AMOUNT; // signed numeric(6, 2) + char OL_DIST_INFO[25]; // fixed text, size 24 //Primary Key: (OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER) //key size is 8 bytes. - static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, uint8_t ol_num, char *out) { + static void CreateKey(uint16_t w_id, uint8_t d_id, uint32_t o_id, + uint8_t ol_num, char* out) { assign_as_bigendian(w_id, &out[0]); assign_as_bigendian(d_id, &out[2]); assign_as_bigendian(o_id, &out[3]); assign_as_bigendian(ol_num, &out[7]); } - void createKey(char *out) const { CreateKey(OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER, out); } + void createKey(char* out) const { + CreateKey(OL_W_ID, OL_D_ID, OL_O_ID, OL_NUMBER, out); + } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; struct Item { alignas(CACHE_LINE_SIZE) - std::uint32_t I_ID; //200,000 unique IDs 100,000 items are populated - std::uint32_t I_IM_ID; //200,000 unique IDs Image ID associated to Item - char I_NAME[25]; //variable text, size 24 - double I_PRICE; //numeric(5, 2) - char I_DATA[51]; //variable text, size 50 Brand information + std::uint32_t I_ID; //200,000 unique IDs 100,000 items are populated + std::uint32_t I_IM_ID; //200,000 unique IDs Image ID associated to Item + char I_NAME[25]; //variable text, size 24 + double I_PRICE; //numeric(5, 2) + char I_DATA[51]; //variable text, size 50 Brand information //Primary Key: I_ID //key size is 8 bytes. - static void CreateKey(uint32_t i_id, char *out) { + static void CreateKey(uint32_t i_id, char* out) { ::memset(&out[0], 0, 4); assign_as_bigendian(i_id, &out[4]); } - void createKey(char *out) const { CreateKey(I_ID, out); } + void createKey(char* out) const { CreateKey(I_ID, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; @@ -359,33 +367,33 @@ struct Stock { //S_W_ID Foreign Key, references W_ID //S_I_ID Foreign Key, references I_ID alignas(CACHE_LINE_SIZE) - std::uint32_t S_I_ID; //200,000 unique IDs 100,000 populated per warehouse - std::uint16_t S_W_ID; //2*W unique IDs - int16_t S_QUANTITY; //signed numeric(4) - char S_DIST_01[25]; //fixed text, size 24 - char S_DIST_02[25]; //fixed text, size 24 - char S_DIST_03[25]; //fixed text, size 24 - char S_DIST_04[25]; // fixed text, size 24 - char S_DIST_05[25]; // fixed text, size 24 - char S_DIST_06[25]; // fixed text, size 24 - char S_DIST_07[25]; // fixed text, size 24 - char S_DIST_08[25]; // fixed text, size 24 - char S_DIST_09[25]; // fixed text, size 24 - char S_DIST_10[25]; // fixed text, size 24 - std::uint32_t S_YTD; // numeric(8) - std::uint16_t S_ORDER_CNT; // numeric(4) + std::uint32_t S_I_ID; //200,000 unique IDs 100,000 populated per warehouse + std::uint16_t S_W_ID; //2*W unique IDs + int16_t S_QUANTITY; //signed numeric(4) + char S_DIST_01[25]; //fixed text, size 24 + char S_DIST_02[25]; //fixed text, size 24 + char S_DIST_03[25]; //fixed text, size 24 + char S_DIST_04[25]; // fixed text, size 24 + char S_DIST_05[25]; // fixed text, size 24 + char S_DIST_06[25]; // fixed text, size 24 + char S_DIST_07[25]; // fixed text, size 24 + char S_DIST_08[25]; // fixed text, size 24 + char S_DIST_09[25]; // fixed text, size 24 + char S_DIST_10[25]; // fixed text, size 24 + std::uint32_t S_YTD; // numeric(8) + std::uint16_t S_ORDER_CNT; // numeric(4) std::uint16_t S_REMOTE_CNT; // numeric(4) - char S_DATA[51]; // variable text, size 50 + char S_DATA[51]; // variable text, size 50 // Primary Key: (S_W_ID, S_I_ID) composite. // key size is 8 bytes. - static void CreateKey(uint16_t w_id, uint32_t i_id, char *out) { + static void CreateKey(uint16_t w_id, uint32_t i_id, char* out) { ::memset(&out[0], 0, 2); assign_as_bigendian(w_id, &out[2]); assign_as_bigendian(i_id, &out[4]); } - void createKey(char *out) const { CreateKey(S_W_ID, S_I_ID, out); } + void createKey(char* out) const { CreateKey(S_W_ID, S_I_ID, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; diff --git a/include/tpcc/tpcc_tx_delivery.hh b/include/tpcc/tpcc_tx_delivery.hh index 4e7f50f8..28ed6e98 100644 --- a/include/tpcc/tpcc_tx_delivery.hh +++ b/include/tpcc/tpcc_tx_delivery.hh @@ -33,7 +33,8 @@ // EXEC SQL WHENEVER NOT FOUND continue; // EXEC SQL FETCH c_no INTO :no_o_id; template -bool get_order_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t &o_id, bool &found) { +bool get_order_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t& o_id, + bool& found) { found = false; std::vector result; SimpleKey<8> left_key, right_key; @@ -41,15 +42,12 @@ bool get_order_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t &o_id, b NewOrder::CreateKey(w_id, d_id + 1, 1, right_key.ptr()); // Return value intentionally discarded: the empty-result and aborted // checks below cover both Status::OK and Status::WARN_NOT_FOUND. - (void)tx.scan(Storage::NewOrder, left_key.view(), false, right_key.view(), true, result, 1); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + (void) tx.scan(Storage::NewOrder, left_key.view(), false, right_key.view(), + true, result, 1); + if (tx.status_ == TransactionStatus::aborted) { return false; } // Per TPC-C spec: if no NEW-ORDER row exists for this district, skip // delivery for this district only (caller continues with the next). - if (result.empty()) { - return true; - } + if (result.empty()) { return true; } found = true; TupleBody* body = *result.begin(); o_id = body->get_value().cast_to().NO_O_ID; @@ -61,16 +59,15 @@ bool get_order_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t &o_id, b // EXEC SQL DELETE FROM new_order WHERE CURRENT OF c_no; // EXEC SQL CLOSE c_no; template -bool delete_new_order(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t o_id) { +bool delete_new_order(TxExecutor& tx, uint16_t w_id, uint8_t d_id, + uint32_t o_id) { SimpleKey<8> no_key; NewOrder::CreateKey(w_id, d_id, o_id, no_key.ptr()); // Return value intentionally discarded: we already verified the row // exists via get_order_id() before calling here, so the only thing left // for the caller to react to is an abort. - (void)tx.delete_record(Storage::NewOrder, no_key.view()); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + (void) tx.delete_record(Storage::NewOrder, no_key.view()); + if (tx.status_ == TransactionStatus::aborted) { return false; } return true; } @@ -86,33 +83,29 @@ bool delete_new_order(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t o_id // WHERE o_id = :no_o_id AND o_d_id = :d_id AND // o_w_id = :w_id; template -bool update_order_and_get_c_id( - TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t o_id, uint8_t o_carrier_id, uint32_t &c_id) { +bool update_order_and_get_c_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, + uint32_t o_id, uint8_t o_carrier_id, + uint32_t& c_id) { SimpleKey<8> o_key; Order::CreateKey(w_id, d_id, o_id, o_key.ptr()); - TupleBody *body; + TupleBody* body; Status status = tx.read(Storage::Order, o_key.view(), &body); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + if (tx.status_ == TransactionStatus::aborted) { return false; } // tx.read leaves *body unchanged on WARN_NOT_FOUND; caller must check. - if (status != Status::OK) { - return false; - } - Order &ord = body->get_value().cast_to(); + if (status != Status::OK) { return false; } + Order& ord = body->get_value().cast_to(); c_id = ord.O_C_ID; HeapObject o_obj; o_obj.allocate(); - Order &new_ord = o_obj.ref(); + Order& new_ord = o_obj.ref(); memcpy(&new_ord, &ord, sizeof(new_ord)); new_ord.O_CARRIER_ID = o_carrier_id; - status = tx.update(Storage::Order, o_key.view(), TupleBody(o_key.view(), std::move(o_obj))); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + status = tx.update(Storage::Order, o_key.view(), + TupleBody(o_key.view(), std::move(o_obj))); + if (tx.status_ == TransactionStatus::aborted) { return false; } return true; } @@ -131,34 +124,33 @@ bool update_order_and_get_c_id( // WHERE ol_o_id = :no_o_id AND ol_d_id = :d_id // AND ol_w_id = :w_id; template -bool update_order_line_and_get_ol_total( - TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t o_id, uint64_t ol_delivery_d, double &ol_total) -{ +bool update_order_line_and_get_ol_total(TxExecutor& tx, uint16_t w_id, + uint8_t d_id, uint32_t o_id, + uint64_t ol_delivery_d, + double& ol_total) { std::vector result; SimpleKey<8> left_key, right_key; OrderLine::CreateKey(w_id, d_id, o_id, 1, left_key.ptr()); OrderLine::CreateKey(w_id, d_id, o_id + 1, 1, right_key.ptr()); - Status status = tx.scan(Storage::OrderLine, left_key.view(), false, right_key.view(), true, result); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + Status status = tx.scan(Storage::OrderLine, left_key.view(), false, + right_key.view(), true, result); + if (tx.status_ == TransactionStatus::aborted) { return false; } ol_total = 0.0; - for (auto& tuple : result) { + for (auto& tuple : result) { const std::string_view ol_key = tuple->get_key(); - const OrderLine &ol = tuple->get_value().cast_to(); + const OrderLine& ol = tuple->get_value().cast_to(); HeapObject ol_obj; ol_obj.allocate(); - OrderLine &new_ol = ol_obj.ref(); + OrderLine& new_ol = ol_obj.ref(); memcpy(&new_ol, &ol, sizeof(new_ol)); new_ol.OL_DELIVERY_D = ol_delivery_d; - status = tx.update(Storage::OrderLine, ol_key, TupleBody(ol_key, std::move(ol_obj))); + status = tx.update(Storage::OrderLine, ol_key, + TupleBody(ol_key, std::move(ol_obj))); if (status != Status::OK) ERR; - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + if (tx.status_ == TransactionStatus::aborted) { return false; } ol_total += ol.OL_AMOUNT; } return true; @@ -174,38 +166,32 @@ bool update_order_line_and_get_ol_total( // WHERE c_id = :c_id AND c_d_id = :d_id AND // c_w_id = :w_id; template -bool update_customer_balance( - TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t c_id, double ol_total) -{ +bool update_customer_balance(TxExecutor& tx, uint16_t w_id, uint8_t d_id, + uint32_t c_id, double ol_total) { SimpleKey<8> c_key; Customer::CreateKey(w_id, d_id, c_id, c_key.ptr()); - TupleBody *body; + TupleBody* body; Status status = tx.read(Storage::Customer, c_key.view(), &body); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } - if (status != Status::OK) { - return false; - } - Customer &cust = body->get_value().cast_to(); + if (tx.status_ == TransactionStatus::aborted) { return false; } + if (status != Status::OK) { return false; } + Customer& cust = body->get_value().cast_to(); HeapObject c_obj; c_obj.allocate(); - Customer &new_cust = c_obj.ref(); + Customer& new_cust = c_obj.ref(); memcpy(&new_cust, &cust, sizeof(new_cust)); new_cust.C_BALANCE += ol_total; new_cust.C_DELIVERY_CNT += 1; - status = tx.update(Storage::Customer, c_key.view(), TupleBody(c_key.view(), std::move(c_obj))); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + status = tx.update(Storage::Customer, c_key.view(), + TupleBody(c_key.view(), std::move(c_obj))); + if (tx.status_ == TransactionStatus::aborted) { return false; } return true; } template -bool run_delivery(TxExecutor &tx, TPCCQuery::Delivery *query) { +bool run_delivery(TxExecutor& tx, TPCCQuery::Delivery* query) { uint16_t w_id = query->w_id; uint8_t o_carrier_id = query->o_carrier_id; uint64_t ol_delivery_d = query->ol_delivery_d; @@ -213,23 +199,26 @@ bool run_delivery(TxExecutor &tx, TPCCQuery::Delivery *query) { for (uint8_t d_id = 1; d_id <= DIST_PER_WARE; ++d_id) { uint32_t o_id; bool found; - if (!get_order_id(tx, w_id, d_id, o_id, found)) + if (!get_order_id(tx, w_id, d_id, o_id, found)) return false; // No outstanding new-order in this district: skip per TPC-C spec. if (!found) continue; - if (!delete_new_order(tx, w_id, d_id, o_id)) + if (!delete_new_order(tx, w_id, d_id, o_id)) return false; uint32_t c_id; - if (!update_order_and_get_c_id(tx, w_id, d_id, o_id, o_carrier_id, c_id)) + if (!update_order_and_get_c_id(tx, w_id, d_id, o_id, + o_carrier_id, c_id)) return false; double ol_total = 0.0; - if (!update_order_line_and_get_ol_total(tx, w_id, d_id, o_id, ol_delivery_d, ol_total)) + if (!update_order_line_and_get_ol_total( + tx, w_id, d_id, o_id, ol_delivery_d, ol_total)) return false; - if (!update_customer_balance(tx, w_id, d_id, c_id, ol_total)) + if (!update_customer_balance(tx, w_id, d_id, c_id, + ol_total)) return false; } diff --git a/include/tpcc/tpcc_tx_neworder.hh b/include/tpcc/tpcc_tx_neworder.hh index b43e9a30..d5a105b3 100644 --- a/include/tpcc/tpcc_tx_neworder.hh +++ b/include/tpcc/tpcc_tx_neworder.hh @@ -18,27 +18,24 @@ template bool get_warehouse(TxExecutor& tx, uint16_t w_id, const Warehouse*& ware) { SimpleKey<8> w_key; Warehouse::CreateKey(w_id, w_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Warehouse, w_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } ware = &body->get_value().cast_to(); return true; } template -bool get_customer(TxExecutor& tx, uint32_t c_id, uint8_t d_id, uint16_t w_id, const Customer*& cust) { +bool get_customer(TxExecutor& tx, uint32_t c_id, uint8_t d_id, uint16_t w_id, + const Customer*& cust) { SimpleKey<8> c_key; Customer::CreateKey(w_id, d_id, c_id, c_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Customer, c_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } cust = &body->get_value().cast_to(); return true; } @@ -55,15 +52,14 @@ bool get_customer(TxExecutor& tx, uint32_t c_id, uint8_t d_id, uint16_t w_id, co * +=================================================== */ template -bool get_and_update_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, District& dist) { +bool get_and_update_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, + District& dist) { SimpleKey<8> d_key; District::CreateKey(w_id, d_id, d_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::District, d_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } HeapObject d_obj; d_obj.allocate(); District& new_dist = d_obj.ref(); @@ -72,11 +68,10 @@ bool get_and_update_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, Distri new_dist.D_NEXT_O_ID++; // Copy out before std::move consumes d_obj (otherwise dist would dangle). dist = new_dist; - stat = tx.update(Storage::District, d_key.view(), TupleBody(d_key.view(), std::move(d_obj))); + stat = tx.update(Storage::District, d_key.view(), + TupleBody(d_key.view(), std::move(d_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } return true; } @@ -88,8 +83,8 @@ bool get_and_update_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, Distri * +======================================= */ template -bool insert_order(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id, uint32_t c_id, - uint8_t ol_cnt, bool remote, Order& ord) { +bool insert_order(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id, + uint32_t c_id, uint8_t ol_cnt, bool remote, Order& ord) { HeapObject o_obj; o_obj.allocate(); Order& new_ord = o_obj.ref(); @@ -106,16 +101,20 @@ bool insert_order(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id, ui key_obj.allocate>(); SimpleKey<8>& o_key = key_obj.ref(); Order::CreateKey(new_ord.O_W_ID, new_ord.O_D_ID, new_ord.O_ID, o_key.ptr()); - Status stat = tx.insert(Storage::Order, o_key.view(), TupleBody(o_key.view(), std::move(o_obj))); + Status stat = tx.insert(Storage::Order, o_key.view(), + TupleBody(o_key.view(), std::move(o_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat == Status::WARN_ALREADY_EXISTS || tx.status_ == TransactionStatus::aborted) { + if (stat == Status::WARN_ALREADY_EXISTS || + tx.status_ == TransactionStatus::aborted) { dump(tx.thid_, "insert order failed"); return false; } SimpleKey<16> o_sec_key; Order::CreateSecondaryKey(w_id, d_id, c_id, o_id, o_sec_key.ptr()); - stat = tx.insert(Storage::OrderSecondary, o_sec_key.view(), TupleBody(o_sec_key.view(), std::move(key_obj))); - if (stat == Status::WARN_ALREADY_EXISTS || tx.status_ == TransactionStatus::aborted) { + stat = tx.insert(Storage::OrderSecondary, o_sec_key.view(), + TupleBody(o_sec_key.view(), std::move(key_obj))); + if (stat == Status::WARN_ALREADY_EXISTS || + tx.status_ == TransactionStatus::aborted) { dump(tx.thid_, "insert order-secondary failed"); return false; } @@ -130,7 +129,8 @@ bool insert_order(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id, ui * +======================================================= */ template -bool insert_neworder(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id) { +bool insert_neworder(TxExecutor& tx, uint32_t o_id, uint8_t d_id, + uint16_t w_id) { HeapObject no_obj; no_obj.allocate(); NewOrder& new_no = no_obj.ref(); @@ -138,12 +138,12 @@ bool insert_neworder(TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id) new_no.NO_D_ID = d_id; new_no.NO_W_ID = w_id; SimpleKey<8> no_key; - NewOrder::CreateKey(new_no.NO_W_ID, new_no.NO_D_ID, new_no.NO_O_ID, no_key.ptr()); - Status stat = tx.insert(Storage::NewOrder, no_key.view(), TupleBody(no_key.view(), std::move(no_obj))); + NewOrder::CreateKey(new_no.NO_W_ID, new_no.NO_D_ID, new_no.NO_O_ID, + no_key.ptr()); + Status stat = tx.insert(Storage::NewOrder, no_key.view(), + TupleBody(no_key.view(), std::move(no_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat == Status::WARN_ALREADY_EXISTS) { - return false; - } + if (stat == Status::WARN_ALREADY_EXISTS) { return false; } return true; } @@ -160,12 +160,10 @@ template bool get_item(TxExecutor& tx, uint32_t ol_i_id, const Item*& item) { SimpleKey<8> i_key; Item::CreateKey(ol_i_id, i_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Item, i_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } item = &body->get_value().cast_to(); return true; } @@ -188,42 +186,37 @@ bool get_item(TxExecutor& tx, uint32_t ol_i_id, const Item*& item) { */ template bool get_and_update_stock(TxExecutor& tx, uint16_t ol_supply_w_id, - uint32_t ol_i_id, uint8_t ol_quantity, - bool remote, Stock& sto) { - SimpleKey<8> s_key; - Stock::CreateKey(ol_supply_w_id, ol_i_id, s_key.ptr()); - TupleBody *body; - Status stat = tx.read(Storage::Stock, s_key.view(), &body); - if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } - const Stock& old_sto = body->get_value().cast_to(); - - HeapObject s_obj; - s_obj.allocate(); - Stock& new_sto = s_obj.ref(); - memcpy(&new_sto, &old_sto, sizeof(new_sto)); - - new_sto.S_YTD = old_sto.S_YTD + ol_quantity; - new_sto.S_ORDER_CNT = old_sto.S_ORDER_CNT + 1; - if (remote) { - new_sto.S_REMOTE_CNT = old_sto.S_REMOTE_CNT + 1; - } - - int32_t s_quantity = old_sto.S_QUANTITY; - int32_t quantity = s_quantity - ol_quantity; - if (s_quantity <= ol_quantity + 10) quantity += 91; - new_sto.S_QUANTITY = quantity; - - // Copy out before std::move consumes s_obj. - sto = new_sto; - stat = tx.update(Storage::Stock, s_key.view(), TupleBody(s_key.view(), std::move(s_obj))); - if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } - return true; + uint32_t ol_i_id, uint8_t ol_quantity, bool remote, + Stock& sto) { + SimpleKey<8> s_key; + Stock::CreateKey(ol_supply_w_id, ol_i_id, s_key.ptr()); + TupleBody* body; + Status stat = tx.read(Storage::Stock, s_key.view(), &body); + if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); + if (stat != Status::OK) { return false; } + const Stock& old_sto = body->get_value().cast_to(); + + HeapObject s_obj; + s_obj.allocate(); + Stock& new_sto = s_obj.ref(); + memcpy(&new_sto, &old_sto, sizeof(new_sto)); + + new_sto.S_YTD = old_sto.S_YTD + ol_quantity; + new_sto.S_ORDER_CNT = old_sto.S_ORDER_CNT + 1; + if (remote) { new_sto.S_REMOTE_CNT = old_sto.S_REMOTE_CNT + 1; } + + int32_t s_quantity = old_sto.S_QUANTITY; + int32_t quantity = s_quantity - ol_quantity; + if (s_quantity <= ol_quantity + 10) quantity += 91; + new_sto.S_QUANTITY = quantity; + + // Copy out before std::move consumes s_obj. + sto = new_sto; + stat = tx.update(Storage::Stock, s_key.view(), + TupleBody(s_key.view(), std::move(s_obj))); + if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); + if (stat != Status::OK) { return false; } + return true; } @@ -237,10 +230,10 @@ bool get_and_update_stock(TxExecutor& tx, uint16_t ol_supply_w_id, * +==================================================== */ template -bool insert_orderline( - TxExecutor& tx, uint32_t o_id, uint8_t d_id, uint16_t w_id, - uint8_t ol_num, uint32_t ol_i_id, uint16_t ol_supply_w_id, - uint8_t ol_quantity, double ol_amount, const Stock& sto) { +bool insert_orderline(TxExecutor& tx, uint32_t o_id, uint8_t d_id, + uint16_t w_id, uint8_t ol_num, uint32_t ol_i_id, + uint16_t ol_supply_w_id, uint8_t ol_quantity, + double ol_amount, const Stock& sto) { HeapObject ol_obj; ol_obj.allocate(); OrderLine& new_ol = ol_obj.ref(); @@ -254,17 +247,28 @@ bool insert_orderline( new_ol.OL_AMOUNT = ol_amount; auto pick_sdist = [&]() -> const char* { switch (d_id) { - case 1: return sto.S_DIST_01; - case 2: return sto.S_DIST_02; - case 3: return sto.S_DIST_03; - case 4: return sto.S_DIST_04; - case 5: return sto.S_DIST_05; - case 6: return sto.S_DIST_06; - case 7: return sto.S_DIST_07; - case 8: return sto.S_DIST_08; - case 9: return sto.S_DIST_09; - case 10: return sto.S_DIST_10; - default: return nullptr; // BUG + case 1: + return sto.S_DIST_01; + case 2: + return sto.S_DIST_02; + case 3: + return sto.S_DIST_03; + case 4: + return sto.S_DIST_04; + case 5: + return sto.S_DIST_05; + case 6: + return sto.S_DIST_06; + case 7: + return sto.S_DIST_07; + case 8: + return sto.S_DIST_08; + case 9: + return sto.S_DIST_09; + case 10: + return sto.S_DIST_10; + default: + return nullptr; // BUG } }; copy_cstr(new_ol.OL_DIST_INFO, pick_sdist(), sizeof(new_ol.OL_DIST_INFO)); @@ -272,58 +276,65 @@ bool insert_orderline( SimpleKey<8> ol_key; OrderLine::CreateKey(new_ol.OL_W_ID, new_ol.OL_D_ID, new_ol.OL_O_ID, new_ol.OL_NUMBER, ol_key.ptr()); - Status stat = tx.insert(Storage::OrderLine, ol_key.view(), TupleBody(ol_key.view(), std::move(ol_obj))); + Status stat = tx.insert(Storage::OrderLine, ol_key.view(), + TupleBody(ol_key.view(), std::move(ol_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat == Status::WARN_ALREADY_EXISTS) { - return false; - } + if (stat == Status::WARN_ALREADY_EXISTS) { return false; } return true; } template -bool run_new_order(TxExecutor& tx, TPCCQuery::NewOrder *query) { +bool run_new_order(TxExecutor& tx, TPCCQuery::NewOrder* query) { bool remote = query->remote; uint16_t w_id = query->w_id; uint8_t d_id = query->d_id; uint32_t c_id = query->c_id; uint8_t ol_cnt = query->ol_cnt; - const Warehouse *ware; - if (!get_warehouse(tx, w_id, ware)) return false; + const Warehouse* ware; + if (!get_warehouse(tx, w_id, ware)) return false; - const Customer *cust; - if (!get_customer(tx, c_id, d_id, w_id, cust)) return false; + const Customer* cust; + if (!get_customer(tx, c_id, d_id, w_id, cust)) + return false; District dist; - if (!get_and_update_district(tx, d_id, w_id, dist)) return false; + if (!get_and_update_district(tx, d_id, w_id, dist)) + return false; uint32_t o_id = dist.D_NEXT_O_ID; Order ord; - if (!insert_order(tx, o_id, d_id, w_id, c_id, ol_cnt, remote, ord)) return false; - if (!insert_neworder(tx, o_id, d_id, w_id)) return false; + if (!insert_order(tx, o_id, d_id, w_id, c_id, ol_cnt, + remote, ord)) + return false; + if (!insert_neworder(tx, o_id, d_id, w_id)) + return false; for (std::uint32_t ol_num = 0; ol_num < ol_cnt; ++ol_num) { uint32_t ol_i_id = query->items[ol_num].ol_i_id; uint16_t ol_supply_w_id = query->items[ol_num].ol_supply_w_id; uint8_t ol_quantity = query->items[ol_num].ol_quantity; - const Item *item; - if (!get_item(tx, ol_i_id, item)) return false; + const Item* item; + if (!get_item(tx, ol_i_id, item)) return false; Stock sto; - if (!get_and_update_stock( - tx, ol_supply_w_id, ol_i_id, ol_quantity, remote, sto)) return false; + if (!get_and_update_stock(tx, ol_supply_w_id, ol_i_id, + ol_quantity, remote, sto)) + return false; double i_price = item->I_PRICE; double w_tax = ware->W_TAX; double d_tax = dist.D_TAX; double c_discount = cust->C_DISCOUNT; - double ol_amount = ol_quantity * i_price * (1.0 + w_tax + d_tax) * (1.0 - c_discount); + double ol_amount = + ol_quantity * i_price * (1.0 + w_tax + d_tax) * (1.0 - c_discount); - if (!insert_orderline( - tx, o_id, d_id, w_id, ol_num, ol_i_id, - ol_supply_w_id, ol_quantity, ol_amount, sto)) return false; + if (!insert_orderline(tx, o_id, d_id, w_id, ol_num, + ol_i_id, ol_supply_w_id, + ol_quantity, ol_amount, sto)) + return false; } // end of ol loop return true; diff --git a/include/tpcc/tpcc_tx_orderstatus.hh b/include/tpcc/tpcc_tx_orderstatus.hh index bb180c27..75dfeada 100644 --- a/include/tpcc/tpcc_tx_orderstatus.hh +++ b/include/tpcc/tpcc_tx_orderstatus.hh @@ -17,20 +17,21 @@ // FROM orders // ORDER BY o_id DESC; template -bool get_order_key_by_customer_id(TxExecutor& tx, - uint16_t w_id, uint8_t d_id, uint32_t c_id, - SimpleKey<8>& o_key) { -// Storage storage = Storage::OrderSecondary; -// char left_key_buf[16], right_key_buf[16]; -// std::string_view left_key = Order::CreateSecondaryKey(w_id, d_id, c_id, 1, &left_key_buf[0]); -// std::string_view right_key = Order::CreateSecondaryKey(w_id, d_id, c_id+1, 1, &right_key_buf[0]); +bool get_order_key_by_customer_id(TxExecutor& tx, uint16_t w_id, uint8_t d_id, + uint32_t c_id, SimpleKey<8>& o_key) { + // Storage storage = Storage::OrderSecondary; + // char left_key_buf[16], right_key_buf[16]; + // std::string_view left_key = Order::CreateSecondaryKey(w_id, d_id, c_id, 1, &left_key_buf[0]); + // std::string_view right_key = Order::CreateSecondaryKey(w_id, d_id, c_id+1, 1, &right_key_buf[0]); std::vector result; SimpleKey<16> left_key, right_key; Order::CreateSecondaryKey(w_id, d_id, c_id, 1, left_key.ptr()); - Order::CreateSecondaryKey(w_id, d_id, c_id+1, 1, right_key.ptr()); - Status status = tx.scan(Storage::OrderSecondary, left_key.view(), false, right_key.view(), true, result, 1); + Order::CreateSecondaryKey(w_id, d_id, c_id + 1, 1, right_key.ptr()); + Status status = tx.scan(Storage::OrderSecondary, left_key.view(), false, + right_key.view(), true, result, 1); if (status != Status::OK || tx.status_ == TransactionStatus::aborted) { - dump(tx.thid_, "cannot get order ID by scanning order-secondary with customer ID"); + dump(tx.thid_, + "cannot get order ID by scanning order-secondary with customer ID"); return false; } if (result.size() != 1) ERR; @@ -65,25 +66,24 @@ bool get_orderline(TxExecutor& tx, uint16_t w_id, uint8_t d_id, uint32_t o_id) { std::vector result; SimpleKey<8> left_key, right_key; OrderLine::CreateKey(w_id, d_id, o_id, 1, left_key.ptr()); - OrderLine::CreateKey(w_id, d_id, o_id+1, 1, right_key.ptr()); + OrderLine::CreateKey(w_id, d_id, o_id + 1, 1, right_key.ptr()); // Return value intentionally discarded: the empty-result and aborted // checks below cover both Status::OK and Status::WARN_NOT_FOUND. - (void)tx.scan( - Storage::OrderLine, left_key.view(), false, right_key.view(), true, result); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + (void) tx.scan(Storage::OrderLine, left_key.view(), false, right_key.view(), + true, result); + if (tx.status_ == TransactionStatus::aborted) { return false; } for (auto& tuple : result) { - [[maybe_unused]] const OrderLine& ol = tuple->get_value().cast_to(); + [[maybe_unused]] const OrderLine& ol = + tuple->get_value().cast_to(); } return true; } -bool get_customer_key_by_last_name( - uint16_t w_id, uint8_t d_id, const char* c_last, SimpleKey<8>& c_key); +bool get_customer_key_by_last_name(uint16_t w_id, uint8_t d_id, + const char* c_last, SimpleKey<8>& c_key); template -bool run_order_status(TxExecutor& tx, TPCCQuery::OrderStatus *query) { +bool run_order_status(TxExecutor& tx, TPCCQuery::OrderStatus* query) { uint16_t w_id = query->w_id; uint8_t d_id = query->d_id; uint32_t c_id = query->c_id; @@ -102,24 +102,21 @@ bool run_order_status(TxExecutor& tx, TPCCQuery::OrderStatus *query) { } // get customer - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Customer, key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } const Customer& cust = body->get_value().cast_to(); c_id = cust.C_ID; // search order by c_id - if (!get_order_key_by_customer_id(tx, w_id, d_id, c_id, key)) + if (!get_order_key_by_customer_id(tx, w_id, d_id, + c_id, key)) return false; // get order stat = tx.read(Storage::Order, key.view(), &body); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + if (tx.status_ == TransactionStatus::aborted) { return false; } // The OrderSecondary→Order indirection can return a primary key whose // Order row is absent (the secondary index can be momentarily stale // under concurrent writes). tx.read leaves *body unchanged on @@ -127,13 +124,11 @@ bool run_order_status(TxExecutor& tx, TPCCQuery::OrderStatus *query) { // body pointed to from the previous tx.read in this transaction — // typically the Customer row, which is a different size and triggers // a HeapObject::cast_to assertion. - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } const Order& o = body->get_value().cast_to(); // scan orderline - if (!get_orderline(tx, o.O_W_ID, o.O_D_ID, o.O_ID)) + if (!get_orderline(tx, o.O_W_ID, o.O_D_ID, o.O_ID)) return false; return true; diff --git a/include/tpcc/tpcc_tx_payment.hh b/include/tpcc/tpcc_tx_payment.hh index f9b25bb7..af673909 100644 --- a/include/tpcc/tpcc_tx_payment.hh +++ b/include/tpcc/tpcc_tx_payment.hh @@ -17,15 +17,14 @@ * +=================================================================== */ template -bool get_and_update_warehouse(TxExecutor& tx, uint16_t w_id, double h_amount, Warehouse& ware) { +bool get_and_update_warehouse(TxExecutor& tx, uint16_t w_id, double h_amount, + Warehouse& ware) { SimpleKey<8> w_key; Warehouse::CreateKey(w_id, w_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Warehouse, w_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } Warehouse& old_ware = body->get_value().cast_to(); HeapObject w_obj; @@ -37,11 +36,10 @@ bool get_and_update_warehouse(TxExecutor& tx, uint16_t w_id, double h_amount, Wa // Copy out before std::move consumes w_obj. ware = new_ware; - stat = tx.update(Storage::Warehouse, w_key.view(), TupleBody(w_key.view(), std::move(w_obj))); + stat = tx.update(Storage::Warehouse, w_key.view(), + TupleBody(w_key.view(), std::move(w_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } return true; } @@ -56,16 +54,14 @@ bool get_and_update_warehouse(TxExecutor& tx, uint16_t w_id, double h_amount, Wa * +==================================================================== */ template -bool get_and_update_district(TxExecutor& tx, - uint8_t d_id, uint16_t w_id, double h_amount, District& dist) { +bool get_and_update_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, + double h_amount, District& dist) { SimpleKey<8> d_key; District::CreateKey(w_id, d_id, d_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::District, d_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } District& old_dist = body->get_value().cast_to(); HeapObject d_obj; @@ -77,11 +73,10 @@ bool get_and_update_district(TxExecutor& tx, // Copy out before std::move consumes d_obj. dist = new_dist; - stat = tx.update(Storage::District, d_key.view(), TupleBody(d_key.view(), std::move(d_obj))); + stat = tx.update(Storage::District, d_key.view(), + TupleBody(d_key.view(), std::move(d_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } return true; } @@ -109,16 +104,18 @@ bool get_and_update_district(TxExecutor& tx, * ========================================================== */ template -bool get_customer_key_by_last_name( - uint16_t c_w_id, uint8_t c_d_id, const char* c_last, SimpleKey<8>& c_key) { +bool get_customer_key_by_last_name(uint16_t c_w_id, uint8_t c_d_id, + const char* c_last, SimpleKey<8>& c_key) { char c_last_key_buf[Customer::CLastKey::required_size()]; - std::string_view c_last_key = Customer::CreateSecondaryKey(c_w_id, c_d_id, c_last, &c_last_key_buf[0]); + std::string_view c_last_key = + Customer::CreateSecondaryKey(c_w_id, c_d_id, c_last, &c_last_key_buf[0]); MasstreeWrapper::thread_init(cached_sched_getcpu()); - Tuple* tuple = Masstrees[get_storage(Storage::CustomerSecondary)].get_value(c_last_key); + Tuple* tuple = + Masstrees[get_storage(Storage::CustomerSecondary)].get_value(c_last_key); assert(tuple != nullptr); - std::vector> *vec_ptr; + std::vector>* vec_ptr; std::string_view value_view = tuple->body_.get_val(); assert(value_view.size() == sizeof(uintptr_t)); ::memcpy(&vec_ptr, value_view.data(), sizeof(uintptr_t)); @@ -163,13 +160,11 @@ bool get_customer_key_by_last_name( template bool get_and_update_customer(TxExecutor& tx, const SimpleKey<8>& c_key, uint32_t c_id, uint8_t c_d_id, uint16_t c_w_id, - uint8_t d_id, uint16_t w_id, double h_amount) { - TupleBody *body; + uint8_t d_id, uint16_t w_id, double h_amount) { + TupleBody* body; Status stat = tx.read(Storage::Customer, c_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } const Customer& old_cust = body->get_value().cast_to(); HeapObject c_obj; @@ -182,19 +177,18 @@ bool get_and_update_customer(TxExecutor& tx, const SimpleKey<8>& c_key, new_cust.C_PAYMENT_CNT += 1; if (new_cust.C_CREDIT[0] == 'B' && new_cust.C_CREDIT[1] == 'C') { - size_t len = snprintf( - &new_cust.C_DATA[0], 501, - "| %4" PRIu32 " %2" PRIu8 " %4" PRIu16 " %2" PRIu16 " %4" PRIu16 " $%7.2f", - c_id, c_d_id, c_w_id, d_id, w_id, h_amount); + size_t len = snprintf(&new_cust.C_DATA[0], 501, + "| %4" PRIu32 " %2" PRIu8 " %4" PRIu16 " %2" PRIu16 + " %4" PRIu16 " $%7.2f", + c_id, c_d_id, c_w_id, d_id, w_id, h_amount); assert(len <= 500); len += copy_cstr(&new_cust.C_DATA[len], &old_cust.C_DATA[0], 501 - len); } - stat = tx.update(Storage::Customer, c_key.view(), TupleBody(c_key.view(), std::move(c_obj))); + stat = tx.update(Storage::Customer, c_key.view(), + TupleBody(c_key.view(), std::move(c_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } return true; } @@ -207,9 +201,10 @@ bool get_and_update_customer(TxExecutor& tx, const SimpleKey<8>& c_key, * ================================================================================ */ template -bool insert_history(TxExecutor& tx, - uint32_t c_id, uint8_t c_d_id, uint16_t c_w_id, uint8_t d_id, uint16_t w_id, - double h_amount, const char* w_name, const char* d_name, HistoryKeyGenerator *hkg) { +bool insert_history(TxExecutor& tx, uint32_t c_id, uint8_t c_d_id, + uint16_t c_w_id, uint8_t d_id, uint16_t w_id, + double h_amount, const char* w_name, const char* d_name, + HistoryKeyGenerator* hkg) { HeapObject h_obj; h_obj.allocate(); History& new_hist = h_obj.ref(); @@ -220,23 +215,23 @@ bool insert_history(TxExecutor& tx, new_hist.H_W_ID = w_id; new_hist.H_DATE = get_lightweight_timestamp(); new_hist.H_AMOUNT = h_amount; - ::snprintf(new_hist.H_DATA, sizeof(new_hist.H_DATA), - "%-10.10s %.10s", w_name, d_name); + ::snprintf(new_hist.H_DATA, sizeof(new_hist.H_DATA), "%-10.10s %.10s", + w_name, d_name); // SimpleKey<8> h_key; // Customer::CreateKey(c_w_id, c_d_id, c_id, h_key.ptr()); SimpleKey<8> h_key = hkg->get_as_simple_key(); - Status stat = tx.insert(Storage::History, h_key.view(), TupleBody(h_key.view(), std::move(h_obj))); + Status stat = tx.insert(Storage::History, h_key.view(), + TupleBody(h_key.view(), std::move(h_obj))); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat == Status::WARN_ALREADY_EXISTS) { - return false; - } + if (stat == Status::WARN_ALREADY_EXISTS) { return false; } return true; } template -bool run_payment(TxExecutor& tx, TPCCQuery::Payment *query, HistoryKeyGenerator *hkg) { +bool run_payment(TxExecutor& tx, TPCCQuery::Payment* query, + HistoryKeyGenerator* hkg) { uint16_t w_id = query->w_id; uint16_t c_w_id = query->c_w_id; uint8_t d_id = query->d_id; @@ -245,23 +240,30 @@ bool run_payment(TxExecutor& tx, TPCCQuery::Payment *query, HistoryKeyGenerator double h_amount = query->h_amount; Warehouse ware; - if (!get_and_update_warehouse(tx, w_id, h_amount, ware)) return false; + if (!get_and_update_warehouse(tx, w_id, h_amount, ware)) + return false; District dist; - if (!get_and_update_district(tx, d_id, w_id, h_amount, dist)) return false; + if (!get_and_update_district(tx, d_id, w_id, h_amount, + dist)) + return false; SimpleKey<8> c_key; if (query->by_last_name) { - if (!get_customer_key_by_last_name(c_w_id, c_d_id, query->c_last, c_key)) return false; + if (!get_customer_key_by_last_name(c_w_id, c_d_id, query->c_last, + c_key)) + return false; } else { // search customers by c_id Customer::CreateKey(c_w_id, c_d_id, c_id, c_key.ptr()); } - if (!get_and_update_customer( - tx, c_key, c_id, c_d_id, c_w_id, d_id, w_id, h_amount)) return false; + if (!get_and_update_customer( + tx, c_key, c_id, c_d_id, c_w_id, d_id, w_id, h_amount)) + return false; - if (!insert_history( - tx, c_id, c_d_id, c_w_id, d_id, w_id, h_amount, - &ware.W_NAME[0], &dist.D_NAME[0], hkg)) return false; + if (!insert_history(tx, c_id, c_d_id, c_w_id, d_id, + w_id, h_amount, &ware.W_NAME[0], + &dist.D_NAME[0], hkg)) + return false; return true; } diff --git a/include/tpcc/tpcc_tx_stocklevel.hh b/include/tpcc/tpcc_tx_stocklevel.hh index cb01704f..d612e788 100644 --- a/include/tpcc/tpcc_tx_stocklevel.hh +++ b/include/tpcc/tpcc_tx_stocklevel.hh @@ -7,41 +7,39 @@ #include "tpcc_util.hh" template -bool get_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, const District*& dist) { +bool get_district(TxExecutor& tx, uint8_t d_id, uint16_t w_id, + const District*& dist) { SimpleKey<8> d_key; District::CreateKey(w_id, d_id, d_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::District, d_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } dist = &body->get_value().cast_to(); return true; } template -bool get_stock(TxExecutor& tx, uint16_t w_id, uint32_t i_id, const Stock*& stock) { +bool get_stock(TxExecutor& tx, uint16_t w_id, uint32_t i_id, + const Stock*& stock) { SimpleKey<8> s_key; Stock::CreateKey(w_id, i_id, s_key.ptr()); - TupleBody *body; + TupleBody* body; Status stat = tx.read(Storage::Stock, s_key.view(), &body); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (stat != Status::OK) { - return false; - } + if (stat != Status::OK) { return false; } stock = &body->get_value().cast_to(); return true; } template -bool run_stock_level(TxExecutor& tx, TPCCQuery::StockLevel *query) { +bool run_stock_level(TxExecutor& tx, TPCCQuery::StockLevel* query) { uint16_t w_id = query->w_id; uint8_t d_id = query->d_id; uint8_t threshold = query->threshold; const District* dist; - if (!get_district(tx, d_id, w_id, dist)) return false; + if (!get_district(tx, d_id, w_id, dist)) return false; std::vector result; SimpleKey<8> low, up; @@ -49,11 +47,10 @@ bool run_stock_level(TxExecutor& tx, TPCCQuery::StockLevel *query) { OrderLine::CreateKey(w_id, d_id, dist->D_NEXT_O_ID, 1, up.ptr()); // Return value intentionally discarded: empty result and aborted status // checks below cover both Status::OK and Status::WARN_NOT_FOUND. - (void)tx.scan(Storage::OrderLine, low.view(), false, up.view(), true, result); + (void) tx.scan(Storage::OrderLine, low.view(), false, up.view(), true, + result); if (FLAGS_tpcc_interactive_ms) sleepMs(FLAGS_tpcc_interactive_ms); - if (tx.status_ == TransactionStatus::aborted) { - return false; - } + if (tx.status_ == TransactionStatus::aborted) { return false; } // Collect item IDs first since read/write set vector might be extended // and the pointer will be obsolete even though this is not the best way. @@ -68,7 +65,8 @@ bool run_stock_level(TxExecutor& tx, TPCCQuery::StockLevel *query) { uint32_t low_stock = 0; const Stock* stock; for (auto& ol_i_id : ol_i_ids) { - if (!get_stock(tx, w_id, ol_i_id, stock)) return false; + if (!get_stock(tx, w_id, ol_i_id, stock)) + return false; if (stock->S_QUANTITY < threshold) low_stock++; } diff --git a/include/tpcc/tpcc_util.hh b/include/tpcc/tpcc_util.hh index f80cf31c..94dd09c6 100644 --- a/include/tpcc/tpcc_util.hh +++ b/include/tpcc/tpcc_util.hh @@ -18,8 +18,7 @@ struct Xoroshiro128PlusWrapper : Xoroshiro128Plus { /** * All thread can use 64bit random number generator. */ -inline std::uint64_t random_64bits() -{ +inline std::uint64_t random_64bits() { thread_local Xoroshiro128PlusWrapper rand; return rand(); } @@ -28,8 +27,7 @@ inline std::uint64_t random_64bits() /** * returned value is in [min, max]. (both-side inclusive) */ -inline std::uint64_t random_int(std::uint64_t min, std::uint64_t max) -{ +inline std::uint64_t random_int(std::uint64_t min, std::uint64_t max) { assert(min <= max); assert(max < UINT64_MAX); @@ -37,14 +35,13 @@ inline std::uint64_t random_int(std::uint64_t min, std::uint64_t max) } -inline double random_double(std::uint64_t min, std::uint64_t max, std::size_t divider) -{ - return random_int(min, max) / (double)divider; +inline double random_double(std::uint64_t min, std::uint64_t max, + std::size_t divider) { + return random_int(min, max) / (double) divider; } -inline void fill_random(void* out, size_t size) -{ +inline void fill_random(void* out, size_t size) { char* p = reinterpret_cast(out); // The word-at-a-time loop only runs while `size >= 8`, so each 8-byte @@ -76,7 +73,8 @@ inline void fill_random(void* out, size_t size) } -constexpr std::uint64_t get_constant_for_non_uniform_random(std::uint64_t A, bool is_load) { +constexpr std::uint64_t get_constant_for_non_uniform_random(std::uint64_t A, + bool is_load) { /* * From section 2.1.6 of TPC-C specifiation v5.11.0: * @@ -121,12 +119,10 @@ constexpr std::uint64_t get_constant_for_non_uniform_random(std::uint64_t A, boo } -template +template std::uint64_t non_uniform_random(std::uint64_t x, std::uint64_t y) { constexpr std::uint64_t C = get_constant_for_non_uniform_random(A, IS_LOAD); - if (C == UINT64_MAX) { - throw std::runtime_error("non_uniform_random() bug"); - } + if (C == UINT64_MAX) { throw std::runtime_error("non_uniform_random() bug"); } return (((random_int(0, A) | random_int(x, y)) + C) % (y - x + 1)) + x; } @@ -136,9 +132,11 @@ std::uint64_t non_uniform_random(std::uint64_t x, std::uint64_t y) { * out buffer will be null-terminated. * returned value is length of the string excluding the last null-value. */ -template -std::size_t random_string_detail(std::size_t min_len, std::size_t max_len, char *out) { - const char c[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +template +std::size_t random_string_detail(std::size_t min_len, std::size_t max_len, + char* out) { + const char c[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; const std::size_t max_idx = is_number_only ? 9 : (sizeof(c) - 1); std::size_t len = random_int(min_len, max_len); @@ -148,19 +146,19 @@ std::size_t random_string_detail(std::size_t min_len, std::size_t max_len, char } #else fill_random(out, len); - for (size_t i = 0; i < len; i++) { - out[i] = c[out[i] % max_idx]; - } + for (size_t i = 0; i < len; i++) { out[i] = c[out[i] % max_idx]; } #endif out[len] = '\0'; return len; } -inline std::size_t random_alpha_string(std::size_t min_len, std::size_t max_len, char *out) { +inline std::size_t random_alpha_string(std::size_t min_len, std::size_t max_len, + char* out) { return random_string_detail(min_len, max_len, out); } -inline std::size_t random_number_string(std::size_t min_len, std::size_t max_len, char *out) { +inline std::size_t random_number_string(std::size_t min_len, + std::size_t max_len, char* out) { return random_string_detail(min_len, max_len, out); } @@ -170,7 +168,7 @@ inline std::size_t random_number_string(std::size_t min_len, std::size_t max_len * * See section 4.3.2.7 of TPC-C specification v5.11.0. */ -inline void random_zip_code(char *out) { +inline void random_zip_code(char* out) { random_number_string(4, 4, &out[0]); out[4] = '1'; out[5] = '1'; @@ -181,7 +179,8 @@ inline void random_zip_code(char *out) { } -inline void make_address(char *str1, char *str2, char *city, char *state, char *zip) { +inline void make_address(char* str1, char* str2, char* city, char* state, + char* zip) { random_alpha_string(10, 20, str1); // street 1. random_alpha_string(10, 20, str2); // street 2. random_alpha_string(10, 20, city); @@ -195,8 +194,9 @@ inline void make_address(char *str1, char *str2, char *city, char *state, char * * out buffer size must 15 + 1 or more. * returned value is the length of the c_last name excluding the last null character. */ -inline std::size_t make_c_last(std::size_t num, char *out) { - const char *chunk[] = {"BAR", "OUGHT", "ABLE", "PRI", "PRES", "ESE", "ANTI", "CALLY", "ATION", "EING"}; +inline std::size_t make_c_last(std::size_t num, char* out) { + const char* chunk[] = {"BAR", "OUGHT", "ABLE", "PRI", "PRES", + "ESE", "ANTI", "CALLY", "ATION", "EING"}; assert(num < 1000); constexpr std::size_t buf_size = 16; @@ -220,14 +220,12 @@ private: public: IsOriginal(std::size_t nr_total, std::size_t nr_original) - : bitvec_(nr_total), nr_total_(nr_total) { + : bitvec_(nr_total), nr_total_(nr_total) { assert(nr_total > nr_original); // CAUSION: nr_original is too large. the following code will be very very slow. for (std::size_t i = 0; i < nr_original; i++) { std::size_t id; - do { - id = random_int(0, nr_total - 1); - } while (bitvec_[id]); + do { id = random_int(0, nr_total - 1); } while (bitvec_[id]); bitvec_[id] = true; } } @@ -239,13 +237,11 @@ public: }; -inline void make_original(char *target, std::size_t len) { +inline void make_original(char* target, std::size_t len) { assert(len >= 8); const char orig[] = "ORIGINAL"; std::size_t pos = random_int(0, len - 8); - for (std::size_t i = 0; i < 8; i++) { - target[pos + i] = orig[i]; - } + for (std::size_t i = 0; i < 8; i++) { target[pos + i] = orig[i]; } } @@ -259,7 +255,7 @@ struct Permutation { assert(min < max); { std::size_t i = min; - for (std::size_t &val : perm_) { + for (std::size_t& val : perm_) { val = i; i++; } @@ -285,7 +281,6 @@ struct Permutation { alignas(CACHE_LINE_SIZE) inline time_t TPCCTimestamp; -[[maybe_unused]] inline time_t get_lightweight_timestamp() -{ - return loadAcquire(TPCCTimestamp); +[[maybe_unused]] inline time_t get_lightweight_timestamp() { + return loadAcquire(TPCCTimestamp); } diff --git a/include/tsc.hh b/include/tsc.hh index 96127641..a940149c 100644 --- a/include/tsc.hh +++ b/include/tsc.hh @@ -2,8 +2,7 @@ #include -[[maybe_unused]] static uint64_t -rdtsc() { +[[maybe_unused]] static uint64_t rdtsc() { uint64_t rax; uint64_t rdx; @@ -15,19 +14,17 @@ rdtsc() { return (rdx << 32) | rax; } -[[maybe_unused]] static uint64_t -rdtsc_serial() { +[[maybe_unused]] static uint64_t rdtsc_serial() { uint64_t rax; uint64_t rdx; - asm volatile("cpuid":: : "rax", "rbx", "rcx", "rdx"); + asm volatile("cpuid" ::: "rax", "rbx", "rcx", "rdx"); asm volatile("rdtsc" : "=a"(rax), "=d"(rdx)); return (rdx << 32) | rax; } -[[maybe_unused]] static uint64_t -rdtscp() { +[[maybe_unused]] static uint64_t rdtscp() { uint64_t rax; uint64_t rdx; uint32_t aux; diff --git a/include/tuple_body.hh b/include/tuple_body.hh index 9d0635c4..71b3dd82 100644 --- a/include/tuple_body.hh +++ b/include/tuple_body.hh @@ -13,7 +13,7 @@ #include "heap_object.hh" #include "util.hh" -class TupleBody { // NOLINT +class TupleBody { // NOLINT public: TupleBody() = default; @@ -23,17 +23,18 @@ public: * @param val * @param val_align */ - TupleBody(std::string_view key, std::string_view val, std::align_val_t val_align) - : key_(key), val_() { + TupleBody(std::string_view key, std::string_view val, + std::align_val_t val_align) + : key_(key), val_() { val_.deep_copy_from(val.data(), val.size(), val_align); } - TupleBody(const TupleBody &right) : TupleBody() { + TupleBody(const TupleBody& right) : TupleBody() { key_ = right.key_; val_.deep_copy_from(right.val_); } - TupleBody(TupleBody &&right) noexcept : TupleBody() { + TupleBody(TupleBody&& right) noexcept : TupleBody() { key_ = std::move(right.key_); val_ = std::move(right.val_); } @@ -42,13 +43,13 @@ public: set(key, std::move(obj)); } - TupleBody &operator=(const TupleBody &right) { + TupleBody& operator=(const TupleBody& right) { key_ = right.key_; val_.deep_copy_from(right.val_); return *this; } - TupleBody &operator=(TupleBody &&right) noexcept { + TupleBody& operator=(TupleBody&& right) noexcept { key_ = std::move(right.key_); val_ = std::move(right.val_); return *this; @@ -58,7 +59,7 @@ public: [[nodiscard]] std::string_view get_val() const { return val_.view(); } - [[nodiscard]] void *get_val_ptr() { return val_.data(); } + [[nodiscard]] void* get_val_ptr() { return val_.data(); } [[nodiscard]] std::size_t get_val_size() const { return val_.size(); } @@ -67,9 +68,7 @@ public: void set_key(std::string_view key) { key_ = key; // copy } - void set_value(HeapObject&& val) { - val_ = std::move(val); - } + void set_value(HeapObject&& val) { val_ = std::move(val); } void set(std::string_view key, HeapObject&& val) { set_key(key); set_value(std::move(val)); diff --git a/include/tx_executor_concept.hh b/include/tx_executor_concept.hh index d125eb52..2dbefc0b 100644 --- a/include/tx_executor_concept.hh +++ b/include/tx_executor_concept.hh @@ -8,7 +8,7 @@ #include "status.hh" #include "tuple_body.hh" -#include "workload.hh" // for `enum class Storage` +#include "workload.hh" // for `enum class Storage` /** * @brief Compile-time contract every protocol's `TxExecutor` must satisfy. @@ -36,18 +36,17 @@ * families. */ template -concept TxExecutorLike = requires( - T t, - Storage s, - std::string_view k, - TupleBody** body, - std::vector& result) { - { t.read(s, k, body) } -> std::same_as; - { t.update(s, k, std::declval()) } -> std::same_as; - { t.insert(s, k, std::declval()) } -> std::same_as; - { t.delete_record(s, k) } -> std::same_as; - { t.scan(s, k, false, k, false, result) } -> std::same_as; - { t.scan(s, k, false, k, false, result, std::int64_t{}) } -> std::same_as; - { t.commit() } -> std::same_as; - { t.abort() } -> std::same_as; +concept TxExecutorLike = requires(T t, Storage s, std::string_view k, + TupleBody** body, + std::vector& result) { + { t.read(s, k, body) } -> std::same_as; + { t.update(s, k, std::declval()) } -> std::same_as; + { t.insert(s, k, std::declval()) } -> std::same_as; + { t.delete_record(s, k) } -> std::same_as; + { t.scan(s, k, false, k, false, result) } -> std::same_as; + { + t.scan(s, k, false, k, false, result, std::int64_t{}) + } -> std::same_as; + { t.commit() } -> std::same_as; + { t.abort() } -> std::same_as; }; diff --git a/include/util.hh b/include/util.hh index 5f942d3f..4462539b 100644 --- a/include/util.hh +++ b/include/util.hh @@ -37,7 +37,7 @@ class LibcError : public std::exception { private: std::string str_; - static std::string generateMessage(int errnum, const std::string &msg) { + static std::string generateMessage(int errnum, const std::string& msg) { std::string s(msg); const size_t BUF_SIZE = 1024; char buf[BUF_SIZE]; @@ -45,39 +45,42 @@ private: s += buf; #ifdef Linux if (::strerror_r(errnum, buf, BUF_SIZE) != nullptr) -#endif // Linux +#endif // Linux #ifdef Darwin - if (::strerror_r(errnum, buf, BUF_SIZE) != 0) -#endif // Darwin - s += buf; + if (::strerror_r(errnum, buf, BUF_SIZE) != 0) +#endif // Darwin + s += buf; return s; } public: - explicit LibcError(int errnum = errno, const std::string &msg = "libc_error:") - : str_(generateMessage(errnum, msg)) {} + explicit LibcError(int errnum = errno, const std::string& msg = "libc_error:") + : str_(generateMessage(errnum, msg)) {} }; // function -[[maybe_unused]] extern bool chkSpan(struct timeval &start, struct timeval &stop, long threshold); +[[maybe_unused]] extern bool chkSpan(struct timeval& start, + struct timeval& stop, long threshold); extern size_t decideParallelBuildNumber(size_t tuple_num); -extern void displayProcedureVector(std::vector &pro); +extern void displayProcedureVector(std::vector& pro); extern void displayRusageRUMaxrss(); -extern bool isReady(const std::vector &readys); +extern bool isReady(const std::vector& readys); -extern void readyAndWaitForReadyOfAllThread(std::atomic &running, const size_t thnm); +extern void readyAndWaitForReadyOfAllThread(std::atomic& running, + const size_t thnm); extern void sleepMs(size_t ms); extern void sleepMicroSec(size_t ms); -extern void waitForReady(const std::vector &readys); +extern void waitForReady(const std::vector& readys); -extern void waitForReadyOfAllThread(std::atomic &running, const size_t thnm); +extern void waitForReadyOfAllThread(std::atomic& running, + const size_t thnm); //---------- // After this line, intending to force inline function. @@ -93,9 +96,9 @@ extern void waitForReadyOfAllThread(std::atomic &running, const size_t return false; } -[[maybe_unused]] inline static bool chkClkSpanSec( - const uint64_t start, const uint64_t stop, const unsigned int clocks_per_us, - const uint64_t sec) { +[[maybe_unused]] inline static bool +chkClkSpanSec(const uint64_t start, const uint64_t stop, + const unsigned int clocks_per_us, const uint64_t sec) { uint64_t diff = 0; diff = stop - start; diff = diff / clocks_per_us / 1000 / 1000; @@ -249,7 +252,7 @@ extern void waitForReadyOfAllThread(std::atomic &running, const size_t while (rdtscp() - start < tics) _mm_pause(); } -template +template Int byteswap(Int in) { switch (sizeof(Int)) { case 1: @@ -265,22 +268,22 @@ Int byteswap(Int in) { } } -template -void assign_as_bigendian(Int value, char *out) { +template +void assign_as_bigendian(Int value, char* out) { Int tmp = byteswap(value); ::memcpy(out, &tmp, sizeof(tmp)); } -template -void parse_bigendian(const char *in, Int &out) { +template +void parse_bigendian(const char* in, Int& out) { Int tmp; ::memcpy(&tmp, in, sizeof(tmp)); out = byteswap(tmp); } -template -std::string_view struct_str_view(const T &t) { - return std::string_view(reinterpret_cast(&t), sizeof(t)); +template +std::string_view struct_str_view(const T& t) { + return std::string_view(reinterpret_cast(&t), sizeof(t)); } /** @@ -288,7 +291,8 @@ std::string_view struct_str_view(const T &t) { * out buffer will be null-terminated. * returned value is written size excluding the last null character. */ -inline std::size_t copy_cstr(char *out, const char *in, std::size_t out_buf_size) { +inline std::size_t copy_cstr(char* out, const char* in, + std::size_t out_buf_size) { if (out_buf_size == 0) return 0; std::size_t i = 0; while (i < out_buf_size - 1) { @@ -315,7 +319,7 @@ inline std::string str_view_hex(std::string_view sv) { } -template -inline std::string_view str_view(const T &t) { - return std::string_view(reinterpret_cast(&t), sizeof(t)); +template +inline std::string_view str_view(const T& t) { + return std::string_view(reinterpret_cast(&t), sizeof(t)); } diff --git a/include/workload.hh b/include/workload.hh index 033e6958..948fa0dc 100644 --- a/include/workload.hh +++ b/include/workload.hh @@ -3,30 +3,24 @@ #include enum class Storage : std::uint32_t; -inline uint32_t get_storage(Storage s) { - return static_cast(s); -} +inline uint32_t get_storage(Storage s) { return static_cast(s); } enum class TxType : std::uint32_t; -inline uint32_t get_tx_type(TxType t) { - return static_cast(t); -} +inline uint32_t get_tx_type(TxType t) { return static_cast(t); } -GLOBAL std::map TxTypes; -inline std::string get_tx_name(uint32_t t) { - return TxTypes.at(t); -} +GLOBAL std::map TxTypes; +inline std::string get_tx_name(uint32_t t) { return TxTypes.at(t); } inline void set_tx_name(TxType t, std::string name) { TxTypes.emplace(get_tx_type(t), name); } -template +template struct SimpleKey { char data[N]; // not null-terminated. - char *ptr() { return &data[0]; } + char* ptr() { return &data[0]; } - const char *ptr() const { return &data[0]; } + const char* ptr() const { return &data[0]; } [[nodiscard]] std::string_view view() const { return std::string_view(&data[0], N); @@ -35,12 +29,8 @@ struct SimpleKey { int compare(const SimpleKey& rhs) const { return ::memcmp(data, rhs.data, N); } - bool operator<(const SimpleKey& rhs) const { - return compare(rhs) < 0; - } - bool operator==(const SimpleKey& rhs) const { - return compare(rhs) == 0; - } + bool operator<(const SimpleKey& rhs) const { return compare(rhs) < 0; } + bool operator==(const SimpleKey& rhs) const { return compare(rhs) == 0; } }; #define MAX_TABLES 16 diff --git a/include/ycsb.hh b/include/ycsb.hh index 07669099..c809adb6 100644 --- a/include/ycsb.hh +++ b/include/ycsb.hh @@ -17,8 +17,10 @@ #include "gflags/gflags.h" #ifdef GLOBAL_VALUE_DEFINE -DEFINE_bool(ycsb_rmw, false, "True means read modify write, false means blind write."); -DEFINE_uint64(ycsb_max_ope, 10, "Total number of operations per single transaction."); +DEFINE_bool(ycsb_rmw, false, + "True means read modify write, false means blind write."); +DEFINE_uint64(ycsb_max_ope, 10, + "Total number of operations per single transaction."); DEFINE_uint64(ycsb_rratio, 50, "read ratio of single transaction."); DEFINE_uint64(ycsb_tuple_num, 1000000, "Total number of records."); DEFINE_double(ycsb_zipf_skew, 0, "zipf skew. 0 ~ 0.999..."); @@ -36,22 +38,21 @@ enum class Storage : std::uint32_t { }; struct YCSB { - alignas(CACHE_LINE_SIZE) - std::uint64_t id_; + alignas(CACHE_LINE_SIZE) std::uint64_t id_; char val_[VAL_SIZE]; //Primary Key: key_ //key size is 8 bytes. - static void CreateKey(uint64_t id, char *out) { + static void CreateKey(uint64_t id, char* out) { assign_as_bigendian(id, &out[0]); } - void createKey(char *out) const { return CreateKey(id_, out); } + void createKey(char* out) const { return CreateKey(id_, out); } [[nodiscard]] std::string_view view() const { return struct_str_view(*this); } }; -inline static void makeProcedure(std::vector &pro, +inline static void makeProcedure(std::vector& pro, Xoroshiro128Plus& rnd, FastZipf& zipf) { pro.clear(); bool ronly_flag(true), wonly_flag(true); @@ -84,130 +85,129 @@ inline static void makeProcedure(std::vector &pro, class YcsbWorkload { public: - Xoroshiro128Plus rnd_; - FastZipf zipf_; + Xoroshiro128Plus rnd_; + FastZipf zipf_; - YcsbWorkload() { - rnd_.init(); - FastZipf zipf(&rnd_, FLAGS_ycsb_zipf_skew, FLAGS_ycsb_tuple_num); - zipf_ = zipf; - } + YcsbWorkload() { + rnd_.init(); + FastZipf zipf(&rnd_, FLAGS_ycsb_zipf_skew, FLAGS_ycsb_tuple_num); + zipf_ = zipf; + } - template - void run(TxExecutor& tx) { + template + void run(TxExecutor& tx) { #if ADD_ANALYSIS - uint64_t start = rdtscp(); + uint64_t start = rdtscp(); #endif - makeProcedure(tx.pro_set_, rnd_, zipf_); + makeProcedure(tx.pro_set_, rnd_, zipf_); #if ADD_ANALYSIS - tx.result_->local_make_procedure_latency_ += rdtscp() - start; + tx.result_->local_make_procedure_latency_ += rdtscp() - start; #endif - tx.is_ronly_ = (*tx.pro_set_.begin()).ronly_; - -RETRY: - if (tx.isLeader()) { - tx.leaderWork(); + tx.is_ronly_ = (*tx.pro_set_.begin()).ronly_; + + RETRY: + if (tx.isLeader()) { tx.leaderWork(); } + + if (loadAcquire(tx.quit_)) return; + + tx.begin(); + SimpleKey<8> key[tx.pro_set_.size()]; + HeapObject obj[tx.pro_set_.size()]; + uint64_t i = 0; + for (auto& pro : tx.pro_set_) { + YCSB::CreateKey(pro.key_, key[i].ptr()); + uint64_t k; + parse_bigendian(key[i].view().data(), k); + if (pro.ope_ == Ope::READ) { + TupleBody* body; + tx.read(Storage::YCSB, key[i].view(), &body); + if (tx.status_ != TransactionStatus::aborted) { + // Touch the value so the read is not optimized away. + [[maybe_unused]] YCSB& t = body->get_value().cast_to(); } + } else if (pro.ope_ == Ope::WRITE) { + obj[i].template allocate(); + // Materialize the payload before it gets std::move'd into update. + [[maybe_unused]] YCSB& t = obj[i].ref(); + tx.update(Storage::YCSB, key[i].view(), + TupleBody(key[i].view(), std::move(obj[i]))); + } else if (pro.ope_ == Ope::READ_MODIFY_WRITE) { + TupleBody* body; + tx.read(Storage::YCSB, key[i].view(), &body); + if (tx.status_ != TransactionStatus::aborted) { + YCSB& old_tuple = body->get_value().cast_to(); + obj[i].template allocate(); + YCSB& new_tuple = obj[i].ref(); + memcpy(new_tuple.val_, old_tuple.val_, VAL_SIZE); + tx.update(Storage::YCSB, key[i].view(), + TupleBody(key[i].view(), std::move(obj[i]))); + } + } else { + ERR; + } - if (loadAcquire(tx.quit_)) return; - - tx.begin(); - SimpleKey<8> key[tx.pro_set_.size()]; - HeapObject obj[tx.pro_set_.size()]; - uint64_t i = 0; - for (auto &pro : tx.pro_set_) { - YCSB::CreateKey(pro.key_, key[i].ptr()); - uint64_t k; - parse_bigendian(key[i].view().data(), k); - if (pro.ope_ == Ope::READ) { - TupleBody* body; - tx.read(Storage::YCSB, key[i].view(), &body); - if (tx.status_ != TransactionStatus::aborted) { - // Touch the value so the read is not optimized away. - [[maybe_unused]] YCSB& t = body->get_value().cast_to(); - } - } else if (pro.ope_ == Ope::WRITE) { - obj[i].template allocate(); - // Materialize the payload before it gets std::move'd into update. - [[maybe_unused]] YCSB& t = obj[i].ref(); - tx.update(Storage::YCSB, key[i].view(), TupleBody(key[i].view(), std::move(obj[i]))); - } else if (pro.ope_ == Ope::READ_MODIFY_WRITE) { - TupleBody* body; - tx.read(Storage::YCSB, key[i].view(), &body); - if (tx.status_ != TransactionStatus::aborted) { - YCSB& old_tuple = body->get_value().cast_to(); - obj[i].template allocate(); - YCSB& new_tuple = obj[i].ref(); - memcpy(new_tuple.val_, old_tuple.val_, VAL_SIZE); - tx.update(Storage::YCSB, key[i].view(), TupleBody(key[i].view(), std::move(obj[i]))); - } - } else { - ERR; - } - - if (tx.status_ == TransactionStatus::aborted) { - tx.abort(); - ++tx.result_->local_abort_counts_; + if (tx.status_ == TransactionStatus::aborted) { + tx.abort(); + ++tx.result_->local_abort_counts_; #if ADD_ANALYSIS - ++tx.result_->local_early_aborts_; + ++tx.result_->local_early_aborts_; #endif - goto RETRY; - } - - i++; - } + goto RETRY; + } - if (!tx.commit()) { - tx.abort(); - ++tx.result_->local_abort_counts_; - goto RETRY; - } - storeRelease(tx.result_->local_commit_counts_, - loadAcquire(tx.result_->local_commit_counts_) + 1); + i++; + } - return; + if (!tx.commit()) { + tx.abort(); + ++tx.result_->local_abort_counts_; + goto RETRY; } + storeRelease(tx.result_->local_commit_counts_, + loadAcquire(tx.result_->local_commit_counts_) + 1); + + return; + } - template - static void partTableInit([[maybe_unused]] size_t thid, Param* p, uint64_t start, uint64_t end) { + template + static void partTableInit([[maybe_unused]] size_t thid, Param* p, + uint64_t start, uint64_t end) { #if MASSTREE_USE - MasstreeWrapper::thread_init(thid); + MasstreeWrapper::thread_init(thid); #endif - for (auto i = start; i <= end; ++i) { - SimpleKey<8> key; - YCSB::CreateKey(i, key.ptr()); - HeapObject obj; - obj.allocate(); - YCSB& ycsb_tuple = obj.ref(); - ycsb_tuple.id_ = i; - Tuple* tmp = new Tuple(); - tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); - Masstrees[get_storage(Storage::YCSB)].insert_value(key.view(), tmp); - } + for (auto i = start; i <= end; ++i) { + SimpleKey<8> key; + YCSB::CreateKey(i, key.ptr()); + HeapObject obj; + obj.allocate(); + YCSB& ycsb_tuple = obj.ref(); + ycsb_tuple.id_ = i; + Tuple* tmp = new Tuple(); + tmp->init(thid, TupleBody(key.view(), std::move(obj)), p); + Masstrees[get_storage(Storage::YCSB)].insert_value(key.view(), tmp); } + } - static uint32_t getTableNum() { - return (uint32_t)Storage::Size; - } + static uint32_t getTableNum() { return (uint32_t) Storage::Size; } - template - static void makeDB(Param* p) { - size_t maxthread = decideParallelBuildNumber(FLAGS_ycsb_tuple_num); + template + static void makeDB(Param* p) { + size_t maxthread = decideParallelBuildNumber(FLAGS_ycsb_tuple_num); - std::vector thv; - for (size_t i = 0; i < maxthread; ++i) - thv.emplace_back(partTableInit, i, p, - i * (FLAGS_ycsb_tuple_num / maxthread), - (i + 1) * (FLAGS_ycsb_tuple_num / maxthread) - 1); - for (auto &th : thv) th.join(); - } + std::vector thv; + for (size_t i = 0; i < maxthread; ++i) + thv.emplace_back(partTableInit, i, p, + i * (FLAGS_ycsb_tuple_num / maxthread), + (i + 1) * (FLAGS_ycsb_tuple_num / maxthread) - 1); + for (auto& th : thv) th.join(); + } - static void displayWorkloadParameter() { - cout << "#FLAGS_ycsb_max_ope:\t" << FLAGS_ycsb_max_ope << endl; - cout << "#FLAGS_ycsb_rmw:\t" << FLAGS_ycsb_rmw << endl; - cout << "#FLAGS_ycsb_rratio:\t" << FLAGS_ycsb_rratio << endl; - cout << "#FLAGS_ycsb_tuple_num:\t" << FLAGS_ycsb_tuple_num << endl; - cout << "#FLAGS_ycsb_zipf_skew:\t" << FLAGS_ycsb_zipf_skew << endl; - } + static void displayWorkloadParameter() { + cout << "#FLAGS_ycsb_max_ope:\t" << FLAGS_ycsb_max_ope << endl; + cout << "#FLAGS_ycsb_rmw:\t" << FLAGS_ycsb_rmw << endl; + cout << "#FLAGS_ycsb_rratio:\t" << FLAGS_ycsb_rratio << endl; + cout << "#FLAGS_ycsb_tuple_num:\t" << FLAGS_ycsb_tuple_num << endl; + cout << "#FLAGS_ycsb_zipf_skew:\t" << FLAGS_ycsb_zipf_skew << endl; + } }; diff --git a/include/zipf.hh b/include/zipf.hh index acbb23cf..65045211 100644 --- a/include/zipf.hh +++ b/include/zipf.hh @@ -15,7 +15,7 @@ using std::endl; // Fast zipf distribution by Jim Gray et al. class FastZipf { - Xoroshiro128Plus *rnd_; + Xoroshiro128Plus* rnd_; size_t nr_; double alpha_, zetan_, eta_; double threshold_; @@ -23,29 +23,24 @@ class FastZipf { public: FastZipf() {} - FastZipf(Xoroshiro128Plus *rnd, double theta, size_t nr) - : rnd_(rnd), - nr_(nr), - alpha_(1.0 / (1.0 - theta)), - zetan_(zeta(nr, theta)), - eta_((1.0 - std::pow(2.0 / (double) nr, 1.0 - theta)) / - (1.0 - zeta(2, theta) / zetan_)), - threshold_(1.0 + std::pow(0.5, theta)) { + FastZipf(Xoroshiro128Plus* rnd, double theta, size_t nr) + : rnd_(rnd), nr_(nr), alpha_(1.0 / (1.0 - theta)), + zetan_(zeta(nr, theta)), + eta_((1.0 - std::pow(2.0 / (double) nr, 1.0 - theta)) / + (1.0 - zeta(2, theta) / zetan_)), + threshold_(1.0 + std::pow(0.5, theta)) { assert(0.0 <= theta); - assert(theta < 1.0); // 1.0 can not be specified. + assert(theta < 1.0); // 1.0 can not be specified. } // Use this constructor if zeta is pre-calculated. - FastZipf(Xoroshiro128Plus *rnd, double theta, size_t nr, double zetan) - : rnd_(rnd), - nr_(nr), - alpha_(1.0 / (1.0 - theta)), - zetan_(zetan), - eta_((1.0 - std::pow(2.0 / (double) nr, 1.0 - theta)) / - (1.0 - zeta(2, theta) / zetan_)), - threshold_(1.0 + std::pow(0.5, theta)) { + FastZipf(Xoroshiro128Plus* rnd, double theta, size_t nr, double zetan) + : rnd_(rnd), nr_(nr), alpha_(1.0 / (1.0 - theta)), zetan_(zetan), + eta_((1.0 - std::pow(2.0 / (double) nr, 1.0 - theta)) / + (1.0 - zeta(2, theta) / zetan_)), + threshold_(1.0 + std::pow(0.5, theta)) { assert(0.0 <= theta); - assert(theta < 1.0); // 1.0 can not be specified. + assert(theta < 1.0); // 1.0 can not be specified. } // FastZipf(const FastZipf& f) @@ -62,7 +57,7 @@ public: double uz = u * zetan_; if (uz < 1.0) return 0; if (uz < threshold_) return 1; - return (size_t)((double) nr_ * std::pow(eta_ * u - eta_ + 1.0, alpha_)); + return (size_t) ((double) nr_ * std::pow(eta_ * u - eta_ + 1.0, alpha_)); } // INLINE size_t get() {