default: 0
services:
- mgr
+- name: objectstore_debug_throw_on_failed_txc
+ type: bool
+ level: dev
+ desc: Enables exception throwing instead of process abort on transaction submission error.
+ default: false
+ with_legacy: false
int BlueStore::umount()
{
+ dout(5) << __func__ << dendl;
ceph_assert(_kv_only || mounted);
_osr_drain_all();
<< " not handled on operation " << op->op
<< " (op " << pos << ", counting from 0)" << dendl;
_dump_transaction<0>(cct, t);
- ceph_abort_msg("unexpected error");
+ if (!g_conf().get_val<bool>("objectstore_debug_throw_on_failed_txc")) {
+ ceph_abort_msg("unexpected error");
+ } else {
+ txc->osr->undo_queue(txc);
+ delete txc;
+ throw r;
+ }
}
// these operations implicity create the object
<< dendl;
derr << msg << dendl;
_dump_transaction<0>(cct, t);
- ceph_abort_msg("unexpected error");
+ if (!g_conf().get_val<bool>("objectstore_debug_throw_on_failed_txc")) {
+ ceph_abort_msg("unexpected error");
+ } else {
+ txc->osr->undo_queue(txc);
+ delete txc;
+ throw r;
+ }
}
}
}
txc->seq = ++last_seq;
q.push_back(*txc);
}
+ void undo_queue(TransContext* txc) {
+ std::lock_guard l(qlock);
+ ceph_assert(&q.back() == txc);
+ --last_seq;
+ q.pop_back();
+ }
void drain() {
std::unique_lock l(qlock);
f.close_section();
f.flush(*_dout);
*_dout << dendl;
- ceph_abort_msg("unexpected error");
+ if (!g_conf().get_val<bool>("objectstore_debug_throw_on_failed_txc")) {
+ ceph_abort_msg("unexpected error");
+ } else {
+ txc->osr->undo_queue(txc);
+ delete txc;
+ throw r;
+ }
}
// object operations
f.close_section();
f.flush(*_dout);
*_dout << dendl;
- ceph_abort_msg("unexpected error");
+ if (!g_conf().get_val<bool>("objectstore_debug_throw_on_failed_txc")) {
+ ceph_abort_msg("unexpected error");
+ } else {
+ txc->osr->undo_queue(txc);
+ delete txc;
+ throw r;
+ }
}
}
}
std::lock_guard<std::mutex> l(qlock);
q.push_back(*txc);
}
+ void undo_queue(TransContext* txc) {
+ std::lock_guard<std::mutex> l(qlock);
+ ceph_assert(&q.back() == txc);
+ q.pop_back();
+ }
void flush() {
std::unique_lock<std::mutex> l(qlock);
f.close_section();
f.flush(*_dout);
*_dout << dendl;
- ceph_abort_msg("unexpected error");
+ if (!g_conf().get_val<bool>("objectstore_debug_throw_on_failed_txc")) {
+ ceph_abort_msg("unexpected error");
+ } else {
+ throw r;
+ }
}
}
int r;
coll_t cid;
- SetDeathTestStyle("threadsafe");
+ SetVal(g_conf(), "objectstore_debug_throw_on_failed_txc", "true");
+ g_conf().apply_changes(nullptr);
auto ch = store->create_new_collection(cid);
{
ObjectStore::Transaction t;
t.remove_collection(cid);
cerr << "Invalid rm coll" << std::endl;
- PrCtl unset_dumpable;
- EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
+ try {
+ queue_transaction(store, ch, std::move(t));
+ FAIL() << "remove_collection failed to return ENOTEMPTY.";
+ } catch (int err) {
+ ASSERT_EQ(err, -ENOTEMPTY);
+ }
}
{
ObjectStore::Transaction t;
t.remove(cid, hoid);
t.remove(cid, hoid2);
t.remove_collection(cid);
- PrCtl unset_dumpable;
- EXPECT_DEATH(queue_transaction(store, ch, std::move(t)), "");
+ try {
+ queue_transaction(store, ch, std::move(t));
+ FAIL() << "remove_collection failed to return ENOTEMPTY.";
+ } catch (int err) {
+ ASSERT_EQ(err, -ENOTEMPTY);
+ }
}
{
ObjectStore::Transaction t;
// config settings. Hence setting it to 'unsafe' here as test case is closing.
g_conf()._clear_safe_to_start_threads();
PopSettings(0);
- if (!orig_death_test_style.empty()) {
- ::testing::FLAGS_gtest_death_test_style = orig_death_test_style;
- orig_death_test_style.clear();
- }
}
void StoreTestFixture::SetVal(ConfigProxy& _conf, const char* key, const char* val)
std::stack<std::pair<std::string, std::string>> saved_settings;
ConfigProxy* conf = nullptr;
- std::string orig_death_test_style;
-
public:
std::unique_ptr<ObjectStore> store;
ObjectStore::CollectionHandle ch;
void SetUp() override;
void TearDown() override;
- void SetDeathTestStyle(const char* new_style) {
- if (orig_death_test_style.empty()) {
- orig_death_test_style = ::testing::FLAGS_gtest_death_test_style;
- }
- ::testing::FLAGS_gtest_death_test_style = new_style;
- }
void SetVal(ConfigProxy& conf, const char* key, const char* val);
struct SettingsBookmark {