diff options
Diffstat (limited to 'ACE/protocols/ace/INet/ConnectionCache.cpp')
-rw-r--r-- | ACE/protocols/ace/INet/ConnectionCache.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/ACE/protocols/ace/INet/ConnectionCache.cpp b/ACE/protocols/ace/INet/ConnectionCache.cpp new file mode 100644 index 00000000000..dda10d74208 --- /dev/null +++ b/ACE/protocols/ace/INet/ConnectionCache.cpp @@ -0,0 +1,344 @@ +// $Id$ + +#include "ace/INet/ConnectionCache.h" + +#if !defined (__ACE_INLINE__) +#include "ace/INet/ConnectionCache.inl" +#endif + +#include "ace/INet/INet_Log.h" + +ACE_RCSID(NET_CLIENT,ACE_INet_ConnectionCache,"$Id$") + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + namespace INet + { + + ConnectionKey::ConnectionKey () + {} + + ConnectionKey::~ConnectionKey () + {} + + ConnectionCacheKey::ConnectionCacheKey () + : key_ (0), + delete_key_ (false) + { + } + + ConnectionCacheKey::ConnectionCacheKey (const ConnectionKey& key) + : key_ (&const_cast<ConnectionKey&> (key)), + delete_key_ (false) + { + } + + ConnectionCacheKey::ConnectionCacheKey (const ConnectionCacheKey& cachekey) + : key_ (0), + delete_key_ (false) + { + *this = cachekey; + } + + ConnectionCacheKey& ConnectionCacheKey::operator =(const ConnectionCacheKey& cachekey) + { + if (this != &cachekey) + { + if (this->key_ != 0 && this->delete_key_) + { + delete this->key_; + this->delete_key_ = false; + } + + this->key_ = cachekey.key_->duplicate (); + + if (this->key_ == 0) + { + this->delete_key_ = false; + } + else + { + this->delete_key_ = true; + } + } + return *this; + } + + u_long ConnectionCacheKey::hash (void) const + { + return this->key_ ? this->key ().hash () : 0; + } + + ConnectionHolder::~ConnectionHolder () {} + ConnectionHolder::ConnectionHolder () {} + + ConnectionFactory::~ConnectionFactory () {} + ConnectionFactory::ConnectionFactory () {} + + ConnectionCacheValue::ConnectionCacheValue () + : state_ (CST_INIT), + connection_ (0) + { + } + + ConnectionCacheValue::ConnectionCacheValue (connection_type* connection) + : state_ (connection ? CST_IDLE : CST_INIT), + connection_ (connection) + { + } + + ConnectionCacheValue::ConnectionCacheValue (const ConnectionCacheValue& cacheval) + { + *this = cacheval; + } + + ConnectionCacheValue& ConnectionCacheValue::operator =(const ConnectionCacheValue& cacheval) + { + if (this != &cacheval) + { + this->state_ = cacheval.state (); + this->connection_ = const_cast<connection_type*> (cacheval.connection ()); + } + return *this; + } + + ConnectionCache::ConnectionCache(size_t size) + : condition_ (lock_), + cache_map_ (size) + { + } + + ConnectionCache::~ConnectionCache () + { + this->close_all_connections (); + } + + bool ConnectionCache::find_connection (const ConnectionKey& key, + ConnectionCacheValue& cacheval) + { + if (this->cache_map_.find (ConnectionCacheKey (key), + cacheval) == 0) + { + return true; + } + return false; + } + + bool ConnectionCache::set_connection (const ConnectionKey& key, + const ConnectionCacheValue& cacheval) + { + return this->cache_map_.rebind (ConnectionCacheKey (key), + cacheval) != -1; + } + + bool ConnectionCache::claim_existing_connection(const ConnectionKey& key, + connection_type*& connection, + ConnectionCacheValue::State& state) + { + INET_TRACE ("ConnectionCache::claim_existing_connection"); + + ConnectionCacheValue cacheval; + if (this->find_connection (key, cacheval)) + { + state = cacheval.state (); + if (state == ConnectionCacheValue::CST_IDLE) + { + cacheval.state (ConnectionCacheValue::CST_BUSY); + if (this->set_connection (key, cacheval)) + { + connection = cacheval.connection (); + return true; + } + else + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_existing_connection - ") + ACE_TEXT ("failed to claim connection entry"))); + } + } + } + return false; + } + + bool ConnectionCache::claim_connection(const ConnectionKey& key, + connection_type*& connection, + const factory_type& connection_factory, + bool wait) + { + INET_TRACE ("ConnectionCache::claim_connection"); + + while (1) + { + bool create_connection = false; + ConnectionCacheValue::State state = ConnectionCacheValue::CST_NONE; + do + { + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, + guard_, + this->lock_, + false)); + + if (this->claim_existing_connection (key, connection, state)) + { + return true; + } + + if ((state == ConnectionCacheValue::CST_BUSY || + state == ConnectionCacheValue::CST_INIT) && !wait) + return false; + + if (state == ConnectionCacheValue::CST_CLOSED || + state == ConnectionCacheValue::CST_NONE) + { + if (!this->set_connection (key, ConnectionCacheValue ())) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_connection - ") + ACE_TEXT ("failed to initialize connection entry"))); + return false; + } + + create_connection = true; + } + else + { + // wait for connection to become ready/free + if (this->condition_.wait () != 0) + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::claim_connection - ") + ACE_TEXT ("error waiting for connection condition (%p)\n"))); + return false; + } + } + } + while (0); + + if (create_connection) + { + connection = connection_factory.create_connection (key); + if (connection) + { + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, + guard_, + this->lock_, + false)); + + ConnectionCacheValue cacheval (connection); + cacheval.state (ConnectionCacheValue::CST_BUSY); + return this->set_connection (key, cacheval); + } + } + } + } + + bool ConnectionCache::release_connection(const ConnectionKey& key, + connection_type* connection) + { + INET_TRACE ("ConnectionCache::release_connection"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, + guard_, + this->lock_, + false)); + + ConnectionCacheValue cacheval; + if (this->find_connection (key, cacheval) && + cacheval.connection () == connection && + cacheval.state () == ConnectionCacheValue::CST_BUSY) + { + cacheval.state (ConnectionCacheValue::CST_IDLE); + if (this->set_connection (key, cacheval)) + { + // signal other threads about free connection + this->condition_.broadcast (); + return true; + } + else + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::release_connection - ") + ACE_TEXT ("failed to release connection entry"))); + return false; + } + } + else + return false; + } + + bool ConnectionCache::close_connection(const ConnectionKey& key, + connection_type* connection) + { + INET_TRACE ("ConnectionCache::close_connection"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, + guard_, + this->lock_, + false)); + + ConnectionCacheValue cacheval; + if (this->find_connection (key, cacheval) && + cacheval.connection () == connection && + cacheval.state () == ConnectionCacheValue::CST_BUSY) + { + connection_type* conn = cacheval.connection (); + cacheval.connection (0); + cacheval.state (ConnectionCacheValue::CST_CLOSED); + if (this->set_connection (key, cacheval)) + { + // signal other threads about closed connection + this->condition_.broadcast (); + delete conn; // clean up + return true; + } + else + { + ACE_ERROR ((LM_ERROR, ACE_TEXT ("%P|%t) ConnectionCache::close_connection - ") + ACE_TEXT ("failed to close connection entry"))); + return false; + } + } + else + return false; + } + + bool ConnectionCache::has_connection(const ConnectionKey& key) + { + INET_TRACE ("ConnectionCache::has_connection"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, + guard_, + this->lock_, + false)); + + ConnectionCacheValue cacheval; + return (this->find_connection (key, cacheval) && + cacheval.state () != ConnectionCacheValue::CST_CLOSED); + } + + void ConnectionCache::close_all_connections() + { + INET_TRACE ("ConnectionCache::close_all_connections"); + + ACE_MT (ACE_GUARD (ACE_SYNCH_MUTEX, + guard_, + this->lock_)); + + map_iter_type iter = this->cache_map_.end (); + for (iter = this->cache_map_.begin (); + iter != this->cache_map_.end (); + ++iter) + { + if ((*iter).int_id_.state () == ConnectionCacheValue::CST_CLOSED) + { + connection_type* conn = (*iter).int_id_.connection (); + (*iter).int_id_.connection (0); + (*iter).int_id_.state (ConnectionCacheValue::CST_CLOSED); + delete conn; + } + } + this->cache_map_.unbind_all (); + } + + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL |