/// Try to get a connection to \a l from the cache, or reserve space for /// a new connection to \a l. This function may evict entries from the /// cache. /// /// \returns If a connection was found in the cache, its value is /// assigned to \a conn and this function returns true. If a /// connection was not found but space was reserved, \a conn is /// set such that conn.get() == 0, and this function returns /// true. If a connection could not be found and space could /// not be returned, \a conn is unmodified and this function /// returns false. /// If force_nsert is true, a new connection entry will be /// created even if that means the cache limits will be /// exceeded. /// /// \note The connection must be returned to the cache by calling /// \a reclaim(). bool get_or_reserve(key_type const& l, connection_type& conn, bool force_insert = false) { std::lock_guard<mutex_type> lock(mtx_); typename cache_type::iterator const it = cache_.find(l); // Check if this key already exists in the cache. if (it != cache_.end()) { // Key exists in cache. // Update LRU meta data. key_tracker_.splice( key_tracker_.end() , key_tracker_ , lru_reference(it->second) ); // If connections to the locality are available in the cache, // remove the oldest one and return it. if (!cached_connections(it->second).empty()) { value_type& connections = cached_connections(it->second); conn = connections.front(); connections.pop_front(); #if defined(HPX_TRACK_STATE_OF_OUTGOING_TCP_CONNECTION) conn->set_state(Connection::state_reinitialized); #endif ++hits_; check_invariants(); return true; } // Otherwise, if we have less connections for this locality // than the maximum, try to reserve space in the cache for a new // connection. if (num_existing_connections(it->second) < max_num_connections(it->second) || force_insert) { // See if we have enough space or can make space available. // Note that if we don't have any space and there are no // outstanding connections for this locality, we grow the // cache size beyond its limit (hoping that it will be // reduced in size next time some connection is handed back // to the cache). if (!free_space() && num_existing_connections(it->second) != 0 && !force_insert) { // If we can't find or make space, give up. ++misses_; check_invariants(); return false; } // Make sure the input connection shared_ptr doesn't hold // anything. conn.reset(); // Increase the per-locality and overall connection counts. increment_connection_count(it->second); // Statistics ++insertions_; check_invariants(); return true; } // We've reached the maximum number of connections for this // locality, and none of them are checked into the cache, so // we have to give up. ++misses_; check_invariants(); return false; } // Key (locality) isn't in cache. // See if we have enough space or can make space available. // Note that we ignore the outcome of free_space() here as we have // to guarantee to have space for the new connection as there are // no connections outstanding for this locality. If free_space // fails we grow the cache size beyond its limit (hoping that it // will be reduced in size next time some connection is handed back // to the cache). free_space(); // Update LRU meta data. typename key_tracker_type::iterator kt = key_tracker_.insert(key_tracker_.end(), l); cache_.insert(std::make_pair( l, util::make_tuple( value_type(), 1, max_connections_per_locality_, kt )) ); // Make sure the input connection shared_ptr doesn't hold anything. conn.reset(); // Increase the overall connection counts. ++connections_; ++insertions_; check_invariants(); return true; }
/// Try to get a connection to \a l from the cache, or reserve space for /// a new connection to \a l. This function may evict entries from the /// cache. /// /// \returns If a connection was found in the cache, its value is /// assigned to \a conn and this function returns true. If a /// connection was not found but space was reserved, \a conn is /// set such that conn.get() == 0, and this function returns /// true. If a connection could not be found and space could /// not be returned, \a conn is unmodified and this function /// returns false. /// /// \note The connection must be returned to the cache by calling /// \a reclaim(). bool get_or_reserve(key_type const& l, connection_type& conn) { mutex_type::scoped_lock lock(mtx_); typename cache_type::iterator const it = cache_.find(l); // Check if this key already exists in the cache. if (it != cache_.end()) { // Key exists in cache. // Update LRU meta data. key_tracker_.splice( key_tracker_.end() , key_tracker_ , boost::get<2>(it->second) ); // If connections to the locality are available in the cache, // remove the oldest one and return it. if (!boost::get<0>(it->second).empty()) { conn = boost::get<0>(it->second).front(); boost::get<0>(it->second).pop_front(); check_invariants(); return true; } // Otherwise, if we have less connections for this locality // than the maximum, try to reserve space in the cache for a new // connection. if (boost::get<1>(it->second) < max_connections_per_locality_) { // See if we have enough space or can make space available. // If we can't find or make space, give up. if (!free_space()) { check_invariants(); return false; } // Make sure the input connection shared_ptr doesn't hold // anything. conn.reset(); // Increase the per-locality and overall connection counts. ++boost::get<1>(it->second); ++connections_; check_invariants(); return true; } // We've reached the maximum number of connections for this // locality, and none of them are checked into the cache, so // we have to give up. check_invariants(); return false; } // Key isn't in cache. // See if we have enough space or can make space available. // If we can't find or make space, give up. if (!free_space()) { check_invariants(); return false; } // Update LRU meta data. typename key_tracker_type::iterator kt = key_tracker_.insert(key_tracker_.end(), l); cache_.insert( std::make_pair(l, boost::make_tuple(value_type(), 1, kt))); // Make sure the input connection shared_ptr doesn't hold anything. conn.reset(); // Increase the overall connection counts. ++connections_; check_invariants(); return true; }