diff --git a/include/ircd/m/vm.h b/include/ircd/m/vm.h index 409b15cc1..bfd3d6127 100644 --- a/include/ircd/m/vm.h +++ b/include/ircd/m/vm.h @@ -37,6 +37,7 @@ namespace ircd::m::vm namespace ircd::m::vm::sequence { extern ctx::dock dock; + extern ctx::mutex mutex; extern uint64_t retired; // already written; always monotonic extern uint64_t committed; // pending write; usually monotonic extern uint64_t uncommitted; // evaluating; not monotonic diff --git a/ircd/m.cc b/ircd/m.cc index eed69c294..6de48ff0b 100644 --- a/ircd/m.cc +++ b/ircd/m.cc @@ -1536,6 +1536,9 @@ ircd::m::vm::eval::operator()(const event &event) // sequence // +decltype(ircd::m::vm::sequence::mutex) +ircd::m::vm::sequence::mutex; + decltype(ircd::m::vm::sequence::dock) ircd::m::vm::sequence::dock; diff --git a/modules/m_vm.cc b/modules/m_vm.cc index c385da819..15f41c5a6 100644 --- a/modules/m_vm.cc +++ b/modules/m_vm.cc @@ -868,13 +868,7 @@ ircd::m::vm::execute_pdu(eval &eval, at<"type"_>(event) }; - const bool already_exists - { - exists(event_id) - }; - - //TODO: ABA - if(already_exists && !opts.replays) + if(m::exists(event_id) && !opts.replays) throw error { fault::EXISTS, "Event has already been evaluated." @@ -954,7 +948,20 @@ ircd::m::vm::execute_pdu(eval &eval, // Commit the transaction to database iff this eval is at the stack base. if(opts.write && !eval.sequence_shared[0]) + { + const std::lock_guard lock + { + sequence::mutex + }; + + if(m::exists(event_id) && !opts.replays) + throw error + { + fault::EXISTS, "Write commit rejected :Event has already been evaluated." + }; + write_commit(eval); + } // Wait for sequencing only if this is the stack base, otherwise we'll // never return back to that stack base. @@ -1106,7 +1113,10 @@ ircd::m::vm::write_commit(eval &eval) assert(eval.txn); assert(eval.txn.use_count() == 1); assert(eval.sequence_shared[0] == 0); - auto &txn(*eval.txn); + auto &txn + { + *eval.txn + }; #ifdef RB_DEBUG const auto db_seq_before(db::sequence(*m::dbs::events));