00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 #include "HttpSessionManager.h"
00034 #include "HttpClientSession.h"
00035 #include "HttpServerSession.h"
00036 #include "HttpSM.h"
00037 #include "HttpDebugNames.h"
00038 
00039 
00040 void
00041 initialize_thread_for_http_sessions(EThread *thread, int )
00042 {
00043   thread->server_session_pool = new ServerSessionPool;
00044 }
00045 
00046 HttpSessionManager httpSessionManager;
00047 
00048 ServerSessionPool::ServerSessionPool()
00049   : Continuation(new_ProxyMutex()), m_ip_pool(1023), m_host_pool(1023)
00050 {
00051   SET_HANDLER(&ServerSessionPool::eventHandler);
00052   m_ip_pool.setExpansionPolicy(IPHashTable::MANUAL);
00053   m_host_pool.setExpansionPolicy(HostHashTable::MANUAL);
00054 }
00055 
00056 void
00057 ServerSessionPool::purge()
00058 { 
00059   for ( IPHashTable::iterator last = m_ip_pool.end(), spot = m_ip_pool.begin() ; spot != last ; ++spot ) {
00060     spot->do_io_close();
00061   }
00062   m_ip_pool.clear();
00063   m_host_pool.clear();
00064 }
00065 
00066 bool
00067 ServerSessionPool::match(HttpServerSession* ss, sockaddr const* addr, INK_MD5 const& hostname_hash, TSServerSessionSharingMatchType match_style)
00068 {
00069   return TS_SERVER_SESSION_SHARING_MATCH_NONE != match_style && 
00070     
00071     (TS_SERVER_SESSION_SHARING_MATCH_IP == match_style ||  (ats_ip_port_cast(addr) == ats_ip_port_cast(ss->server_ip) && ss->hostname_hash == hostname_hash)) &&
00072     
00073     (TS_SERVER_SESSION_SHARING_MATCH_HOST == match_style || ats_ip_addr_port_eq(ss->server_ip, addr))
00074     ;
00075 }
00076 
00077 HttpServerSession*
00078 ServerSessionPool::acquireSession(sockaddr const* addr, INK_MD5 const& hostname_hash, TSServerSessionSharingMatchType match_style)
00079 {
00080   HttpServerSession* zret = NULL;
00081 
00082   if (TS_SERVER_SESSION_SHARING_MATCH_HOST == match_style) {
00083     
00084     HostHashTable::Location loc = m_host_pool.find(hostname_hash);
00085     in_port_t port = ats_ip_port_cast(addr);
00086     while (loc && port != ats_ip_port_cast(loc->server_ip)) ++loc; 
00087     if (loc) {
00088       zret = loc;
00089       m_host_pool.remove(loc);
00090       m_ip_pool.remove(m_ip_pool.find(zret));
00091     }
00092   } else if (TS_SERVER_SESSION_SHARING_MATCH_NONE != match_style) { 
00093     IPHashTable::Location loc = m_ip_pool.find(addr);
00094     
00095     
00096     
00097     if (TS_SERVER_SESSION_SHARING_MATCH_IP != match_style) {
00098       while (loc && loc->hostname_hash != hostname_hash)
00099         ++loc;
00100     }
00101     if (loc) {
00102       zret = loc;
00103       m_ip_pool.remove(loc);
00104       m_host_pool.remove(m_host_pool.find(zret));
00105     }
00106   }
00107   return zret;
00108 }
00109 
00110 void
00111 ServerSessionPool::releaseSession(HttpServerSession* ss)
00112 {
00113   ss->state = HSS_KA_SHARED;
00114   
00115   
00116   
00117   
00118   ss->do_io_read(this, INT64_MAX, ss->read_buffer);
00119 
00120   
00121   ss->do_io_write(this, 0, NULL);
00122 
00123   
00124   ss->get_netvc()->set_inactivity_timeout(ss->get_netvc()->get_inactivity_timeout());
00125   ss->get_netvc()->set_active_timeout(ss->get_netvc()->get_active_timeout());
00126   
00127   m_ip_pool.insert(ss);
00128   m_host_pool.insert(ss);
00129 
00130   Debug("http_ss", "[%" PRId64 "] [release session] " "session placed into shared pool", ss->con_id);
00131 }
00132 
00133 
00134 
00135 
00136 int
00137 ServerSessionPool::eventHandler(int event, void *data)
00138 {
00139   NetVConnection *net_vc = NULL;
00140   HttpServerSession *s = NULL;
00141 
00142   switch (event) {
00143   case VC_EVENT_READ_READY:
00144     
00145     
00146     
00147   case VC_EVENT_EOS:
00148   case VC_EVENT_ERROR:
00149   case VC_EVENT_INACTIVITY_TIMEOUT:
00150   case VC_EVENT_ACTIVE_TIMEOUT:
00151     net_vc = static_cast<NetVConnection *>((static_cast<VIO *>(data))->vc_server);
00152     break;
00153 
00154   default:
00155     ink_release_assert(0);
00156     return 0;
00157   }
00158 
00159   sockaddr const* addr = net_vc->get_remote_addr();
00160   HttpConfigParams *http_config_params = HttpConfig::acquire();
00161   bool found = false;
00162 
00163   for ( ServerSessionPool::IPHashTable::Location lh = m_ip_pool.find(addr) ; lh ; ++lh ) {
00164     if ((s = lh)->get_netvc() == net_vc) {
00165       
00166       
00167       
00168       
00169       if ((event == VC_EVENT_INACTIVITY_TIMEOUT || event == VC_EVENT_ACTIVE_TIMEOUT) &&
00170           s->state == HSS_KA_SHARED &&
00171           s->enable_origin_connection_limiting) {
00172         bool connection_count_below_min = s->connection_count->getCount(s->server_ip) <= http_config_params->origin_min_keep_alive_connections;
00173 
00174         if (connection_count_below_min) {
00175           Debug("http_ss", "[%" PRId64 "] [session_bucket] session received io notice [%s], "
00176                 "reseting timeout to maintain minimum number of connections", s->con_id,
00177                 HttpDebugNames::get_event_name(event));
00178           s->get_netvc()->set_inactivity_timeout(s->get_netvc()->get_inactivity_timeout());
00179           s->get_netvc()->set_active_timeout(s->get_netvc()->get_active_timeout());
00180           found = true;
00181           break;
00182         }
00183       }
00184 
00185       
00186       
00187       Debug("http_ss", "[%" PRId64 "] [session_pool] session %p received io notice [%s]",
00188             s->con_id, s, HttpDebugNames::get_event_name(event));
00189       ink_assert(s->state == HSS_KA_SHARED);
00190       
00191       m_ip_pool.remove(lh);
00192       m_host_pool.remove(m_host_pool.find(s));
00193       
00194       s->do_io_close();
00195       found = true;
00196       break;
00197     }
00198   }
00199 
00200   HttpConfig::release(http_config_params);
00201   if (!found) {
00202     
00203     
00204     Warning("Connection leak from http keep-alive system");
00205     ink_assert(0);
00206   }
00207   return 0;
00208 }
00209 
00210 
00211 void
00212 HttpSessionManager::init()
00213 {
00214   m_g_pool = new ServerSessionPool;
00215 }
00216 
00217 
00218 
00219 void
00220 HttpSessionManager::purge_keepalives()
00221 {
00222   EThread *ethread = this_ethread();
00223 
00224   MUTEX_TRY_LOCK(lock, m_g_pool->mutex, ethread);
00225   if (lock) {
00226     m_g_pool->purge();
00227   } 
00228 }
00229 
00230 HSMresult_t
00231 HttpSessionManager::acquire_session(Continuation * , sockaddr const* ip,
00232                                     const char *hostname, HttpClientSession *ua_session, HttpSM *sm)
00233 {
00234   HttpServerSession *to_return = NULL;
00235   TSServerSessionSharingMatchType match_style = static_cast<TSServerSessionSharingMatchType>(sm->t_state.txn_conf->server_session_sharing_match);
00236   INK_MD5 hostname_hash;
00237 
00238   ink_code_md5((unsigned char *) hostname, strlen(hostname), (unsigned char *) &hostname_hash);
00239 
00240   
00241   
00242   to_return = ua_session->get_server_session();
00243   if (to_return != NULL) {
00244     ua_session->attach_server_session(NULL);
00245 
00246     if (ServerSessionPool::match(to_return, ip, hostname_hash, match_style)) {
00247       Debug("http_ss", "[%" PRId64 "] [acquire session] returning attached session ", to_return->con_id);
00248       to_return->state = HSS_ACTIVE;
00249       sm->attach_server_session(to_return);
00250       return HSM_DONE;
00251     }
00252     
00253     
00254     Debug("http_ss", "[%" PRId64 "] [acquire session] " "session not a match, returning to shared pool", to_return->con_id);
00255     to_return->release();
00256     to_return = NULL;
00257   }
00258 
00259   
00260   EThread *ethread = this_ethread();
00261 
00262   if (TS_SERVER_SESSION_SHARING_POOL_THREAD == sm->t_state.txn_conf->server_session_sharing_pool) {
00263     to_return = ethread->server_session_pool->acquireSession(ip, hostname_hash, match_style);
00264   } else {
00265     MUTEX_TRY_LOCK(lock, m_g_pool->mutex, ethread);
00266     if (lock) {
00267       to_return = m_g_pool->acquireSession(ip, hostname_hash, match_style);
00268       Debug("http_ss", "[acquire session] pool search %s", to_return ? "successful" : "failed");
00269     } else {
00270       Debug("http_ss", "[acquire session] could not acquire session due to lock contention");
00271       return HSM_RETRY;
00272     }
00273   }
00274 
00275   if (to_return) {
00276     Debug("http_ss", "[%" PRId64 "] [acquire session] " "return session from shared pool", to_return->con_id);
00277     to_return->state = HSS_ACTIVE;
00278     sm->attach_server_session(to_return);
00279     return HSM_DONE;
00280   }
00281   return HSM_NOT_FOUND;
00282 }
00283 
00284 HSMresult_t
00285 HttpSessionManager::release_session(HttpServerSession *to_release)
00286 {
00287   EThread *ethread = this_ethread();
00288   ServerSessionPool* pool = TS_SERVER_SESSION_SHARING_POOL_THREAD == to_release->sharing_pool ? ethread->server_session_pool : m_g_pool;
00289   bool released_p = true;
00290   
00291   
00292   MUTEX_TRY_LOCK(lock, pool->mutex, ethread);
00293   if (lock) {
00294     pool->releaseSession(to_release);
00295   } else {
00296     Debug("http_ss", "[%" PRId64 "] [release session] could not release session due to lock contention", to_release->con_id);
00297     released_p = false;
00298   }
00299 
00300   return released_p ? HSM_DONE : HSM_RETRY;
00301 }