From 88334aa583f25a0f5a7d58ba0cb872e271738f47 Mon Sep 17 00:00:00 2001 From: thawk105 Date: Thu, 14 May 2026 07:31:06 +0000 Subject: [PATCH] masstree: add remove_value_if_present() and use it in DELETE-commit paths (#59) --- cc/d2pl/transaction.cc | 2 +- cc/mocc/transaction.cc | 4 ++-- cc/silo/transaction.cc | 4 ++-- cc/ss2pl/transaction.cc | 2 +- cc/tictoc/transaction.cc | 4 ++-- include/masstree_wrapper.hh | 6 ++++++ 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cc/d2pl/transaction.cc b/cc/d2pl/transaction.cc index 16fee0fd..3b3fa371 100644 --- a/cc/d2pl/transaction.cc +++ b/cc/d2pl/transaction.cc @@ -85,7 +85,7 @@ bool TxExecutor::commit() { case OpType::DELETE: { // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - (void)Masstrees[get_storage((*itr).storage_)].remove_value((*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; diff --git a/cc/mocc/transaction.cc b/cc/mocc/transaction.cc index 17c82dc2..c5abdc38 100644 --- a/cc/mocc/transaction.cc +++ b/cc/mocc/transaction.cc @@ -958,7 +958,7 @@ void TxExecutor::abort() { // remove inserted records for (auto& we : write_set_) { if (we.op_ == OpType::INSERT) { - Masstrees[get_storage(we.storage_)].remove_value(we.key_); + Masstrees[get_storage(we.storage_)].remove_value_if_present(we.key_); delete we.rcdptr_; } } @@ -1047,7 +1047,7 @@ void TxExecutor::writePhase() { maxtid.absent = true; // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - (void)Masstrees[get_storage((*itr).storage_)].remove_value((*itr).key_); + Masstrees[get_storage((*itr).storage_)].remove_value_if_present((*itr).key_); gc_records_.push_back((*itr).rcdptr_); break; } diff --git a/cc/silo/transaction.cc b/cc/silo/transaction.cc index 65bacf1e..2f83e216 100644 --- a/cc/silo/transaction.cc +++ b/cc/silo/transaction.cc @@ -27,7 +27,7 @@ void TxExecutor::abort() { // remove inserted records for (auto& we : write_set_) { if (we.op_ == OpType::INSERT) { - Masstrees[get_storage(we.storage_)].remove_value(we.key_); + Masstrees[get_storage(we.storage_)].remove_value_if_present(we.key_); delete we.rcdptr_; } } @@ -554,7 +554,7 @@ void TxExecutor::writePhase() { maxtid.absent = true; // Return value intentionally ignored: a missing key still needs the // tid bump and gc_records_ push below. - (void)Masstrees[get_storage((*itr).storage_)].remove_value((*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_); diff --git a/cc/ss2pl/transaction.cc b/cc/ss2pl/transaction.cc index 0b33388f..5c05fe3d 100644 --- a/cc/ss2pl/transaction.cc +++ b/cc/ss2pl/transaction.cc @@ -85,7 +85,7 @@ bool TxExecutor::commit() { case OpType::DELETE: { // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - (void)Masstrees[get_storage((*itr).storage_)].remove_value((*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; diff --git a/cc/tictoc/transaction.cc b/cc/tictoc/transaction.cc index f2a76419..c0460e7f 100644 --- a/cc/tictoc/transaction.cc +++ b/cc/tictoc/transaction.cc @@ -477,7 +477,7 @@ void TxExecutor::abort() { // remove inserted records for (auto& we : write_set_) { if (we.op_ == OpType::INSERT) { - Masstrees[get_storage(we.storage_)].remove_value(we.key_); + Masstrees[get_storage(we.storage_)].remove_value_if_present(we.key_); delete we.rcdptr_; } } @@ -526,7 +526,7 @@ void TxExecutor::writePhase() { result.absent = true; // Return value intentionally ignored: a missing key still needs the // record put on the GC queue below. - (void)Masstrees[get_storage((*itr).storage_)].remove_value((*itr).key_); + 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; } diff --git a/include/masstree_wrapper.hh b/include/masstree_wrapper.hh index 2ff5680d..3384d00c 100644 --- a/include/masstree_wrapper.hh +++ b/include/masstree_wrapper.hh @@ -165,6 +165,12 @@ public: return Status::WARN_NOT_FOUND; } + // "delete if present" — discards "not found" since callers in the + // DELETE-commit path may race with concurrent deletions of the same key. + void remove_value_if_present(std::string_view key) { + (void) remove_value(key); + } + T *get_value(std::string_view key) { unlocked_cursor_type lp(table_, key.data(), key.size()); bool found = lp.find_unlocked(*ti);