void storage_t::drop_subscription_for_all_states( const mbox_t & mbox, const std::type_index & msg_type ) { const is_same_mbox_msg is_same{ mbox->id(), msg_type }; auto lower_bound = m_events.lower_bound( key_t{ mbox->id(), msg_type, nullptr } ); auto need_erase = [&] { return lower_bound != std::end(m_events) && is_same( lower_bound->first ); }; const bool events_found = need_erase(); if( events_found ) { do { m_events.erase( lower_bound++ ); } while( need_erase() ); // Note: since v.5.5.9 mbox unsubscription is initiated even if // it is MPSC mboxes. It is important for the case of message // delivery tracing. mbox->unsubscribe_event_handlers( msg_type, owner() ); } }
void storage_t::drop_subscription( const mbox_t & mbox, const std::type_index & msg_type, const state_t & target_state ) { auto existed_position = find( m_events, mbox->id(), msg_type, target_state ); if( existed_position != m_events.end() ) { // Note v.5.5.9 unsubscribe_event_handlers is called for // mbox even if it is MPSC mbox. It is necessary for the case // of message delivery tracing. // We must destroy mbox subscription in case if the agent has no // more subscriptions for that mbox+msg_type pair. // Detect this while existed_position is not invalidated. bool must_unsubscribe_mbox = !is_known_mbox_msg_pair( m_events, existed_position ); m_events.erase( existed_position ); if( must_unsubscribe_mbox ) { mbox->unsubscribe_event_handlers( msg_type, owner() ); } } }
void storage_t::drop_subscription_for_all_states( const mbox_t & mbox_ref, const std::type_index & type_index ) { const key_t key( mbox_ref->id(), type_index ); auto it = m_map.lower_bound( key ); auto need_erase = [&] { return it != m_map.end() && key.is_same_mbox_msg_pair( it->first ); }; const bool found = need_erase(); if( found ) { do { m_hash_table.erase( &(it->first) ); m_map.erase( it++ ); } while( need_erase() ); mbox_ref->unsubscribe_event_handlers( type_index, owner() ); } }
void storage_t::create_event_subscription( const mbox_t & mbox, const std::type_index & msg_type, const message_limit::control_block_t * limit, const state_t & target_state, const event_handler_method_t & method, thread_safety_t thread_safety ) { using namespace std; using namespace subscription_storage_common; const auto mbox_id = mbox->id(); // Check that this subscription is new. auto existed_position = find( m_events, mbox_id, msg_type, target_state ); if( existed_position != m_events.end() ) SO_5_THROW_EXCEPTION( rc_evt_handler_already_provided, "agent is already subscribed to message, " + make_subscription_description( mbox, msg_type, target_state ) ); // Just add subscription to the end. auto ins_result = m_events.emplace( subscr_map_t::value_type { key_t { mbox_id, msg_type, &target_state }, value_t { mbox, event_handler_data_t { method, thread_safety } } } ); // Note: since v.5.5.9 mbox subscription is initiated even if // it is MPSC mboxes. It is important for the case of message // delivery tracing. // If there was no subscription for that mbox // then new subscription in the mbox must be created. if( !is_known_mbox_msg_pair( m_events, ins_result.first ) ) { so_5::details::do_with_rollback_on_exception( [&] { mbox->subscribe_event_handler( msg_type, limit, owner() ); }, [&] { m_events.erase( ins_result.first ); } ); } }
/*! * \since v.5.5.3 * \brief A helper function for creating subscription description. */ inline std::string make_subscription_description( const mbox_t & mbox_ref, std::type_index msg_type, const state_t & state ) { std::ostringstream s; s << "(mbox:'" << mbox_ref->query_name() << "', msg_type:'" << msg_type.name() << "', state:'" << state.query_name() << "')"; return s.str(); }