void parcelport::put_parcel(parcel const& p, write_handler_type const& f) { typedef pending_parcels_map::iterator iterator; typedef pending_parcels_map::mapped_type mapped_type; naming::locality locality_id = p.get_destination_locality(); naming::gid_type parcel_id = p.get_parcel_id(); // enqueue the incoming parcel ... { lcos::local::spinlock::scoped_lock l(mtx_); mapped_type& e = pending_parcels_[locality_id]; e.first.push_back(p); e.second.push_back(f); } get_connection_and_send_parcels(locality_id, parcel_id); }
void parcelport::put_parcel(parcel const& p, write_handler_type f) { typedef pending_parcels_map::iterator iterator; naming::locality locality_id = p.get_destination_locality(); parcelport_connection_ptr client_connection; // enqueue the incoming parcel ... { util::spinlock::scoped_lock l(mtx_); pending_parcels_[locality_id].first.push_back(p); pending_parcels_[locality_id].second.push_back(f); } // Get a connection or reserve space for a new connection. if (!connection_cache_.get_or_reserve(locality_id, client_connection)) return; // Check if we need to create the new connection. if (!client_connection) { client_connection.reset(new parcelport_connection( io_service_pool_.get_io_service(), locality_id, connection_cache_, timer_, parcels_sent_)); // Connect to the target locality, retry if needed. boost::system::error_code error = boost::asio::error::try_again; for (int i = 0; i < HPX_MAX_NETWORK_RETRIES; ++i) { try { naming::locality::iterator_type end = locality_id.connect_end(); for (naming::locality::iterator_type it = locality_id.connect_begin(io_service_pool_.get_io_service()); it != end; ++it) { client_connection->socket().close(); client_connection->socket().connect(*it, error); if (!error) break; } if (!error) break; // we wait for a really short amount of time // TODO: Should this be an hpx::threads::suspend? boost::this_thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(HPX_NETWORK_RETRIES_SLEEP)); } catch (boost::system::error_code const& e) { HPX_THROW_EXCEPTION(network_error, "parcelport::send_parcel", e.message()); } } if (error) { client_connection->socket().close(); hpx::util::osstream strm; strm << error.message() << " (while trying to connect to: " << locality_id << ")"; HPX_THROW_EXCEPTION(network_error, "parcelport::send_parcel", hpx::util::osstream_get_string(strm)); } #if defined(HPX_DEBUG) else { std::string connection_addr = client_connection->socket().remote_endpoint().address().to_string(); boost::uint16_t connection_port = client_connection->socket().remote_endpoint().port(); BOOST_ASSERT(locality_id.get_address() == connection_addr); BOOST_ASSERT(locality_id.get_port() == connection_port); } #endif } #if defined(HPX_DEBUG) else { //LPT_(info) << "parcelport: reusing existing connection to: " // << addr.locality_; BOOST_ASSERT(locality_id == client_connection->destination()); std::string connection_addr = client_connection->socket().remote_endpoint().address().to_string(); boost::uint16_t connection_port = client_connection->socket().remote_endpoint().port(); BOOST_ASSERT(locality_id.get_address() == connection_addr); BOOST_ASSERT(locality_id.get_port() == connection_port); } #endif std::vector<parcel> parcels; std::vector<write_handler_type> handlers; util::spinlock::scoped_lock l(mtx_); iterator it = pending_parcels_.find(locality_id); if (it != pending_parcels_.end()) { BOOST_ASSERT(it->first == locality_id); std::swap(parcels, it->second.first); std::swap(handlers, it->second.second); } // If the parcels didn't get sent by another connection ... if (!parcels.empty() && !handlers.empty()) { send_pending_parcels(client_connection, parcels, handlers); } else { // ... or re-add the stuff to the cache BOOST_ASSERT(locality_id == client_connection->destination()); connection_cache_.reclaim(locality_id, client_connection); } }