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 }